From ae82914795b038de550ef84f595934b2f8b73dae Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Thu, 16 Nov 2023 18:21:56 +0100 Subject: [PATCH] Initial changes for v2.3 --- .../include/AmsConfiguration.h | 184 +- lib/AmsConfiguration/include/AmsStorage.h | 6 + lib/AmsConfiguration/include/Timezones.h | 6 + lib/AmsConfiguration/include/hexutils.h | 6 + lib/AmsConfiguration/src/AmsConfiguration.cpp | 605 +++--- lib/AmsConfiguration/src/hexutils.cpp | 6 + lib/AmsData/include/AmsData.h | 9 + lib/AmsData/include/AmsMqttHandler.h | 37 - lib/AmsData/include/OBIScodes.h | 79 + lib/AmsData/src/AmsData.cpp | 95 + lib/AmsDataStorage/include/AmsDataStorage.h | 6 + lib/AmsDataStorage/src/AmsDataStorage.cpp | 14 +- lib/AmsDecoder/include/Cosem.h | 6 + lib/AmsDecoder/include/DataParser.h | 10 + lib/AmsDecoder/include/DataParsers.h | 6 + lib/AmsDecoder/include/DlmsParser.h | 6 + lib/AmsDecoder/include/DsmrParser.h | 6 + lib/AmsDecoder/include/GbtParser.h | 6 + lib/AmsDecoder/include/GcmParser.h | 6 + lib/AmsDecoder/include/HdlcParser.h | 6 + lib/AmsDecoder/include/LlcParser.h | 6 + lib/AmsDecoder/include/MbusParser.h | 6 + lib/AmsDecoder/include/crc.h | 6 + lib/AmsDecoder/include/ntohll.h | 6 + lib/AmsDecoder/src/Cosem.cpp | 6 + lib/AmsDecoder/src/DlmsParser.cpp | 6 + lib/AmsDecoder/src/DsmrParser.cpp | 6 + lib/AmsDecoder/src/GbtParser.cpp | 6 + lib/AmsDecoder/src/GcmParser.cpp | 6 + lib/AmsDecoder/src/HdlcParser.cpp | 11 +- lib/AmsDecoder/src/LlcParser.cpp | 6 + lib/AmsDecoder/src/MbusParser.cpp | 6 + lib/AmsDecoder/src/crc.cpp | 6 + lib/AmsDecoder/src/ntohll.cpp | 6 + lib/AmsMqttHandler/include/AmsMqttHandler.h | 66 + lib/AmsMqttHandler/src/AmsMqttHandler.cpp | 171 ++ lib/CloudConnector/include/CloudConnector.h | 67 +- lib/CloudConnector/src/CloudConnector.cpp | 245 ++- .../include/DomoticzMqttHandler.h | 11 +- .../src/DomoticzMqttHandler.cpp | 24 +- .../include/EnergyAccounting.h | 6 + lib/EnergyAccounting/src/EnergyAccounting.cpp | 6 + lib/EntsoePriceApi/include/DnbCurrParser.h | 6 + lib/EntsoePriceApi/include/EntsoeA44Parser.h | 6 + lib/EntsoePriceApi/include/EntsoeApi.h | 6 + lib/EntsoePriceApi/include/PricesContainer.h | 6 + lib/EntsoePriceApi/src/DnbCurrParser.cpp | 6 + lib/EntsoePriceApi/src/EntsoeA44Parser.cpp | 6 + lib/EntsoePriceApi/src/EntsoeApi.cpp | 6 + lib/FirmwareVersion/include/FirmwareVersion.h | 6 + lib/FirmwareVersion/src/FirmwareVersion.cpp | 6 + .../include/HomeAssistantMqttHandler.h | 20 +- .../include/HomeAssistantStatic.h | 6 + .../src/HomeAssistantMqttHandler.cpp | 50 +- lib/HwTools/include/HwTools.h | 9 + lib/HwTools/src/HwTools.cpp | 37 +- lib/JsonMqttHandler/include/JsonMqttHandler.h | 16 +- lib/JsonMqttHandler/src/JsonMqttHandler.cpp | 59 +- lib/RawMqttHandler/include/RawMqttHandler.h | 18 +- lib/RawMqttHandler/src/RawMqttHandler.cpp | 136 +- lib/RealtimePlot/include/RealtimePlot.h | 31 + lib/RealtimePlot/src/RealtimePlot.cpp | 82 + lib/SvelteUi/app/.gitignore | 2 + lib/SvelteUi/app/dist/index.css | 2 +- lib/SvelteUi/app/dist/index.html | 2 +- lib/SvelteUi/app/dist/index.js | 30 +- lib/SvelteUi/app/index.html | 2 +- lib/SvelteUi/app/package-lock.json | 1891 +++++++++-------- lib/SvelteUi/app/package.json | 20 +- lib/SvelteUi/app/src/App.svelte | 22 + lib/SvelteUi/app/src/app.postcss | 19 +- .../app/src/lib/BoardTypeSelectOptions.svelte | 3 + .../app/src/lib/ConfigurationPanel.svelte | 159 +- lib/SvelteUi/app/src/lib/Dashboard.svelte | 6 + lib/SvelteUi/app/src/lib/DataStores.js | 12 + lib/SvelteUi/app/src/lib/Helpers.js | 8 +- lib/SvelteUi/app/src/lib/Mask.svelte | 4 +- lib/SvelteUi/app/src/lib/PowerGaugeSvg.svelte | 2 +- lib/SvelteUi/app/src/lib/RealtimePlot.svelte | 145 ++ lib/SvelteUi/app/src/lib/SetupPanel.svelte | 25 +- lib/SvelteUi/app/src/lib/StatusPage.svelte | 4 +- lib/SvelteUi/app/src/main.js | 1 - lib/SvelteUi/app/tailwind.config.cjs | 2 + lib/SvelteUi/include/AmsWebHeaders.h | 6 + lib/SvelteUi/include/AmsWebServer.h | 21 +- lib/SvelteUi/json/conf_cloud.json | 6 + lib/SvelteUi/json/conf_gpio.json | 7 +- lib/SvelteUi/json/conf_ha.json | 2 +- lib/SvelteUi/json/conf_meter.json | 2 + lib/SvelteUi/json/conf_net.json | 1 + lib/SvelteUi/json/conf_ui.json | 4 +- lib/SvelteUi/json/conf_wifi.json | 1 - lib/SvelteUi/json/sysinfo.json | 7 +- lib/SvelteUi/src/AmsWebServer.cpp | 518 +++-- lib/Uptime/include/Uptime.h | 6 + lib/Uptime/src/Uptime.cpp | 6 + platformio.ini | 4 +- src/AmsToMqttBridge.cpp | 1581 ++++---------- src/AmsToMqttBridge.h | 39 - src/ConnectionHandler.h | 41 + src/EthernetConnectionHandler.cpp | 148 ++ src/EthernetConnectionHandler.h | 40 + src/IEC6205621.cpp | 6 + src/IEC6205621.h | 6 + src/IEC6205675.cpp | 6 + src/IEC6205675.h | 6 + src/KamstrupPullCommunicator.cpp | 784 +++++++ src/KamstrupPullCommunicator.h | 80 + src/LNG.cpp | 6 + src/LNG.h | 6 + src/LNG2.cpp | 6 + src/LNG2.h | 6 + src/MeterCommunicator.h | 26 + src/PassiveMeterCommunicator.cpp | 682 ++++++ src/PassiveMeterCommunicator.h | 79 + src/PassthroughMqttHandler.cpp | 42 + src/PassthroughMqttHandler.h | 28 + src/WiFiAccessPointConnectionHandler.cpp | 72 + src/WiFiAccessPointConnectionHandler.h | 39 + src/WiFiClientConnectionHandler.cpp | 224 ++ src/WiFiClientConnectionHandler.h | 42 + 121 files changed, 6175 insertions(+), 3080 deletions(-) delete mode 100644 lib/AmsData/include/AmsMqttHandler.h create mode 100644 lib/AmsData/include/OBIScodes.h create mode 100644 lib/AmsMqttHandler/include/AmsMqttHandler.h create mode 100644 lib/AmsMqttHandler/src/AmsMqttHandler.cpp create mode 100644 lib/RealtimePlot/include/RealtimePlot.h create mode 100644 lib/RealtimePlot/src/RealtimePlot.cpp create mode 100644 lib/SvelteUi/app/src/lib/RealtimePlot.svelte create mode 100644 lib/SvelteUi/json/conf_cloud.json delete mode 100644 src/AmsToMqttBridge.h create mode 100644 src/ConnectionHandler.h create mode 100644 src/EthernetConnectionHandler.cpp create mode 100644 src/EthernetConnectionHandler.h create mode 100644 src/KamstrupPullCommunicator.cpp create mode 100644 src/KamstrupPullCommunicator.h create mode 100644 src/MeterCommunicator.h create mode 100644 src/PassiveMeterCommunicator.cpp create mode 100644 src/PassiveMeterCommunicator.h create mode 100644 src/PassthroughMqttHandler.cpp create mode 100644 src/PassthroughMqttHandler.h create mode 100644 src/WiFiAccessPointConnectionHandler.cpp create mode 100644 src/WiFiAccessPointConnectionHandler.h create mode 100644 src/WiFiClientConnectionHandler.cpp create mode 100644 src/WiFiClientConnectionHandler.h diff --git a/lib/AmsConfiguration/include/AmsConfiguration.h b/lib/AmsConfiguration/include/AmsConfiguration.h index 0fd9fc98..bca51ed4 100644 --- a/lib/AmsConfiguration/include/AmsConfiguration.h +++ b/lib/AmsConfiguration/include/AmsConfiguration.h @@ -1,31 +1,54 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _AMSCONFIGURATION_h #define _AMSCONFIGURATION_h #include #include "Arduino.h" #define EEPROM_SIZE 1024*3 -#define EEPROM_CHECK_SUM 103 // Used to check if config is stored. Change if structure changes +#define EEPROM_CHECK_SUM 104 // Used to check if config is stored. Change if structure changes #define EEPROM_CLEARED_INDICATOR 0xFC #define EEPROM_CONFIG_ADDRESS 0 #define EEPROM_TEMP_CONFIG_ADDRESS 2048 #define CONFIG_SYSTEM_START 8 -#define CONFIG_METER_START 32 -#define CONFIG_UPGRADE_INFO_START 216 -#define CONFIG_UI_START 248 -#define CONFIG_GPIO_START 266 -#define CONFIG_ENTSOE_START 290 -#define CONFIG_WIFI_START 360 -#define CONFIG_ENERGYACCOUNTING_START 576 -#define CONFIG_WEB_START 648 -#define CONFIG_DEBUG_START 824 -#define CONFIG_DOMOTICZ_START 856 -#define CONFIG_NTP_START 872 -#define CONFIG_MQTT_START 1004 -#define CONFIG_HA_START 1680 +#define CONFIG_UPGRADE_INFO_START 16 +#define CONFIG_NETWORK_START 40 +#define CONFIG_METER_START 296 +#define CONFIG_GPIO_START 368 +#define CONFIG_ENTSOE_START 400 +#define CONFIG_ENERGYACCOUNTING_START 464 +#define CONFIG_WEB_START 488 +#define CONFIG_DEBUG_START 624 +#define CONFIG_NTP_START 632 +#define CONFIG_MQTT_START 760 +#define CONFIG_DOMOTICZ_START 1528 +#define CONFIG_HA_START 1544 +#define CONFIG_UI_START 1712 +#define CONFIG_CLOUD_START 1728 -#define CONFIG_METER_START_93 224 +#define CONFIG_METER_START_103 32 +#define CONFIG_UPGRADE_INFO_START_103 216 +#define CONFIG_UI_START_103 248 +#define CONFIG_GPIO_START_103 266 +#define CONFIG_ENTSOE_START_103 290 +#define CONFIG_WIFI_START_103 360 +#define CONFIG_ENERGYACCOUNTING_START_103 576 +#define CONFIG_WEB_START_103 648 +#define CONFIG_DEBUG_START_103 824 +#define CONFIG_DOMOTICZ_START_103 856 +#define CONFIG_NTP_START_103 872 +#define CONFIG_MQTT_START_103 1004 +#define CONFIG_HA_START_103 1680 +#define LED_BEHAVIOUR_DEFAULT 0 +#define LED_BEHAVIOUR_BOOT 1 +#define LED_BEHAVIOUR_ERROR_ONLY 3 +#define LED_BEHAVIOUR_OFF 9 struct SystemConfig { uint8_t boardType; @@ -33,9 +56,10 @@ struct SystemConfig { bool userConfigured; uint8_t dataCollectionConsent; // 0 = unknown, 1 = accepted, 2 = declined char country[3]; -}; // 7 + uint8_t energyspeedometer; +}; // 8 -struct WiFiConfig { +struct NetworkConfig { char ssid[32]; char psk[64]; char ip[16]; @@ -49,7 +73,8 @@ struct WiFiConfig { uint8_t sleep; uint8_t use11b; bool autoreboot; -}; // 213 + uint8_t mode; +}; // 214 struct MqttConfig { char host[128]; @@ -85,41 +110,10 @@ struct MeterConfig { uint8_t source; uint8_t parser; uint8_t bufferSize; -}; // 62 - -struct MeterConfig100 { - uint32_t baud; - uint8_t parity; - bool invert; - uint8_t distributionSystem; - uint8_t mainFuse; - uint8_t productionCapacity; - uint8_t encryptionKey[16]; - uint8_t authenticationKey[16]; - uint32_t wattageMultiplier; - uint32_t voltageMultiplier; - uint32_t amperageMultiplier; - uint32_t accumulatedMultiplier; - uint8_t source; - uint8_t parser; -}; // 59 - -struct MeterConfig95 { - uint32_t baud; - uint8_t parity; - bool invert; - uint8_t distributionSystem; - uint8_t mainFuse; - uint8_t productionCapacity; - uint8_t encryptionKey[16]; - uint8_t authenticationKey[16]; - uint16_t wattageMultiplier; - uint16_t voltageMultiplier; - uint16_t amperageMultiplier; - uint16_t accumulatedMultiplier; - uint8_t source; - uint8_t parser; -}; // 50 + uint8_t rxPin; + bool rxPinPullup; + uint8_t txPin; +}; // 65 struct DebugConfig { bool telnet; @@ -128,6 +122,26 @@ struct DebugConfig { }; // 3 struct GpioConfig { + uint8_t apPin; + uint8_t ledPin; + bool ledInverted; + uint8_t ledPinRed; + uint8_t ledPinGreen; + uint8_t ledPinBlue; + bool ledRgbInverted; + uint8_t tempSensorPin; + uint8_t tempAnalogSensorPin; + uint8_t vccPin; + int16_t vccOffset; + uint16_t vccMultiplier; + uint8_t vccBootLimit; + uint16_t vccResistorGnd; + uint16_t vccResistorVcc; + uint8_t ledDisablePin; + uint8_t ledBehaviour; +}; // 21 + +struct GpioConfig103 { uint8_t hanPin; uint8_t apPin; uint8_t ledPin; @@ -145,7 +159,9 @@ struct GpioConfig { uint16_t vccResistorGnd; uint16_t vccResistorVcc; bool hanPinPullup; -}; // 21 + uint8_t ledDisablePin; + uint8_t ledBehaviour; +}; // 23 struct DomoticzConfig { uint16_t elidx; @@ -168,14 +184,6 @@ struct NtpConfig { char timezone[32]; }; // 98 -struct NtpConfig96 { - bool enable; - bool dhcp; - int16_t offset; - int16_t summerOffset; - char server[64]; -}; // 70 - struct EntsoeConfig { char token[37]; char area[17]; @@ -207,7 +215,9 @@ struct UiConfig { uint8_t showDayPlot; uint8_t showMonthPlot; uint8_t showTemperaturePlot; -}; // 11 + uint8_t showRealtimePlot; + uint8_t darkMode; +}; // 12 struct TempSensorConfig { uint8_t address[8]; @@ -222,6 +232,15 @@ struct UpgradeInformation { int16_t errorCode; }; // 20 +struct CloudConfig { + bool enabled; + uint8_t interval; + char hostname[64]; + uint16_t port; + char clientId[17]; + char clientSecret[17]; +}; + class AmsConfiguration { public: bool hasConfig(); @@ -231,13 +250,15 @@ public: bool getSystemConfig(SystemConfig&); bool setSystemConfig(SystemConfig&); + bool isSystemConfigChanged(); + void ackSystemConfigChanged(); - bool getWiFiConfig(WiFiConfig&); - bool setWiFiConfig(WiFiConfig&); - void clearWifi(WiFiConfig&); - void clearWifiIp(WiFiConfig&); - bool isWifiChanged(); - void ackWifiChange(); + bool getNetworkConfig(NetworkConfig&); + bool setNetworkConfig(NetworkConfig&); + void clearNetworkConfig(NetworkConfig&); + void clearNetworkConfigIp(NetworkConfig&); + bool isNetworkConfigChanged(); + void ackNetworkConfigChange(); bool getMqttConfig(MqttConfig&); bool setMqttConfig(MqttConfig&); @@ -299,18 +320,16 @@ public: bool setUiConfig(UiConfig&); void clearUiConfig(UiConfig&); - void loadTempSensors(); - void saveTempSensors(); - uint8_t getTempSensorCount(); - TempSensorConfig* getTempSensorConfig(uint8_t address[8]); - void updateTempSensorConfig(uint8_t address[8], const char name[32], bool common); - - bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]); - bool getUpgradeInformation(UpgradeInformation&); bool setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion); void clearUpgradeInformation(UpgradeInformation&); + bool getCloudConfig(CloudConfig&); + bool setCloudConfig(CloudConfig&); + void clearCloudConfig(CloudConfig&); + bool isCloudChanged(); + void ackCloudConfig(); + void clear(); protected: @@ -318,18 +337,11 @@ protected: private: uint8_t configVersion = 0; - bool wifiChanged, mqttChanged, meterChanged = true, ntpChanged = true, entsoeChanged = false, energyAccountingChanged = true; + bool sysChanged = false, networkChanged, mqttChanged, meterChanged = true, ntpChanged = true, entsoeChanged = false, energyAccountingChanged = true, cloudChanged = true; - uint8_t tempSensorCount = 0; - TempSensorConfig** tempSensors = NULL; - - bool relocateConfig93(); // 2.1.0 - bool relocateConfig94(); // 2.1.0 - bool relocateConfig95(); // 2.1.4 - bool relocateConfig96(); // 2.1.14 - bool relocateConfig100(); // 2.2-dev bool relocateConfig101(); // 2.2.0 through 2.2.8 bool relocateConfig102(); // 2.2.9 through 2.2.11 + bool relocateConfig103(); // 2.2.12 onward void saveToFs(); bool loadFromFs(uint8_t version); diff --git a/lib/AmsConfiguration/include/AmsStorage.h b/lib/AmsConfiguration/include/AmsStorage.h index 41abab10..c9638d1f 100644 --- a/lib/AmsConfiguration/include/AmsStorage.h +++ b/lib/AmsConfiguration/include/AmsStorage.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _AMSSTORAGE_H #define _AMSSTORAGE_H diff --git a/lib/AmsConfiguration/include/Timezones.h b/lib/AmsConfiguration/include/Timezones.h index 1e7be4f4..eaa62a02 100644 --- a/lib/AmsConfiguration/include/Timezones.h +++ b/lib/AmsConfiguration/include/Timezones.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include #define JULY1970 15634800 diff --git a/lib/AmsConfiguration/include/hexutils.h b/lib/AmsConfiguration/include/hexutils.h index 3316a9cc..45d6285a 100644 --- a/lib/AmsConfiguration/include/hexutils.h +++ b/lib/AmsConfiguration/include/hexutils.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _HEXUTILS_H #define _HEXUTILS_H diff --git a/lib/AmsConfiguration/src/AmsConfiguration.cpp b/lib/AmsConfiguration/src/AmsConfiguration.cpp index 1202ba7c..858a95fb 100644 --- a/lib/AmsConfiguration/src/AmsConfiguration.cpp +++ b/lib/AmsConfiguration/src/AmsConfiguration.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "AmsConfiguration.h" #include "hexutils.h" @@ -13,12 +19,22 @@ bool AmsConfiguration::getSystemConfig(SystemConfig& config) { config.vendorConfigured = false; config.userConfigured = false; config.dataCollectionConsent = 0; + config.energyspeedometer = 0; strcpy(config.country, ""); return false; } } bool AmsConfiguration::setSystemConfig(SystemConfig& config) { + SystemConfig existing; + if(getSystemConfig(existing)) { + sysChanged |= config.boardType != existing.boardType; + sysChanged |= config.vendorConfigured != existing.vendorConfigured; + sysChanged |= config.userConfigured != existing.userConfigured; + sysChanged |= config.dataCollectionConsent != existing.dataCollectionConsent; + sysChanged |= strcmp(config.country, existing.country) != 0; + sysChanged |= config.energyspeedometer != existing.energyspeedometer; + } EEPROM.begin(EEPROM_SIZE); stripNonAscii((uint8_t*) config.country, 2); EEPROM.put(CONFIG_SYSTEM_START, config); @@ -27,39 +43,48 @@ bool AmsConfiguration::setSystemConfig(SystemConfig& config) { return ret; } -bool AmsConfiguration::getWiFiConfig(WiFiConfig& config) { +bool AmsConfiguration::isSystemConfigChanged() { + return sysChanged; +} + +void AmsConfiguration::ackSystemConfigChanged() { + sysChanged = false; +} + +bool AmsConfiguration::getNetworkConfig(NetworkConfig& config) { if(hasConfig()) { EEPROM.begin(EEPROM_SIZE); - EEPROM.get(CONFIG_WIFI_START, config); + EEPROM.get(CONFIG_NETWORK_START, config); EEPROM.end(); if(config.sleep > 2) config.sleep = 1; return true; } else { - clearWifi(config); + clearNetworkConfig(config); return false; } } -bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) { - WiFiConfig existing; +bool AmsConfiguration::setNetworkConfig(NetworkConfig& config) { + NetworkConfig existing; if(config.sleep > 2) config.sleep = 1; - if(getWiFiConfig(existing)) { - wifiChanged |= strcmp(config.ssid, existing.ssid) != 0; - wifiChanged |= strcmp(config.psk, existing.psk) != 0; - wifiChanged |= strcmp(config.ip, existing.ip) != 0; + if(getNetworkConfig(existing)) { + networkChanged |= strcmp(config.ssid, existing.ssid) != 0; + networkChanged |= strcmp(config.psk, existing.psk) != 0; + networkChanged |= strcmp(config.ip, existing.ip) != 0; if(strlen(config.ip) > 0) { - wifiChanged |= strcmp(config.gateway, existing.gateway) != 0; - wifiChanged |= strcmp(config.subnet, existing.subnet) != 0; - wifiChanged |= strcmp(config.dns1, existing.dns1) != 0; - wifiChanged |= strcmp(config.dns2, existing.dns2) != 0; + networkChanged |= strcmp(config.gateway, existing.gateway) != 0; + networkChanged |= strcmp(config.subnet, existing.subnet) != 0; + networkChanged |= strcmp(config.dns1, existing.dns1) != 0; + networkChanged |= strcmp(config.dns2, existing.dns2) != 0; } - wifiChanged |= strcmp(config.hostname, existing.hostname) != 0; - wifiChanged |= config.power != existing.power; - wifiChanged |= config.sleep != existing.sleep; - wifiChanged |= config.use11b != existing.use11b; - wifiChanged |= config.autoreboot != existing.autoreboot; + networkChanged |= strcmp(config.hostname, existing.hostname) != 0; + networkChanged |= config.power != existing.power; + networkChanged |= config.sleep != existing.sleep; + networkChanged |= config.use11b != existing.use11b; + networkChanged |= config.autoreboot != existing.autoreboot; + networkChanged |= config.mode != existing.mode; } else { - wifiChanged = true; + networkChanged = true; } stripNonAscii((uint8_t*) config.ssid, 32, true); @@ -72,20 +97,20 @@ bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) { stripNonAscii((uint8_t*) config.hostname, 32); EEPROM.begin(EEPROM_SIZE); - EEPROM.put(CONFIG_WIFI_START, config); + EEPROM.put(CONFIG_NETWORK_START, config); bool ret = EEPROM.commit(); EEPROM.end(); return ret; } -void AmsConfiguration::clearWifi(WiFiConfig& config) { +void AmsConfiguration::clearNetworkConfig(NetworkConfig& config) { strcpy(config.ssid, ""); strcpy(config.psk, ""); - clearWifiIp(config); + clearNetworkConfigIp(config); uint16_t chipId; #if defined(ESP32) - chipId = ESP.getEfuseMac(); + chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF; config.power = 195; #else chipId = ESP.getChipId(); @@ -97,7 +122,7 @@ void AmsConfiguration::clearWifi(WiFiConfig& config) { config.use11b = 1; } -void AmsConfiguration::clearWifiIp(WiFiConfig& config) { +void AmsConfiguration::clearNetworkConfigIp(NetworkConfig& config) { strcpy(config.ip, ""); strcpy(config.gateway, ""); strcpy(config.subnet, ""); @@ -105,12 +130,12 @@ void AmsConfiguration::clearWifiIp(WiFiConfig& config) { strcpy(config.dns2, ""); } -bool AmsConfiguration::isWifiChanged() { - return wifiChanged; +bool AmsConfiguration::isNetworkConfigChanged() { + return networkChanged; } -void AmsConfiguration::ackWifiChange() { - wifiChanged = false; +void AmsConfiguration::ackNetworkConfigChange() { + networkChanged = false; } bool AmsConfiguration::getMqttConfig(MqttConfig& config) { @@ -234,6 +259,9 @@ bool AmsConfiguration::setMeterConfig(MeterConfig& config) { meterChanged |= strcmp((char*) config.encryptionKey, (char*) existing.encryptionKey); meterChanged |= strcmp((char*) config.authenticationKey, (char*) existing.authenticationKey); meterChanged |= config.bufferSize != existing.bufferSize; + meterChanged |= config.rxPin != existing.rxPin; + meterChanged |= config.rxPinPullup != existing.rxPinPullup; + meterChanged |= config.txPin != existing.txPin; } else { meterChanged = true; } @@ -245,6 +273,9 @@ bool AmsConfiguration::setMeterConfig(MeterConfig& config) { } void AmsConfiguration::clearMeter(MeterConfig& config) { + config.rxPin = 0xFF; + config.txPin = 0xFF; + config.rxPinPullup = true; config.baud = 0; config.parity = 0; config.invert = false; @@ -386,7 +417,6 @@ bool AmsConfiguration::pinUsed(uint8_t pin, GpioConfig& config) { if(pin == 0xFF) return false; return - pin == config.hanPin || pin == config.apPin || pin == config.ledPin || pin == config.ledPinRed || @@ -394,7 +424,8 @@ bool AmsConfiguration::pinUsed(uint8_t pin, GpioConfig& config) { pin == config.ledPinBlue || pin == config.tempSensorPin || pin == config.tempAnalogSensorPin || - pin == config.vccPin + pin == config.vccPin || + pin == config.ledDisablePin ; } @@ -413,10 +444,6 @@ bool AmsConfiguration::getGpioConfig(GpioConfig& config) { bool AmsConfiguration::setGpioConfig(GpioConfig& config) { GpioConfig existing; - if(getGpioConfig(existing)) { - meterChanged |= config.hanPin != existing.hanPin; - meterChanged |= config.hanPinPullup != existing.hanPinPullup; - } /* This currently does not work, as it checks its own pin if(pinUsed(config.hanPin, config)) { debugger->println(F("HAN pin already used")); @@ -454,6 +481,10 @@ bool AmsConfiguration::setGpioConfig(GpioConfig& config) { debugger->println(F("Vcc pin already used")); return false; } + if(pinUsed(config.ledDisablePin, config)) { + debugger->println(F("ledDisablePin already used")); + return false; + } */ if(config.apPin >= 0) pinMode(config.apPin, INPUT_PULLUP); @@ -466,8 +497,6 @@ bool AmsConfiguration::setGpioConfig(GpioConfig& config) { } void AmsConfiguration::clearGpio(GpioConfig& config) { - config.hanPin = 3; - config.hanPinPullup = true; config.apPin = 0xFF; config.ledPin = 0xFF; config.ledInverted = true; @@ -483,6 +512,8 @@ void AmsConfiguration::clearGpio(GpioConfig& config) { config.vccBootLimit = 0; config.vccResistorGnd = 0; config.vccResistorVcc = 0; + config.ledDisablePin = 0xFF; + config.ledBehaviour = LED_BEHAVIOUR_DEFAULT; } bool AmsConfiguration::getNtpConfig(NtpConfig& config) { @@ -502,7 +533,7 @@ bool AmsConfiguration::setNtpConfig(NtpConfig& config) { if(getNtpConfig(existing)) { if(config.enable != existing.enable) { if(!existing.enable) { - wifiChanged = true; + networkChanged = true; } else { ntpChanged = true; } @@ -660,6 +691,7 @@ bool AmsConfiguration::getUiConfig(UiConfig& config) { EEPROM.begin(EEPROM_SIZE); EEPROM.get(CONFIG_UI_START, config); if(config.showImport > 2) clearUiConfig(config); // Must be wrong + if(config.showRealtimePlot > 2) config.showRealtimePlot = 1; // TODO: Move to new config version for v2.3 EEPROM.end(); return true; } else { @@ -677,7 +709,7 @@ bool AmsConfiguration::setUiConfig(UiConfig& config) { } void AmsConfiguration::clearUiConfig(UiConfig& config) { - // 1 = Always, 2 = If value present, 0 = Hidden + // 1 = Enable, 2 = Auto, 0 = Disable config.showImport = 1; config.showExport = 2; config.showVoltage = 2; @@ -689,6 +721,8 @@ void AmsConfiguration::clearUiConfig(UiConfig& config) { config.showDayPlot = 1; config.showMonthPlot = 1; config.showTemperaturePlot = 2; + config.showRealtimePlot = 1; + config.darkMode = 2; } bool AmsConfiguration::setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion) { @@ -730,6 +764,58 @@ void AmsConfiguration::clearUpgradeInformation(UpgradeInformation& upinfo) { memset(upinfo.toVersion, 0, 8); } +bool AmsConfiguration::getCloudConfig(CloudConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_CLOUD_START, config); + EEPROM.end(); + return true; + } else { + clearCloudConfig(config); + return false; + } +} + +bool AmsConfiguration::setCloudConfig(CloudConfig& config) { + CloudConfig existing; + if(getCloudConfig(existing)) { + cloudChanged |= config.enabled != existing.enabled; + cloudChanged |= config.interval!= existing.interval; + cloudChanged |= config.port!= existing.port; + cloudChanged |= strcmp(config.hostname, existing.hostname) != 0; + cloudChanged |= strcmp(config.clientId, existing.clientId) != 0; + cloudChanged |= strcmp(config.clientSecret, existing.clientSecret) != 0; + } else { + cloudChanged = true; + } + + stripNonAscii((uint8_t*) config.hostname, 64); + stripNonAscii((uint8_t*) config.clientId, 17); + stripNonAscii((uint8_t*) config.clientSecret, 17); + + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_CLOUD_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; +} + +void AmsConfiguration::clearCloudConfig(CloudConfig& config) { + config.enabled = false; + strcpy(config.hostname, "cloud.amsleser.no"); + config.port = 7443; + config.interval = 10; + strcpy(config.clientId, ""); + strcpy(config.clientSecret, ""); +} + +bool AmsConfiguration::isCloudChanged() { + return cloudChanged; +} + +void AmsConfiguration::ackCloudConfig() { + cloudChanged = false; +} void AmsConfiguration::clear() { EEPROM.begin(EEPROM_SIZE); @@ -738,6 +824,7 @@ void AmsConfiguration::clear() { EEPROM.get(CONFIG_SYSTEM_START, sys); sys.userConfigured = false; sys.dataCollectionConsent = 0; + sys.energyspeedometer = 0; strcpy(sys.country, ""); EEPROM.put(CONFIG_SYSTEM_START, sys); @@ -745,9 +832,9 @@ void AmsConfiguration::clear() { clearMeter(meter); EEPROM.put(CONFIG_METER_START, meter); - WiFiConfig wifi; - clearWifi(wifi); - EEPROM.put(CONFIG_WIFI_START, wifi); + NetworkConfig network; + clearNetworkConfig(network); + EEPROM.put(CONFIG_NETWORK_START, network); MqttConfig mqtt; clearMqtt(mqtt); @@ -789,6 +876,10 @@ void AmsConfiguration::clear() { clearUpgradeInformation(upinfo); EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo); + CloudConfig cloud; + clearCloudConfig(cloud); + EEPROM.put(CONFIG_CLOUD_START, cloud); + EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CLEARED_INDICATOR); EEPROM.commit(); EEPROM.end(); @@ -808,46 +899,6 @@ bool AmsConfiguration::hasConfig() { } } else { switch(configVersion) { - case 93: - configVersion = -1; // Prevent loop - if(relocateConfig93()) { - configVersion = 94; - } else { - configVersion = 0; - return false; - } - case 94: - configVersion = -1; // Prevent loop - if(relocateConfig94()) { - configVersion = 95; - } else { - configVersion = 0; - return false; - } - case 95: - configVersion = -1; // Prevent loop - if(relocateConfig95()) { - configVersion = 96; - } else { - configVersion = 0; - return false; - } - case 96: - configVersion = -1; // Prevent loop - if(relocateConfig96()) { - configVersion = 100; - } else { - configVersion = 0; - return false; - } - case 100: - configVersion = -1; // Prevent loop - if(relocateConfig100()) { - configVersion = 101; - } else { - configVersion = 0; - return false; - } case 101: configVersion = -1; // Prevent loop if(relocateConfig101()) { @@ -864,6 +915,14 @@ bool AmsConfiguration::hasConfig() { configVersion = 0; return false; } + case 103: + configVersion = -1; // Prevent loop + if(relocateConfig103()) { + configVersion = 104; + } else { + configVersion = 0; + return false; + } case EEPROM_CHECK_SUM: return true; default: @@ -878,204 +937,18 @@ int AmsConfiguration::getConfigVersion() { return configVersion; } -void AmsConfiguration::loadTempSensors() { - EEPROM.begin(EEPROM_SIZE); - TempSensorConfig* tempSensors[32]; - int address = EEPROM_TEMP_CONFIG_ADDRESS; - int c = 0; - int storedCount = EEPROM.read(address++); - if(storedCount > 0 && storedCount <= 32) { - for(int i = 0; i < storedCount; i++) { - TempSensorConfig* tsc = new TempSensorConfig(); - EEPROM.get(address, *tsc); - if(tsc->address[0] != 0xFF) { - tempSensors[c++] = tsc; - } - address += sizeof(*tsc); - } - } - this->tempSensors = new TempSensorConfig*[c]; - for(int i = 0; i < c; i++) { - this->tempSensors[i] = tempSensors[i]; - } - tempSensorCount = c; - EEPROM.end(); -} - -void AmsConfiguration::saveTempSensors() { - int address = EEPROM_TEMP_CONFIG_ADDRESS; - EEPROM.put(address++, tempSensorCount); - for(int i = 0; i < tempSensorCount; i++) { - TempSensorConfig* tsc = tempSensors[i]; - if(tsc->address[0] != 0xFF) { - EEPROM.put(address, *tsc); - address += sizeof(*tsc); - } - } -} - -bool AmsConfiguration::relocateConfig93() { - MeterConfig95 meter; - EEPROM.begin(EEPROM_SIZE); - EEPROM.get(CONFIG_METER_START_93, meter); - meter.wattageMultiplier = 0; - meter.voltageMultiplier = 0; - meter.amperageMultiplier = 0; - meter.accumulatedMultiplier = 0; - EEPROM.put(CONFIG_METER_START, meter); - EEPROM.put(EEPROM_CONFIG_ADDRESS, 94); - bool ret = EEPROM.commit(); - EEPROM.end(); - return ret; -} - -bool AmsConfiguration::relocateConfig94() { - EnergyAccountingConfig eac; - EEPROM.begin(EEPROM_SIZE); - EEPROM.get(CONFIG_ENERGYACCOUNTING_START, eac); - eac.hours = 1; - EEPROM.put(CONFIG_ENERGYACCOUNTING_START, eac); - EEPROM.put(EEPROM_CONFIG_ADDRESS, 95); - bool ret = EEPROM.commit(); - EEPROM.end(); - return ret; -} - -bool AmsConfiguration::relocateConfig95() { - MeterConfig95 meter; - MeterConfig95 meter95; - EEPROM.begin(EEPROM_SIZE); - EEPROM.get(CONFIG_METER_START, meter); - EEPROM.get(CONFIG_METER_START, meter95); - meter.wattageMultiplier = meter95.wattageMultiplier; - meter.voltageMultiplier = meter95.voltageMultiplier; - meter.amperageMultiplier = meter95.amperageMultiplier; - meter.accumulatedMultiplier = meter95.accumulatedMultiplier; - EEPROM.put(CONFIG_METER_START, meter); - EEPROM.put(EEPROM_CONFIG_ADDRESS, 96); - bool ret = EEPROM.commit(); - EEPROM.end(); - return ret; -} - -bool AmsConfiguration::relocateConfig96() { - EEPROM.begin(EEPROM_SIZE); - SystemConfig sys; - EEPROM.get(CONFIG_SYSTEM_START, sys); - - MeterConfig100 meter; - EEPROM.get(CONFIG_METER_START, meter); - meter.source = 1; // Serial - meter.parser = 0; // Auto - EEPROM.put(CONFIG_METER_START, meter); - - #if defined(ESP8266) - GpioConfig gpio; - EEPROM.get(CONFIG_GPIO_START, gpio); - - switch(sys.boardType) { - case 3: // Pow UART0 -- Now Pow-K UART0 - case 4: // Pow GPIO12 -- Now Pow-U UART0 - case 5: // Pow-K+ -- Now also Pow-K GPIO12 - case 7: // Pow-U+ -- Now also Pow-U GPIO12 - if(meter.baud == 2400 && meter.parity == 3) { // 3 == 8N1, assuming Pow-K - if(gpio.hanPin == 3) { // UART0 - sys.boardType = 3; - } else if(gpio.hanPin == 12) { - sys.boardType = 5; - } - } else { // Assuming Pow-U - if(gpio.hanPin == 3) { // UART0 - sys.boardType = 4; - } else if(gpio.hanPin == 12) { - sys.boardType = 7; - } - } - break; - } - #endif - - sys.vendorConfigured = true; - sys.userConfigured = true; - sys.dataCollectionConsent = 0; - strcpy(sys.country, ""); - EEPROM.put(CONFIG_SYSTEM_START, sys); - - WiFiConfig wifi; - EEPROM.get(CONFIG_WIFI_START, wifi); - wifi.use11b = 1; - wifi.autoreboot = true; - EEPROM.put(CONFIG_WIFI_START, wifi); - - NtpConfig ntp; - NtpConfig96 ntp96; - EEPROM.get(CONFIG_NTP_START, ntp96); - ntp.enable = ntp96.enable; - ntp.dhcp = ntp96.dhcp; - if(ntp96.offset == 360 && ntp96.summerOffset == 360) { - strcpy(ntp.timezone, "Europe/Oslo"); - } else { - strcpy(ntp.timezone, "GMT"); - } - strcpy(ntp.server, ntp96.server); - EEPROM.put(CONFIG_NTP_START, ntp); - - EntsoeConfig entsoe; - EEPROM.get(CONFIG_ENTSOE_START, entsoe); - entsoe.enabled = strlen(entsoe.token) > 0; - EEPROM.put(CONFIG_ENTSOE_START, entsoe); - - EEPROM.put(EEPROM_CONFIG_ADDRESS, 100); - bool ret = EEPROM.commit(); - EEPROM.end(); - return ret; -} - -bool AmsConfiguration::relocateConfig100() { - EEPROM.begin(EEPROM_SIZE); - - MeterConfig100 meter100; - EEPROM.get(CONFIG_METER_START, meter100); - MeterConfig meter; - meter.baud = meter100.baud; - meter.parity = meter100.parity; - meter.invert = meter100.invert; - meter.distributionSystem = meter100.distributionSystem; - meter.mainFuse = meter100.mainFuse; - meter.productionCapacity = meter100.productionCapacity; - memcpy(meter.encryptionKey, meter100.encryptionKey, 16); - memcpy(meter.authenticationKey, meter100.authenticationKey, 16); - meter.wattageMultiplier = meter100.wattageMultiplier; - meter.voltageMultiplier = meter100.voltageMultiplier; - meter.amperageMultiplier = meter100.amperageMultiplier; - meter.accumulatedMultiplier = meter100.accumulatedMultiplier; - meter.source = meter100.source; - meter.parser = meter100.parser; - - EEPROM.put(CONFIG_METER_START, meter); - - UiConfig ui; - clearUiConfig(ui); - EEPROM.put(CONFIG_UI_START, ui); - - EEPROM.put(EEPROM_CONFIG_ADDRESS, 101); - bool ret = EEPROM.commit(); - EEPROM.end(); - return ret; -} - bool AmsConfiguration::relocateConfig101() { EEPROM.begin(EEPROM_SIZE); EnergyAccountingConfig config; EnergyAccountingConfig101 config101; - EEPROM.get(CONFIG_ENERGYACCOUNTING_START, config101); + EEPROM.get(CONFIG_ENERGYACCOUNTING_START_103, config101); for(uint8_t i = 0; i < 9; i++) { config.thresholds[i] = config101.thresholds[i]; } config.thresholds[9] = 0xFFFF; config.hours = config101.hours; - EEPROM.put(CONFIG_ENERGYACCOUNTING_START, config); + EEPROM.put(CONFIG_ENERGYACCOUNTING_START_103, config); EEPROM.put(EEPROM_CONFIG_ADDRESS, 102); bool ret = EEPROM.commit(); @@ -1086,19 +959,19 @@ bool AmsConfiguration::relocateConfig101() { bool AmsConfiguration::relocateConfig102() { EEPROM.begin(EEPROM_SIZE); - GpioConfig gpioConfig; - EEPROM.get(CONFIG_GPIO_START, gpioConfig); + GpioConfig103 gpioConfig; + EEPROM.get(CONFIG_GPIO_START_103, gpioConfig); gpioConfig.hanPinPullup = true; - EEPROM.put(CONFIG_GPIO_START, gpioConfig); + EEPROM.put(CONFIG_GPIO_START_103, gpioConfig); HomeAssistantConfig haconf; clearHomeAssistantConfig(haconf); - EEPROM.put(CONFIG_HA_START, haconf); + EEPROM.put(CONFIG_HA_START_103, haconf); EntsoeConfig entsoe; - EEPROM.get(CONFIG_ENTSOE_START, entsoe); + EEPROM.get(CONFIG_ENTSOE_START_103, entsoe); entsoe.fixedPrice = 0; - EEPROM.put(CONFIG_ENTSOE_START, entsoe); + EEPROM.put(CONFIG_ENTSOE_START_103, entsoe); EEPROM.put(EEPROM_CONFIG_ADDRESS, 103); bool ret = EEPROM.commit(); @@ -1106,10 +979,89 @@ bool AmsConfiguration::relocateConfig102() { return ret; } +bool AmsConfiguration::relocateConfig103() { + EEPROM.begin(EEPROM_SIZE); + + MeterConfig meter; + UpgradeInformation upinfo; + UiConfig ui; + GpioConfig103 gpio103; + EntsoeConfig entsoe; + NetworkConfig wifi; + EnergyAccountingConfig eac; + WebConfig web; + DebugConfig debug; + DomoticzConfig domo; + NtpConfig ntp; + MqttConfig mqtt; + HomeAssistantConfig ha; + + EEPROM.get(CONFIG_METER_START_103, meter); + EEPROM.get(CONFIG_UPGRADE_INFO_START_103, upinfo); + EEPROM.get(CONFIG_UI_START_103, ui); + EEPROM.get(CONFIG_GPIO_START_103, gpio103); + EEPROM.get(CONFIG_ENTSOE_START_103, entsoe); + EEPROM.get(CONFIG_WIFI_START_103, wifi); + EEPROM.get(CONFIG_ENERGYACCOUNTING_START_103, eac); + EEPROM.get(CONFIG_WEB_START_103, web); + EEPROM.get(CONFIG_DEBUG_START_103, debug); + EEPROM.get(CONFIG_DOMOTICZ_START_103, domo); + EEPROM.get(CONFIG_NTP_START_103, ntp); + EEPROM.get(CONFIG_MQTT_START_103, mqtt); + EEPROM.get(CONFIG_HA_START_103, ha); + + meter.rxPin = gpio103.hanPin; + meter.txPin = 0xFF; + meter.rxPinPullup = gpio103.hanPinPullup; + wifi.mode = 1; // 1 == WiFi client + + GpioConfig gpio = { + gpio103.apPin, + gpio103.ledPin, + gpio103.ledInverted, + gpio103.ledPinRed, + gpio103.ledPinGreen, + gpio103.ledPinBlue, + gpio103.ledRgbInverted, + gpio103.tempSensorPin, + gpio103.tempAnalogSensorPin, + gpio103.vccPin, + gpio103.vccOffset, + gpio103.vccMultiplier, + gpio103.vccBootLimit, + gpio103.vccResistorGnd, + gpio103.vccResistorVcc, + gpio103.ledDisablePin, + gpio103.ledBehaviour + }; + + EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo); + EEPROM.put(CONFIG_NETWORK_START, wifi); + EEPROM.put(CONFIG_METER_START, meter); + EEPROM.put(CONFIG_GPIO_START, gpio); + EEPROM.put(CONFIG_ENTSOE_START, entsoe); + EEPROM.put(CONFIG_ENERGYACCOUNTING_START, eac); + EEPROM.put(CONFIG_WEB_START, web); + EEPROM.put(CONFIG_DEBUG_START, debug); + EEPROM.put(CONFIG_NTP_START, ntp); + EEPROM.put(CONFIG_MQTT_START, mqtt); + EEPROM.put(CONFIG_DOMOTICZ_START, domo); + EEPROM.put(CONFIG_HA_START, ha); + EEPROM.put(CONFIG_UI_START, ui); + + CloudConfig cloud; + clearCloudConfig(cloud); + EEPROM.put(CONFIG_CLOUD_START, cloud); + + EEPROM.put(EEPROM_CONFIG_ADDRESS, 104); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; +} + bool AmsConfiguration::save() { EEPROM.begin(EEPROM_SIZE); EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM); - saveTempSensors(); bool success = EEPROM.commit(); EEPROM.end(); @@ -1117,60 +1069,6 @@ bool AmsConfiguration::save() { return success; } -uint8_t AmsConfiguration::getTempSensorCount() { - return tempSensorCount; -} - -TempSensorConfig* AmsConfiguration::getTempSensorConfig(uint8_t address[8]) { - if(tempSensors == NULL) - return NULL; - for(int x = 0; x < tempSensorCount; x++) { - TempSensorConfig *conf = tempSensors[x]; - if(isSensorAddressEqual(conf->address, address)) { - return conf; - } - } - return NULL; -} - -void AmsConfiguration::updateTempSensorConfig(uint8_t address[8], const char name[32], bool common) { - bool found = false; - if(tempSensors != NULL) { - for(int x = 0; x < tempSensorCount; x++) { - TempSensorConfig *data = tempSensors[x]; - if(isSensorAddressEqual(data->address, address)) { - found = true; - strcpy(data->name, name); - data->common = common; - } - } - } - if(!found) { - TempSensorConfig** tempSensors = new TempSensorConfig*[tempSensorCount+1]; - if(this->tempSensors != NULL) { - for(int i = 0;i < tempSensorCount; i++) { - tempSensors[i] = this->tempSensors[i]; - } - } - TempSensorConfig *data = new TempSensorConfig(); - memcpy(data->address, address, 8); - strcpy(data->name, name); - data->common = common; - tempSensors[tempSensorCount++] = data; - if(this->tempSensors != NULL) { - delete this->tempSensors; - } - this->tempSensors = tempSensors; - } -} - -bool AmsConfiguration::isSensorAddressEqual(uint8_t a[8], uint8_t b[8]) { - for(int i = 0; i < 8; i++) { - if(a[i] != b[i]) return false; - } - return true; -} - void AmsConfiguration::saveToFs() { } @@ -1186,21 +1084,32 @@ void AmsConfiguration::deleteFromFs(uint8_t version) { void AmsConfiguration::print(Print* debugger) { debugger->println(F("-----------------------------------------------")); - WiFiConfig wifi; - if(getWiFiConfig(wifi)) { - debugger->println(F("--WiFi configuration--")); - debugger->printf_P(PSTR("SSID: '%s'\r\n"), wifi.ssid); - debugger->printf_P(PSTR("Psk: '%s'\r\n"), wifi.psk); - if(strlen(wifi.ip) > 0) { - debugger->printf_P(PSTR("IP: '%s'\r\n"), wifi.ip); - debugger->printf_P(PSTR("Gateway: '%s'\r\n"), wifi.gateway); - debugger->printf_P(PSTR("Subnet: '%s'\r\n"), wifi.subnet); - debugger->printf_P(PSTR("DNS1: '%s'\r\n"), wifi.dns1); - debugger->printf_P(PSTR("DNS2: '%s'\r\n"), wifi.dns2); + NetworkConfig network; + if(getNetworkConfig(network)) { + debugger->println(F("--Network configuration--")); + switch(network.mode) { + case 1: + debugger->printf_P(PSTR("Mode: 'WiFi client'\r\n")); + break; + case 2: + debugger->printf_P(PSTR("Mode: 'WiFi AP'\r\n")); + break; + case 3: + debugger->printf_P(PSTR("Mode: 'Ethernet'\r\n")); + break; } - debugger->printf_P(PSTR("Hostname: '%s'\r\n"), wifi.hostname); - debugger->printf_P(PSTR("mDNS: '%s'\r\n"), wifi.mdns ? "Yes" : "No"); - debugger->printf_P(PSTR("802.11b: '%s'\r\n"), wifi.use11b ? "Yes" : "No"); + debugger->printf_P(PSTR("SSID: '%s'\r\n"), network.ssid); + debugger->printf_P(PSTR("Psk: '%s'\r\n"), network.psk); + if(strlen(network.ip) > 0) { + debugger->printf_P(PSTR("IP: '%s'\r\n"), network.ip); + debugger->printf_P(PSTR("Gateway: '%s'\r\n"), network.gateway); + debugger->printf_P(PSTR("Subnet: '%s'\r\n"), network.subnet); + debugger->printf_P(PSTR("DNS1: '%s'\r\n"), network.dns1); + debugger->printf_P(PSTR("DNS2: '%s'\r\n"), network.dns2); + } + debugger->printf_P(PSTR("Hostname: '%s'\r\n"), network.hostname); + debugger->printf_P(PSTR("mDNS: '%s'\r\n"), network.mdns ? "Yes" : "No"); + debugger->printf_P(PSTR("802.11b: '%s'\r\n"), network.use11b ? "Yes" : "No"); debugger->println(F("")); delay(10); debugger->flush(); @@ -1246,6 +1155,8 @@ void AmsConfiguration::print(Print* debugger) MeterConfig meter; if(getMeterConfig(meter)) { debugger->println(F("--Meter configuration--")); + debugger->printf_P(PSTR("HAN RX: %i\r\n"), meter.rxPin); + debugger->printf_P(PSTR("HAN RX pullup %s\r\n"), meter.rxPinPullup ? "Yes" : "No"); debugger->printf_P(PSTR("Baud: %i\r\n"), meter.baud); debugger->printf_P(PSTR("Parity: %i\r\n"), meter.parity); debugger->printf_P(PSTR("Invert serial: %s\r\n"), meter.invert ? "Yes" : "No"); @@ -1261,8 +1172,6 @@ void AmsConfiguration::print(Print* debugger) GpioConfig gpio; if(getGpioConfig(gpio)) { debugger->println(F("--GPIO configuration--")); - debugger->printf_P(PSTR("HAN pin: %i\r\n"), gpio.hanPin); - debugger->printf_P(PSTR("HAN pin pullup %s\r\n"), gpio.hanPinPullup ? "Yes" : "No"); debugger->printf_P(PSTR("LED pin: %i\r\n"), gpio.ledPin); debugger->printf_P(PSTR("LED inverted: %s\r\n"), gpio.ledInverted ? "Yes" : "No"); debugger->printf_P(PSTR("LED red pin: %i\r\n"), gpio.ledPinRed); @@ -1273,6 +1182,8 @@ void AmsConfiguration::print(Print* debugger) debugger->printf_P(PSTR("Temperature pin: %i\r\n"), gpio.tempSensorPin); debugger->printf_P(PSTR("Temp analog pin: %i\r\n"), gpio.tempAnalogSensorPin); debugger->printf_P(PSTR("Vcc pin: %i\r\n"), gpio.vccPin); + debugger->printf_P(PSTR("LED disable pin: %i\r\n"), gpio.ledDisablePin); + debugger->printf_P(PSTR("LED behaviour: %i\r\n"), gpio.ledBehaviour); if(gpio.vccMultiplier > 0) { debugger->printf_P(PSTR("Vcc multiplier: %f\r\n"), gpio.vccMultiplier / 1000.0); } @@ -1335,7 +1246,5 @@ void AmsConfiguration::print(Print* debugger) debugger->flush(); } - debugger->printf_P(PSTR("Temp sensor count: %i\r\n"), this->getTempSensorCount()); - debugger->println(F("-----------------------------------------------")); } diff --git a/lib/AmsConfiguration/src/hexutils.cpp b/lib/AmsConfiguration/src/hexutils.cpp index a8151824..35819aa0 100644 --- a/lib/AmsConfiguration/src/hexutils.cpp +++ b/lib/AmsConfiguration/src/hexutils.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "hexutils.h" String toHex(uint8_t* in) { diff --git a/lib/AmsData/include/AmsData.h b/lib/AmsData/include/AmsData.h index b864a2bc..025b09d4 100644 --- a/lib/AmsData/include/AmsData.h +++ b/lib/AmsData/include/AmsData.h @@ -1,8 +1,15 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _AMSDATA_H #define _AMSDATA_H #include "Arduino.h" #include +#include "OBIScodes.h" enum AmsType { AmsTypeAutodetect = 0x00, @@ -21,6 +28,7 @@ public: AmsData(); void apply(AmsData& other); + void apply(const OBIS_code_t obis, double value); uint64_t getLastUpdateMillis(); @@ -68,6 +76,7 @@ public: bool isThreePhase(); bool isTwoPhase(); + bool isCounterEstimated(); int8_t getLastError(); void setLastError(int8_t); diff --git a/lib/AmsData/include/AmsMqttHandler.h b/lib/AmsData/include/AmsMqttHandler.h deleted file mode 100644 index 08732819..00000000 --- a/lib/AmsData/include/AmsMqttHandler.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _AMSMQTTHANDLER_H -#define _AMSMQTTHANDLER_H - -#include "Arduino.h" -#include -#include "AmsData.h" -#include "AmsConfiguration.h" -#include "EnergyAccounting.h" -#include "HwTools.h" -#include "EntsoeApi.h" - -#if defined(ESP32) -#include -#endif - -class AmsMqttHandler { -public: - AmsMqttHandler(MQTTClient* mqtt, char* buf) { - this->mqtt = mqtt; - this->json = buf; - }; - virtual ~AmsMqttHandler() {}; - - virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); - virtual bool publishTemperatures(AmsConfiguration*, HwTools*); - virtual bool publishPrices(EntsoeApi* eapi); - virtual bool publishSystem(HwTools*, EntsoeApi*, EnergyAccounting*); - -protected: - MQTTClient* mqtt; - char* json; - uint16_t BufferSize = 2048; - - bool loop(); -}; - -#endif diff --git a/lib/AmsData/include/OBIScodes.h b/lib/AmsData/include/OBIScodes.h new file mode 100644 index 00000000..4e5a7e29 --- /dev/null +++ b/lib/AmsData/include/OBIScodes.h @@ -0,0 +1,79 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _OBISCODES_H +#define _OBISCODES_H + +#include "lwip/def.h" + +#define OBIS_MEDIUM_ABSTRACT 0 +#define OBIS_MEDIUM_ELECTRICITY 1 + +#define OBIS_CHAN_0 0 +#define OBIS_CHAN_1 1 + +#define OBIS_RANGE_NA 0xFF + +struct OBIS_head_t { + uint8_t medium; + uint8_t channel; +} __attribute__((packed)); + +struct OBIS_code_t { + uint8_t sensor; + uint8_t gr; + uint8_t tariff; +} __attribute__((packed)); + +struct OBIS_t { + OBIS_head_t head; + OBIS_code_t code; + uint8_t range; +} __attribute__((packed)); + + +const OBIS_code_t OBIS_NULL PROGMEM = { 0, 0, 0 }; + +const OBIS_code_t OBIS_VERSION PROGMEM = { 0, 2, 129 }; +const OBIS_code_t OBIS_METER_MODEL PROGMEM = { 96, 1, 1 }; +const OBIS_code_t OBIS_METER_MODEL_2 PROGMEM = { 96, 1, 7 }; +const OBIS_code_t OBIS_METER_ID PROGMEM = { 96, 1, 0 }; +const OBIS_code_t OBIS_METER_ID_2 PROGMEM = { 0, 0, 5 }; +const OBIS_code_t OBIS_METER_TIMESTAMP PROGMEM = { 1, 0, 0 }; + +const OBIS_code_t OBIS_ACTIVE_IMPORT PROGMEM = { 1, 7, 0 }; +const OBIS_code_t OBIS_ACTIVE_IMPORT_COUNT PROGMEM = { 1, 8, 0 }; +const OBIS_code_t OBIS_ACTIVE_EXPORT PROGMEM = { 2, 7, 0 }; +const OBIS_code_t OBIS_ACTIVE_EXPORT_COUNT PROGMEM = { 2, 8, 0 }; +const OBIS_code_t OBIS_REACTIVE_IMPORT PROGMEM = { 3, 7, 0 }; +const OBIS_code_t OBIS_REACTIVE_IMPORT_COUNT PROGMEM = { 3, 8, 0 }; +const OBIS_code_t OBIS_REACTIVE_EXPORT PROGMEM = { 4, 7, 0 }; +const OBIS_code_t OBIS_REACTIVE_EXPORT_COUNT PROGMEM = { 4, 8, 0 }; + +const OBIS_code_t OBIS_POWER_FACTOR PROGMEM = { 13, 7, 0 }; + +const OBIS_code_t OBIS_ACTIVE_IMPORT_L1 PROGMEM = { 21, 7, 0 }; +const OBIS_code_t OBIS_ACTIVE_EXPORT_L1 PROGMEM = { 22, 7, 0 }; + +const OBIS_code_t OBIS_CURRENT_L1 PROGMEM = { 31, 7, 0 }; +const OBIS_code_t OBIS_VOLTAGE_L1 PROGMEM = { 32, 7, 0 }; +const OBIS_code_t OBIS_POWER_FACTOR_L1 PROGMEM = { 33, 7, 0 }; + +const OBIS_code_t OBIS_ACTIVE_IMPORT_L2 PROGMEM = { 41, 7, 0 }; +const OBIS_code_t OBIS_ACTIVE_EXPORT_L2 PROGMEM = { 42, 7, 0 }; + +const OBIS_code_t OBIS_CURRENT_L2 PROGMEM = { 51, 7, 0 }; +const OBIS_code_t OBIS_VOLTAGE_L2 PROGMEM = { 52, 7, 0 }; +const OBIS_code_t OBIS_POWER_FACTOR_L2 PROGMEM = { 53, 7, 0 }; + +const OBIS_code_t OBIS_ACTIVE_IMPORT_L3 PROGMEM = { 61, 7, 0 }; +const OBIS_code_t OBIS_ACTIVE_EXPORT_L3 PROGMEM = { 62, 7, 0 }; + +const OBIS_code_t OBIS_CURRENT_L3 PROGMEM = { 71, 7, 0 }; +const OBIS_code_t OBIS_VOLTAGE_L3 PROGMEM = { 72, 7, 0 }; +const OBIS_code_t OBIS_POWER_FACTOR_L3 PROGMEM = { 73, 7, 0 }; + +#endif diff --git a/lib/AmsData/src/AmsData.cpp b/lib/AmsData/src/AmsData.cpp index 66e5fea5..829f28f9 100644 --- a/lib/AmsData/src/AmsData.cpp +++ b/lib/AmsData/src/AmsData.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "AmsData.h" AmsData::AmsData() {} @@ -82,6 +88,91 @@ void AmsData::apply(AmsData& other) { this->activeExportPower = other.getActiveExportPower(); } +void AmsData::apply(OBIS_code_t obis, double value) { + switch(obis.gr) { + case 1: + switch(obis.sensor) { + case 7: + switch(obis.tariff) { + case 0: + activeImportPower = value; + listType = max(listType, (uint8_t) 1); + break; + } + break; + case 8: + switch(obis.tariff) { + case 0: + activeImportCounter = value; + listType = max(listType, (uint8_t) 3); + break; + } + break; + } + break; + case 2: + switch(obis.sensor) { + case 7: + switch(obis.tariff) { + case 0: + activeExportPower = value; + listType = max(listType, (uint8_t) 2); + break; + } + break; + case 8: + switch(obis.tariff) { + case 0: + activeExportCounter = value; + listType = max(listType, (uint8_t) 3); + break; + } + break; + } + break; + case 3: + switch(obis.sensor) { + case 7: + switch(obis.tariff) { + case 0: + reactiveImportPower = value; + listType = max(listType, (uint8_t) 2); + break; + } + break; + case 8: + switch(obis.tariff) { + case 0: + reactiveImportCounter = value; + listType = max(listType, (uint8_t) 3); + break; + } + break; + } + break; + case 4: + switch(obis.sensor) { + case 7: + switch(obis.tariff) { + case 0: + reactiveExportPower = value; + listType = max(listType, (uint8_t) 2); + break; + } + break; + case 8: + switch(obis.tariff) { + case 0: + reactiveExportCounter = value; + listType = max(listType, (uint8_t) 3); + break; + } + break; + } + break; + } +} + uint64_t AmsData::getLastUpdateMillis() { return this->lastUpdateMillis; } @@ -218,6 +309,10 @@ bool AmsData::isTwoPhase() { return this->twoPhase; } +bool AmsData::isCounterEstimated() { + return this->counterEstimated; +} + int8_t AmsData::getLastError() { return lastErrorCount > 2 ? lastError : 0; } diff --git a/lib/AmsDataStorage/include/AmsDataStorage.h b/lib/AmsDataStorage/include/AmsDataStorage.h index 46e1bdb9..3b511f14 100644 --- a/lib/AmsDataStorage/include/AmsDataStorage.h +++ b/lib/AmsDataStorage/include/AmsDataStorage.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _AMSDATASTORAGE_H #define _AMSDATASTORAGE_H #include "Arduino.h" diff --git a/lib/AmsDataStorage/src/AmsDataStorage.cpp b/lib/AmsDataStorage/src/AmsDataStorage.cpp index 44b2bcb3..c0ab2920 100644 --- a/lib/AmsDataStorage/src/AmsDataStorage.cpp +++ b/lib/AmsDataStorage/src/AmsDataStorage.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "AmsDataStorage.h" #include #include "LittleFS.h" @@ -578,7 +584,6 @@ bool AmsDataStorage::isHappy() { bool AmsDataStorage::isDayHappy() { if(tz == NULL) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Timezone is missing\n")); return false; } @@ -586,11 +591,9 @@ bool AmsDataStorage::isDayHappy() { if(now < FirmwareVersion::BuildEpoch) return false; if(now < day.lastMeterReadTime) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data timestamp %lu < %lu\n"), (int32_t) now, (int32_t) day.lastMeterReadTime); return false; } if(now-day.lastMeterReadTime > 3600) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data timestamp age %lu - %lu > 3600\n"), (int32_t) now, (int32_t) day.lastMeterReadTime); return false; } @@ -598,7 +601,6 @@ bool AmsDataStorage::isDayHappy() { breakTime(tz->toLocal(now), tm); breakTime(tz->toLocal(day.lastMeterReadTime), last); if(tm.Hour != last.Hour) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data hour of last timestamp %d > %d\n"), tm.Hour, last.Hour); return false; } @@ -607,7 +609,6 @@ bool AmsDataStorage::isDayHappy() { bool AmsDataStorage::isMonthHappy() { if(tz == NULL) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Timezone is missing\n")); return false; } @@ -616,19 +617,16 @@ bool AmsDataStorage::isMonthHappy() { tmElements_t tm, last; if(now < month.lastMeterReadTime) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Month data timestamp %lu < %lu\n"), (int32_t) now, (int32_t) month.lastMeterReadTime); return false; } breakTime(tz->toLocal(now), tm); breakTime(tz->toLocal(month.lastMeterReadTime), last); if(tm.Day != last.Day) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Month data day of last timestamp %d > %d\n"), tm.Day, last.Day); return false; } if(now-month.lastMeterReadTime > 90100) { - if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Month %lu - %lu > 3600\n", (int32_t) now, (int32_t) month.lastMeterReadTime); return false; } diff --git a/lib/AmsDecoder/include/Cosem.h b/lib/AmsDecoder/include/Cosem.h index e218cd7e..012d9773 100644 --- a/lib/AmsDecoder/include/Cosem.h +++ b/lib/AmsDecoder/include/Cosem.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _COSEM_H #define _COSEM_H diff --git a/lib/AmsDecoder/include/DataParser.h b/lib/AmsDecoder/include/DataParser.h index 6aa92fae..eb80e6ce 100644 --- a/lib/AmsDecoder/include/DataParser.h +++ b/lib/AmsDecoder/include/DataParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DATAPASERSER_H #define _DATAPASERSER_H @@ -10,6 +16,10 @@ #define DATA_TAG_MBUS 0x68 #define DATA_TAG_GBT 0xE0 #define DATA_TAG_GCM 0xDB +#define DATA_TAG_SNRM 0x81 +#define DATA_TAG_AARQ 0x60 +#define DATA_TAG_AARE 0x61 +#define DATA_TAG_RES 0xC4 // Get Response #define DATA_PARSE_OK 0 #define DATA_PARSE_FAIL -1 diff --git a/lib/AmsDecoder/include/DataParsers.h b/lib/AmsDecoder/include/DataParsers.h index 5355784e..3e29b576 100644 --- a/lib/AmsDecoder/include/DataParsers.h +++ b/lib/AmsDecoder/include/DataParsers.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DATAPASERSERS_H #define _DATAPASERSERS_H diff --git a/lib/AmsDecoder/include/DlmsParser.h b/lib/AmsDecoder/include/DlmsParser.h index 200f0fe9..e7ee15d4 100644 --- a/lib/AmsDecoder/include/DlmsParser.h +++ b/lib/AmsDecoder/include/DlmsParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DLMSPARSER_H #define _DLMSPARSER_H diff --git a/lib/AmsDecoder/include/DsmrParser.h b/lib/AmsDecoder/include/DsmrParser.h index 7d476de9..d57ce88c 100644 --- a/lib/AmsDecoder/include/DsmrParser.h +++ b/lib/AmsDecoder/include/DsmrParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DSMRPARSER_H #define _DSMRPARSER_H diff --git a/lib/AmsDecoder/include/GbtParser.h b/lib/AmsDecoder/include/GbtParser.h index dd97960b..70afcd6b 100644 --- a/lib/AmsDecoder/include/GbtParser.h +++ b/lib/AmsDecoder/include/GbtParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _GBTPARSER_H #define _GBTPARSER_H diff --git a/lib/AmsDecoder/include/GcmParser.h b/lib/AmsDecoder/include/GcmParser.h index eff75044..3ed6f2d5 100644 --- a/lib/AmsDecoder/include/GcmParser.h +++ b/lib/AmsDecoder/include/GcmParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _GCMPARSER_H #define _GCMPARSER_H diff --git a/lib/AmsDecoder/include/HdlcParser.h b/lib/AmsDecoder/include/HdlcParser.h index 7091cfbd..4b3cac96 100644 --- a/lib/AmsDecoder/include/HdlcParser.h +++ b/lib/AmsDecoder/include/HdlcParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _HDLCPARSER_H #define _HDLCPARSER_H diff --git a/lib/AmsDecoder/include/LlcParser.h b/lib/AmsDecoder/include/LlcParser.h index 3be93109..a7b1fb1b 100644 --- a/lib/AmsDecoder/include/LlcParser.h +++ b/lib/AmsDecoder/include/LlcParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _LLCPARSER_H #define _LLCPARSER_H diff --git a/lib/AmsDecoder/include/MbusParser.h b/lib/AmsDecoder/include/MbusParser.h index 61e255d4..132e8371 100644 --- a/lib/AmsDecoder/include/MbusParser.h +++ b/lib/AmsDecoder/include/MbusParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _MBUSPARSER_H #define _MBUSPARSER_H diff --git a/lib/AmsDecoder/include/crc.h b/lib/AmsDecoder/include/crc.h index 660b5057..b054cd2c 100644 --- a/lib/AmsDecoder/include/crc.h +++ b/lib/AmsDecoder/include/crc.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _CRC_H #define _CRC_H diff --git a/lib/AmsDecoder/include/ntohll.h b/lib/AmsDecoder/include/ntohll.h index 2bb1e5e0..761fed0a 100644 --- a/lib/AmsDecoder/include/ntohll.h +++ b/lib/AmsDecoder/include/ntohll.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _NTOHLL_H #define _NTOHLL_H diff --git a/lib/AmsDecoder/src/Cosem.cpp b/lib/AmsDecoder/src/Cosem.cpp index 96d796fd..298a681d 100644 --- a/lib/AmsDecoder/src/Cosem.cpp +++ b/lib/AmsDecoder/src/Cosem.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "Cosem.h" #include "lwip/def.h" #include diff --git a/lib/AmsDecoder/src/DlmsParser.cpp b/lib/AmsDecoder/src/DlmsParser.cpp index f0ed63e2..08af8dc9 100644 --- a/lib/AmsDecoder/src/DlmsParser.cpp +++ b/lib/AmsDecoder/src/DlmsParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "DlmsParser.h" #include "Cosem.h" diff --git a/lib/AmsDecoder/src/DsmrParser.cpp b/lib/AmsDecoder/src/DsmrParser.cpp index 05f0fa47..711eb39b 100644 --- a/lib/AmsDecoder/src/DsmrParser.cpp +++ b/lib/AmsDecoder/src/DsmrParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "DsmrParser.h" #include "crc.h" #include "hexutils.h" diff --git a/lib/AmsDecoder/src/GbtParser.cpp b/lib/AmsDecoder/src/GbtParser.cpp index 721bb5b3..ec5d3a25 100644 --- a/lib/AmsDecoder/src/GbtParser.cpp +++ b/lib/AmsDecoder/src/GbtParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "GbtParser.h" #include "lwip/def.h" diff --git a/lib/AmsDecoder/src/GcmParser.cpp b/lib/AmsDecoder/src/GcmParser.cpp index ad27ffa1..b8fff7b4 100644 --- a/lib/AmsDecoder/src/GcmParser.cpp +++ b/lib/AmsDecoder/src/GcmParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "GcmParser.h" #include "lwip/def.h" #if defined(ESP8266) diff --git a/lib/AmsDecoder/src/HdlcParser.cpp b/lib/AmsDecoder/src/HdlcParser.cpp index 68a65ae1..71835eba 100644 --- a/lib/AmsDecoder/src/HdlcParser.cpp +++ b/lib/AmsDecoder/src/HdlcParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "HdlcParser.h" #include "lwip/def.h" #include "crc.h" @@ -49,7 +55,10 @@ int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) { ptr += 3; // Exclude all of header and 3 byte footer - ctx.length -= ptr-d+3; + ctx.length -= ptr-d; + if(ctx.length > 1) { + ctx.length -= 3; + } return ptr-d; } return DATA_PARSE_UNKNOWN_DATA; diff --git a/lib/AmsDecoder/src/LlcParser.cpp b/lib/AmsDecoder/src/LlcParser.cpp index c6d41a56..9ab24a94 100644 --- a/lib/AmsDecoder/src/LlcParser.cpp +++ b/lib/AmsDecoder/src/LlcParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "LlcParser.h" int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) { diff --git a/lib/AmsDecoder/src/MbusParser.cpp b/lib/AmsDecoder/src/MbusParser.cpp index 4a090da9..85285de8 100644 --- a/lib/AmsDecoder/src/MbusParser.cpp +++ b/lib/AmsDecoder/src/MbusParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "MbusParser.h" int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) { diff --git a/lib/AmsDecoder/src/crc.cpp b/lib/AmsDecoder/src/crc.cpp index da8e9d76..88fa06ca 100644 --- a/lib/AmsDecoder/src/crc.cpp +++ b/lib/AmsDecoder/src/crc.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "crc.h" uint16_t crc16_x25(const uint8_t* p, int len) diff --git a/lib/AmsDecoder/src/ntohll.cpp b/lib/AmsDecoder/src/ntohll.cpp index 25732434..52046e1a 100644 --- a/lib/AmsDecoder/src/ntohll.cpp +++ b/lib/AmsDecoder/src/ntohll.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "ntohll.h" uint64_t ntohll(uint64_t x) { diff --git a/lib/AmsMqttHandler/include/AmsMqttHandler.h b/lib/AmsMqttHandler/include/AmsMqttHandler.h new file mode 100644 index 00000000..c3f2cb3b --- /dev/null +++ b/lib/AmsMqttHandler/include/AmsMqttHandler.h @@ -0,0 +1,66 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _AMSMQTTHANDLER_H +#define _AMSMQTTHANDLER_H + +#include "Arduino.h" +#include +#include "AmsData.h" +#include "AmsConfiguration.h" +#include "EnergyAccounting.h" +#include "HwTools.h" +#include "EntsoeApi.h" + +#if defined(ESP32) +#include +#endif + +class AmsMqttHandler { +public: + AmsMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf) { + this->mqttConfig = mqttConfig; + this->debugger = debugger; + this->json = buf; + mqtt.dropOverflow(true); + }; + + void setCaVerification(bool); + + bool connect(); + void disconnect(); + lwmqtt_err_t lastError(); + bool connected(); + bool loop(); + + virtual uint8_t getFormat() { return 0; }; + + virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { return false; }; + virtual bool publishTemperatures(AmsConfiguration*, HwTools*) { return false; }; + virtual bool publishPrices(EntsoeApi* eapi) { return false; }; + virtual bool publishSystem(HwTools*, EntsoeApi*, EnergyAccounting*) { return false; }; + virtual bool publishRaw(String data) { return false; }; + + virtual ~AmsMqttHandler() { + if(mqttClient != NULL) { + mqttClient->stop(); + delete mqttClient; + } + }; + +protected: + RemoteDebug* debugger; + MqttConfig mqttConfig; + MQTTClient mqtt = MQTTClient(256); + unsigned long lastMqttRetry = -10000; + bool caVerification = true; + WiFiClient *mqttClient = NULL; + WiFiClientSecure *mqttSecureClient = NULL; + char* json; + uint16_t BufferSize = 2048; +}; + +#endif diff --git a/lib/AmsMqttHandler/src/AmsMqttHandler.cpp b/lib/AmsMqttHandler/src/AmsMqttHandler.cpp new file mode 100644 index 00000000..f3030cb8 --- /dev/null +++ b/lib/AmsMqttHandler/src/AmsMqttHandler.cpp @@ -0,0 +1,171 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "AmsMqttHandler.h" +#include "FirmwareVersion.h" +#include "AmsStorage.h" +#include "LittleFS.h" + +void AmsMqttHandler::setCaVerification(bool caVerification) { + this->caVerification = caVerification; +} + +bool AmsMqttHandler::connect() { + if(millis() - lastMqttRetry < 10000) { + yield(); + return false; + } + lastMqttRetry = millis(); + + time_t epoch = time(nullptr); + + if(mqttConfig.ssl) { + if(epoch < FirmwareVersion::BuildEpoch) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("NTP not ready for MQTT SSL\n")); + return false; + } + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("MQTT SSL is configured (%dkb free heap)\n"), ESP.getFreeHeap()); + if(mqttSecureClient == NULL) { + mqttSecureClient = new WiFiClientSecure(); + #if defined(ESP8266) + mqttSecureClient->setBufferSizes(512, 512); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("ESP8266 firmware does not have enough memory...\n")); + return false; + #endif + + if(caVerification && LittleFS.begin()) { + File file; + + if(LittleFS.exists(FILE_MQTT_CA)) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Found MQTT CA file (%dkb free heap)\n"), ESP.getFreeHeap()); + file = LittleFS.open(FILE_MQTT_CA, (char*) "r"); + #if defined(ESP8266) + BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file); + mqttSecureClient->setTrustAnchors(serverTrustedCA); + #elif defined(ESP32) + if(mqttSecureClient->loadCACert(file, file.size())) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("CA accepted\n")); + } else { + if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("CA was rejected\n")); + delete mqttSecureClient; + mqttSecureClient = NULL; + return false; + } + #endif + file.close(); + + if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) { + #if defined(ESP8266) + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Found MQTT certificate file (%dkb free heap)\n"), ESP.getFreeHeap()); + file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); + BearSSL::X509List *serverCertList = new BearSSL::X509List(file); + file.close(); + + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Found MQTT key file (%dkb free heap)\n"), ESP.getFreeHeap()); + file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); + BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file); + file.close(); + + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Setting client certificates (%dkb free heap)"), ESP.getFreeHeap()); + mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey); + #elif defined(ESP32) + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Found MQTT certificate file (%dkb free heap)\n"), ESP.getFreeHeap()); + file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); + mqttSecureClient->loadCertificate(file, file.size()); + file.close(); + + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Found MQTT key file (%dkb free heap)\n"), ESP.getFreeHeap()); + file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); + mqttSecureClient->loadPrivateKey(file, file.size()); + file.close(); + #endif + } + } else { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("No CA, disabling validation\n")); + mqttSecureClient->setInsecure(); + } + LittleFS.end(); + } else { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("CA verification disabled\n")); + mqttSecureClient->setInsecure(); + } + mqttClient = mqttSecureClient; + + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("MQTT SSL setup complete (%dkb free heap)\n"), ESP.getFreeHeap()); + } + } + + if(mqttClient == NULL) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("No SSL, using client without SSL support\n")); + mqttClient = new WiFiClient(); + } + + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Connecting to MQTT %s:%d\n"), mqttConfig.host, mqttConfig.port); + + mqtt.begin(mqttConfig.host, mqttConfig.port, *mqttClient); + + #if defined(ESP8266) + if(mqttSecureClient) { + time_t epoch = time(nullptr); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Setting NTP time %lu for secure MQTT connection\n"), epoch); + mqttSecureClient->setX509Time(epoch); + } + #endif + + // Connect to a unsecure or secure MQTT server + if ((strlen(mqttConfig.username) == 0 && mqtt.connect(mqttConfig.clientId)) || + (strlen(mqttConfig.username) > 0 && mqtt.connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Successfully connected to MQTT!\n")); + return true; + } else { + if (debugger->isActive(RemoteDebug::ERROR)) { + debugger->printf_P(PSTR("Failed to connect to MQTT: %d\n"), mqtt.lastError()); + #if defined(ESP8266) + if(mqttSecureClient) { + mqttSecureClient->getLastSSLError((char*) json, BufferSize); + debugger->println((char*) json); + } + #endif + } + return false; + } +} + +void AmsMqttHandler::disconnect() { + mqtt.disconnect(); + mqtt.loop(); + delay(10); + yield(); + + if(mqttClient != NULL) { + mqttClient->stop(); + delete mqttClient; + mqttClient = NULL; + if(mqttSecureClient != NULL) { + mqttSecureClient = NULL; + } + } +} + +lwmqtt_err_t AmsMqttHandler::lastError() { + return mqtt.lastError(); +} + +bool AmsMqttHandler::connected() { + return mqtt.connected(); +} + +bool AmsMqttHandler::loop() { + bool ret = mqtt.loop(); + delay(10); + yield(); + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif + return ret; +} \ No newline at end of file diff --git a/lib/CloudConnector/include/CloudConnector.h b/lib/CloudConnector/include/CloudConnector.h index 9ea41673..fe291bdc 100644 --- a/lib/CloudConnector/include/CloudConnector.h +++ b/lib/CloudConnector/include/CloudConnector.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _CLOUDCONNECTOR_H #define _CLOUDCONNECTOR_H @@ -11,18 +17,28 @@ #include "mbedtls/error.h" #include "mbedtls/certs.h" #include "mbedtls/rsa.h" +#include "AmsConfiguration.h" +#include "AmsData.h" +#include "EnergyAccounting.h" +#include "HwTools.h" +#if defined(ESP8266) + #include +#elif defined(ESP32) // ARDUINO_ARCH_ESP32 + #include + #include + #include + #include +#else + #warning "Unsupported board type" +#endif -const unsigned char PUBLIC_KEY[] = \ -"-----BEGIN PUBLIC KEY-----\n"\ -"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoIo0CSuuX3tAdF7KPssdlzJNX\n"\ -"QryhgVV1rQIFPhHv3SxzyKtRrRM9s0CVfymcibhnEBXxxg3pxlGmwI/R6k7HHXJN\n"\ -"lBsXzzDtZ/GHDVnw+xRakTfRT0Zt+xdJSH5xJNWq4EwpvJfjA22L1Nz4dKSpgWMx\n"\ -"VRndAaXf0s7Q1XBz2wIDAQAB\n"\ -"-----END PUBLIC KEY-----\0"; +#define CC_BUF_SIZE 1024 - -//const unsigned char PUBLIC_KEY[] = { 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe8, 0x22, 0x8d, 0x02, 0x4a, 0xeb, 0x97, 0xde, 0xd0, 0x1d, 0x17, 0xb2, 0x8f, 0xb2, 0xc7, 0x65, 0xcc, 0x93, 0x57, 0x42, 0xbc, 0xa1, 0x81, 0x55, 0x75, 0xad, 0x02, 0x05, 0x3e, 0x11, 0xef, 0xdd, 0x2c, 0x73, 0xc8, 0xab, 0x51, 0xad, 0x13, 0x3d, 0xb3, 0x40, 0x95, 0x7f, 0x29, 0x9c, 0x89, 0xb8, 0x67, 0x10, 0x15, 0xf1, 0xc6, 0x0d, 0xe9, 0xc6, 0x51, 0xa6, 0xc0, 0x8f, 0xd1, 0xea, 0x4e, 0xc7, 0x1d, 0x72, 0x4d, 0x94, 0x1b, 0x17, 0xcf, 0x30, 0xed, 0x67, 0xf1, 0x87, 0x0d, 0x59, 0xf0, 0xfb, 0x14, 0x5a, 0x91, 0x37, 0xd1, 0x4f, 0x46, 0x6d, 0xfb, 0x17, 0x49, 0x48, 0x7e, 0x71, 0x24, 0xd5, 0xaa, 0xe0, 0x4c, 0x29, 0xbc, 0x97, 0xe3, 0x03, 0x6d, 0x8b, 0xd4, 0xdc, 0xf8, 0x74, 0xa4, 0xa9, 0x81, 0x63, 0x31, 0x55, 0x19, 0xdd, 0x01, 0xa5, 0xdf, 0xd2, 0xce, 0xd0, 0xd5, 0x70, 0x73, 0xdb, 0x02, 0x03, 0x01, 0x00, 0x01}; +static const char CC_JSON_POWER[] PROGMEM = ",\"%s\":{\"P\":%lu,\"Q\":%lu}"; +static const char CC_JSON_POWER_LIST3[] PROGMEM = ",\"%s\":{\"P\":%lu,\"Q\":%lu,\"tP\":%.3f,\"tQ\":%.3f}"; +static const char CC_JSON_PHASE[] PROGMEM = "%s\"%d\":{\"u\":%.2f,\"i\":%.2f}"; +static const char CC_JSON_PHASE_LIST4[] PROGMEM = "%s\"%d\":{\"u\":%.2f,\"i\":%.2f,\"Pim\":%lu,\"Pex\":%lu,\"pf\":%.2f}"; struct CloudData { uint8_t type; @@ -32,16 +48,41 @@ struct CloudData { class CloudConnector { public: CloudConnector(RemoteDebug*); - void setup(const unsigned char * key); - void send(); + void setup(CloudConfig& config, HwTools* hw); + void update(AmsData& data, EnergyAccounting& ea); + void forceUpdate(); private: RemoteDebug* debugger; + HwTools* hw; + CloudConfig config; + HTTPClient http; + WiFiUDP udp; + bool initialized = false; + unsigned long lastUpdate = 0; + char mac[18]; - unsigned char buf[4096]; + char clearBuffer[CC_BUF_SIZE]; + unsigned char encryptedBuffer[256]; mbedtls_rsa_context* rsa = nullptr; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + char* pers = "amsreader"; + bool init(); void debugPrint(byte *buffer, int start, int length); + String meterManufacturer(uint8_t type) { + switch(type) { + case AmsTypeAidon: return F("Aidon"); + case AmsTypeKaifa: return F("Kaifa"); + case AmsTypeKamstrup: return F("Kamstrup"); + case AmsTypeIskra: return F("Iskra"); + case AmsTypeLandisGyr: return F("Landis+Gyr"); + case AmsTypeSagemcom: return F("Sagemcom"); + } + return F(""); + } + }; -#endif +#endif \ No newline at end of file diff --git a/lib/CloudConnector/src/CloudConnector.cpp b/lib/CloudConnector/src/CloudConnector.cpp index 7dbb5976..be242145 100644 --- a/lib/CloudConnector/src/CloudConnector.cpp +++ b/lib/CloudConnector/src/CloudConnector.cpp @@ -1,44 +1,223 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "CloudConnector.h" +#include "FirmwareVersion.h" +#include "crc.h" +#include "Uptime.h" +#include "hexutils.h" CloudConnector::CloudConnector(RemoteDebug* debugger) { this->debugger = debugger; - mbedtls_pk_context pk; - mbedtls_pk_init(&pk); - int error_code = 0; - if((error_code = mbedtls_pk_parse_public_key(&pk, PUBLIC_KEY, sizeof(PUBLIC_KEY))) == 0){ - debugger->printf("RSA public key OK\n"); - rsa = mbedtls_pk_rsa(pk); - } else { - debugger->printf("RSA public key read error: "); - mbedtls_strerror(error_code, (char*) buf, 4096); - debugger->printf("%s\n", buf); - } - debugger->flush(); - //send(); + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + http.setReuse(false); + http.setTimeout(60000); + http.setUserAgent("ams2mqtt/" + String(FirmwareVersion::VersionString)); + http.useHTTP10(true); + + uint8_t mac[6]; + + #if defined(ESP8266) + wifi_get_macaddr(STATION_IF, mac); + #elif defined(ESP32) + esp_wifi_get_mac((wifi_interface_t)ESP_IF_WIFI_STA, mac); + #endif + sprintf(this->mac, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } -void CloudConnector::send() { - if(rsa != nullptr && mbedtls_rsa_check_pubkey(rsa) == 0) { - memset(buf, 0, 4096); - - CloudData data = {65, 127}; - unsigned char toEncrypt[4096] = {0}; - - debugger->println("RSA clear data: "); - debugPrint(toEncrypt, 0, 256); - - mbedtls_rsa_rsaes_pkcs1_v15_encrypt(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, 256, toEncrypt, buf); - - //byte hashResult[32]; - //mbedtls_sha256(toEncrypt, strlen((char*) toEncrypt), hashResult, 0); - //int success = mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, strlen((char*) hashResult), hashResult, buf); - debugger->println("RSA encrypted data: "); - debugPrint(buf, 0, 256); - } else { - debugger->println("RSA key is invalid"); - } +void CloudConnector::setup(CloudConfig& config, HwTools* hw) { + this->config = config; + this->hw = hw; } + +bool CloudConnector::init() { + if(config.enabled && strlen(config.hostname) > 0 && config.port > 0) { + snprintf_P(clearBuffer, CC_BUF_SIZE, PSTR("http://%s/hub/cloud/public.key"), config.hostname); + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(CloudConnector) Downloading public key from %s\n", clearBuffer); + #if defined(ESP8266) + WiFiClient client; + client.setTimeout(5000); + if(http.begin(client, clearBuffer)) { + #elif defined(ESP32) + if(http.begin(clearBuffer)) { + #endif + int status = http.GET(); + + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif + + if(status == HTTP_CODE_OK) { + String pub = http.getString(); + http.end(); + + memset(clearBuffer, 0, CC_BUF_SIZE); + snprintf(clearBuffer, CC_BUF_SIZE, pub.c_str()); + + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Cloud public key:\n%s\n", clearBuffer); + + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + + int error_code = 0; + if((error_code = mbedtls_pk_parse_public_key(&pk, (unsigned char*) clearBuffer, strlen((const char*) clearBuffer)+1)) == 0){ + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("RSA public key OK\n"); + rsa = mbedtls_pk_rsa(pk); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + + int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, + &entropy, (const unsigned char *) pers, + strlen(pers)); + if(ret != 0) { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("mbedtls_ctr_drbg_seed return code: %d\n", ret); + } + return ret == 0; + } else { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("RSA public key read error: "); + mbedtls_strerror(error_code, clearBuffer, CC_BUF_SIZE); + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("%s\n", clearBuffer); + } + } else { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(CloudConnector) Communication error, returned status: %d\n"), status); + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(http.errorToString(status).c_str()); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(http.getString().c_str()); + + http.end(); + } + } + } + return false; +} + +void CloudConnector::update(AmsData& data, EnergyAccounting& ea) { + if(!config.enabled || strlen(config.hostname) == 0 || config.port == 0) return; + unsigned long now = millis(); + if(now-lastUpdate < config.interval*1000) return; + lastUpdate = now; + if(strlen(config.clientId) == 0 || strlen(config.clientSecret) == 0) { + if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf("(CloudConnector) Client ID and secret is missing\n"); + return; + } + if(data.getListType() < 2) return; + + memset(clearBuffer, 0, CC_BUF_SIZE); + + int pos = 0; + if(initialized) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR("{\"id\":\"%s\",\"secret\":\"%s\",\"data\":{\"clock\":%lu,\"up\":%lu,\"lastUpdate\":%lu,\"est\":%s"), + config.clientId, + config.clientSecret, + (uint32_t) time(nullptr), + (uint32_t) (millis64()/1000), + (uint32_t) (data.getLastUpdateMillis()/1000), + data.isCounterEstimated() ? "true" : "false" + ); + if(data.getListType() > 2) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_POWER_LIST3, "import", data.getActiveImportPower(), data.getReactiveImportPower(), data.getActiveImportCounter(), data.getReactiveImportCounter()); + } else { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_POWER, "import", data.getActiveImportPower(), data.getReactiveImportPower()); + } + if(data.getListType() > 2) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_POWER_LIST3, "export", data.getActiveExportPower(), data.getReactiveExportPower(), data.getActiveExportCounter(), data.getReactiveExportCounter()); + } else { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_POWER, "export", data.getActiveExportPower(), data.getReactiveExportPower()); + } + + if(data.getListType() > 1) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR(",\"phases\":{")); + bool first = true; + if(data.getL1Voltage() > 0.0) { + if(data.getListType() > 3) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE_LIST4, first ? "" : ",", 1, data.getL1Voltage(), data.getL1Current(), data.getL1ActiveImportPower(), data.getL1ActiveExportPower(), data.getL1PowerFactor()); + } else { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE, first ? "" : ",", 1, data.getL1Voltage(), data.getL1Current()); + } + first = false; + } + if(data.getL2Voltage() > 0.0) { + if(data.getListType() > 3) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE_LIST4, first ? "" : ",", 2, data.getL2Voltage(), data.getL2Current(), data.getL2ActiveImportPower(), data.getL2ActiveExportPower(), data.getL2PowerFactor()); + } else { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE, first ? "" : ",", 2, data.getL2Voltage(), data.getL2Current()); + } + first = false; + } + if(data.getL3Voltage() > 0.0) { + if(data.getListType() > 3) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE_LIST4, first ? "" : ",", 3, data.getL3Voltage(), data.getL3Current(), data.getL3ActiveImportPower(), data.getL3ActiveExportPower(), data.getL3PowerFactor()); + } else { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, CC_JSON_PHASE, first ? "" : ",", 3, data.getL3Voltage(), data.getL3Current()); + } + first = false; + } + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR("}")); + } + if(data.getListType() > 3) { + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR(",\"pf\":%.2f"), data.getPowerFactor()); + } + + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR(",\"realtime\":{\"import\":%.3f,\"export\":%.3f}"), ea.getUseThisHour(), ea.getProducedThisHour()); + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR(",\"vcc\":%.2f,\"temp\":%.2f,\"rssi\":%d,\"free\":%d"), hw->getVcc(), hw->getTemperature(), hw->getWifiRssi(), ESP.getFreeHeap()); + + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR("}")); + } else { + if(!init()) { + if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf("Unable to initialize cloud connector\n"); + return; + } + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR("{\"id\":\"%s\",\"secret\":\"%s\",\"init\":{\"mac\":\"%s\",\"version\":\"%s\"},\"meter\":{\"manufacturer\":\"%s\",\"model\":\"%s\",\"id\":\"%s\"}"), + config.clientId, + config.clientSecret, + mac, + FirmwareVersion::VersionString, + meterManufacturer(data.getMeterType()).c_str(), + data.getMeterModel().c_str(), + data.getMeterId().c_str() + ); + initialized = true; + } + uint16_t crc = crc16((uint8_t*) clearBuffer, pos); + pos += snprintf_P(clearBuffer+pos, CC_BUF_SIZE-pos, PSTR(",\"crc\":\"%04X\"}"), crc); + + if(rsa == nullptr) return; + int ret = mbedtls_rsa_check_pubkey(rsa); + if(ret != 0) { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("mbedtls_rsa_pkcs1_encrypt return code: %d\n", ret); + mbedtls_strerror(ret, clearBuffer, CC_BUF_SIZE); + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("%s\n", clearBuffer); + return; + } + memset(encryptedBuffer, 0, rsa->len); + + int maxlen = 100 * (rsa->len/128); + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(CloudConnector) Sending %d bytes and maxlen %d\n", pos, maxlen); + udp.beginPacket(config.hostname,7443); + for(int i = 0; i < pos; i += maxlen) { + int size = min(maxlen, pos-i); + int ret = mbedtls_rsa_pkcs1_encrypt(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, size, (unsigned char*) (clearBuffer+i), encryptedBuffer); + if(ret == 0) { + udp.write(encryptedBuffer, rsa->len); + delay(1); + } else { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("mbedtls_rsa_pkcs1_encrypt return code: %d\n", ret); + mbedtls_strerror(ret, clearBuffer, CC_BUF_SIZE); + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("%s\n", clearBuffer); + } + } + udp.endPacket(); +} + +void CloudConnector::forceUpdate() { + lastUpdate = 0; +} + void CloudConnector::debugPrint(byte *buffer, int start, int length) { for (int i = start; i < start + length; i++) { if (buffer[i] < 0x10) diff --git a/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h b/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h index e0630ff4..3b51f57a 100644 --- a/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h +++ b/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DOMOTICZMQTTHANDLER_H #define _DOMOTICZMQTTHANDLER_H @@ -6,13 +12,16 @@ class DomoticzMqttHandler : public AmsMqttHandler { public: - DomoticzMqttHandler(MQTTClient* mqtt, char* buf, DomoticzConfig config) : AmsMqttHandler(mqtt, buf) { + DomoticzMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, DomoticzConfig config) : AmsMqttHandler(mqttConfig, debugger, buf) { this->config = config; }; bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); + bool publishRaw(String data); + + uint8_t getFormat(); private: DomoticzConfig config; diff --git a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp index e0147ef0..82e655e1 100644 --- a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp +++ b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "DomoticzMqttHandler.h" #include "json/domoticz_json.h" @@ -14,7 +20,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.elidx, val ); - ret = mqtt->publish(F("domoticz/in"), json); + ret = mqtt.publish(F("domoticz/in"), json); } } @@ -28,7 +34,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.vl1idx, val ); - ret |= mqtt->publish(F("domoticz/in"), json); + ret |= mqtt.publish(F("domoticz/in"), json); } if (config.vl2idx > 0){ @@ -38,7 +44,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.vl2idx, val ); - ret |= mqtt->publish(F("domoticz/in"), json); + ret |= mqtt.publish(F("domoticz/in"), json); } if (config.vl3idx > 0){ @@ -48,7 +54,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.vl3idx, val ); - ret |= mqtt->publish(F("domoticz/in"), json); + ret |= mqtt.publish(F("domoticz/in"), json); } if (config.cl1idx > 0){ @@ -58,7 +64,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA config.cl1idx, val ); - ret |= mqtt->publish(F("domoticz/in"), json); + ret |= mqtt.publish(F("domoticz/in"), json); } return ret; } @@ -74,3 +80,11 @@ bool DomoticzMqttHandler::publishPrices(EntsoeApi* eapi) { bool DomoticzMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { return false; } + +uint8_t DomoticzMqttHandler::getFormat() { + return 3; +} + +bool DomoticzMqttHandler::publishRaw(String data) { + return false; +} diff --git a/lib/EnergyAccounting/include/EnergyAccounting.h b/lib/EnergyAccounting/include/EnergyAccounting.h index 10ee6817..46af44ae 100644 --- a/lib/EnergyAccounting/include/EnergyAccounting.h +++ b/lib/EnergyAccounting/include/EnergyAccounting.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _ENERGYACCOUNTING_H #define _ENERGYACCOUNTING_H diff --git a/lib/EnergyAccounting/src/EnergyAccounting.cpp b/lib/EnergyAccounting/src/EnergyAccounting.cpp index f93e2cdf..823e344b 100644 --- a/lib/EnergyAccounting/src/EnergyAccounting.cpp +++ b/lib/EnergyAccounting/src/EnergyAccounting.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "EnergyAccounting.h" #include "LittleFS.h" #include "AmsStorage.h" diff --git a/lib/EntsoePriceApi/include/DnbCurrParser.h b/lib/EntsoePriceApi/include/DnbCurrParser.h index 25032342..0cce8c34 100644 --- a/lib/EntsoePriceApi/include/DnbCurrParser.h +++ b/lib/EntsoePriceApi/include/DnbCurrParser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _DNBCURRPARSER_H #define _DNBCURRPARSER_H diff --git a/lib/EntsoePriceApi/include/EntsoeA44Parser.h b/lib/EntsoePriceApi/include/EntsoeA44Parser.h index bc144a59..3a96aad9 100644 --- a/lib/EntsoePriceApi/include/EntsoeA44Parser.h +++ b/lib/EntsoePriceApi/include/EntsoeA44Parser.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _ENTSOEA44PARSER_H #define _ENTSOEA44PARSER_H diff --git a/lib/EntsoePriceApi/include/EntsoeApi.h b/lib/EntsoePriceApi/include/EntsoeApi.h index 80a5902c..2f4fd28f 100644 --- a/lib/EntsoePriceApi/include/EntsoeApi.h +++ b/lib/EntsoePriceApi/include/EntsoeApi.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _ENTSOEAPI_H #define _ENTSOEAPI_H diff --git a/lib/EntsoePriceApi/include/PricesContainer.h b/lib/EntsoePriceApi/include/PricesContainer.h index dea3050f..89671bcf 100644 --- a/lib/EntsoePriceApi/include/PricesContainer.h +++ b/lib/EntsoePriceApi/include/PricesContainer.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _PRICESCONTAINER_H #define _PRICESCONTAINER_H struct PricesContainer { diff --git a/lib/EntsoePriceApi/src/DnbCurrParser.cpp b/lib/EntsoePriceApi/src/DnbCurrParser.cpp index 4c576ef1..3233e7a9 100644 --- a/lib/EntsoePriceApi/src/DnbCurrParser.cpp +++ b/lib/EntsoePriceApi/src/DnbCurrParser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "DnbCurrParser.h" #include "Arduino.h" diff --git a/lib/EntsoePriceApi/src/EntsoeA44Parser.cpp b/lib/EntsoePriceApi/src/EntsoeA44Parser.cpp index 51bda13e..d7c6247a 100644 --- a/lib/EntsoePriceApi/src/EntsoeA44Parser.cpp +++ b/lib/EntsoePriceApi/src/EntsoeA44Parser.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "EntsoeA44Parser.h" #include "HardwareSerial.h" diff --git a/lib/EntsoePriceApi/src/EntsoeApi.cpp b/lib/EntsoePriceApi/src/EntsoeApi.cpp index 03acd606..8e931141 100644 --- a/lib/EntsoePriceApi/src/EntsoeApi.cpp +++ b/lib/EntsoePriceApi/src/EntsoeApi.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "EntsoeApi.h" #include #include "Uptime.h" diff --git a/lib/FirmwareVersion/include/FirmwareVersion.h b/lib/FirmwareVersion/include/FirmwareVersion.h index 291e2668..d6487f25 100644 --- a/lib/FirmwareVersion/include/FirmwareVersion.h +++ b/lib/FirmwareVersion/include/FirmwareVersion.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _FIRMWARE_VERSION_h #define _FIRMWARE_VERSION_h diff --git a/lib/FirmwareVersion/src/FirmwareVersion.cpp b/lib/FirmwareVersion/src/FirmwareVersion.cpp index b8386871..7155a617 100644 --- a/lib/FirmwareVersion/src/FirmwareVersion.cpp +++ b/lib/FirmwareVersion/src/FirmwareVersion.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "FirmwareVersion.h" #include "generated_version.h" diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h index 3157b9e2..9da088b9 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _HOMEASSISTANTMQTTHANDLER_H #define _HOMEASSISTANTMQTTHANDLER_H @@ -7,12 +13,12 @@ class HomeAssistantMqttHandler : public AmsMqttHandler { public: - HomeAssistantMqttHandler(MQTTClient* mqtt, char* buf, const char* clientId, const char* topic, uint8_t boardType, HomeAssistantConfig config, HwTools* hw) : AmsMqttHandler(mqtt, buf) { - this->clientId = clientId; - this->topic = String(topic); + HomeAssistantMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, uint8_t boardType, HomeAssistantConfig config, HwTools* hw) : AmsMqttHandler(mqttConfig, debugger, buf) { this->hw = hw; l1Init = l2Init = l2eInit = l3Init = l3eInit = l4Init = l4eInit = rtInit = rteInit = pInit = sInit = false; + topic = String(mqttConfig.publishTopic); + if(strlen(config.discoveryNameTag) > 0) { snprintf_P(buf, 128, PSTR("AMS reader (%s)"), config.discoveryNameTag); deviceName = String(buf); @@ -56,11 +62,13 @@ public: bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); + bool publishRaw(String data); -protected: - bool loop(); + uint8_t getFormat(); private: + String topic; + String deviceName; String deviceModel; String deviceUid; @@ -74,8 +82,6 @@ private: bool tInit[32] = {false}; bool prInit[38] = {false}; - String clientId; - String topic; HwTools* hw; bool publishList1(AmsData* data, EnergyAccounting* ea); diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h index 8fceefad..685e1ad6 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _HOMEASSISTANTSTATIC_H #define _HOMEASSISTANTSTATIC_H diff --git a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp index 18897833..38a1da3b 100644 --- a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp +++ b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "HomeAssistantMqttHandler.h" #include "hexutils.h" #include "Uptime.h" @@ -16,7 +22,7 @@ #endif bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; if(data->getListType() >= 3) { // publish energy counts @@ -45,7 +51,7 @@ bool HomeAssistantMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) snprintf_P(json, BufferSize, HA1_JSON, data->getActiveImportPower() ); - return mqtt->publish(topic + "/power", json); + return mqtt.publish(topic + "/power", json); } bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { @@ -66,7 +72,7 @@ bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) data->getL2Voltage(), data->getL3Voltage() ); - return mqtt->publish(topic + "/power", json); + return mqtt.publish(topic + "/power", json); } bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { @@ -79,7 +85,7 @@ bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) data->getReactiveExportCounter(), data->getMeterTimestamp() ); - return mqtt->publish(topic + "/energy", json); + return mqtt.publish(topic + "/energy", json); } bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { @@ -110,7 +116,7 @@ bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(), data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor() ); - return mqtt->publish(topic + "/power", json); + return mqtt.publish(topic + "/power", json); } String HomeAssistantMqttHandler::getMeterModel(AmsData* data) { @@ -146,7 +152,7 @@ bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting* ea->getProducedThisMonth(), ea->getIncomeThisMonth() ); - return mqtt->publish(topic + "/realtime", json); + return mqtt.publish(topic + "/realtime", json); } @@ -174,13 +180,13 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT } char* pos = buf+strlen(buf); snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}")); - bool ret = mqtt->publish(topic + "/temperatures", buf); + bool ret = mqtt.publish(topic + "/temperatures", buf); loop(); return ret; } bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; if(eapi->getValueForHour(0) == ENTSOE_NO_VALUE) return false; @@ -310,13 +316,13 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { ts3hr, ts6hr ); - bool ret = mqtt->publish(topic + "/prices", json, true, 0); + bool ret = mqtt.publish(topic + "/prices", json, true, 0); loop(); return ret; } bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; publishSystemSensors(); @@ -324,14 +330,14 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ snprintf_P(json, BufferSize, JSONSYS_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), hw->getVcc(), hw->getWifiRssi(), hw->getTemperature(), FirmwareVersion::VersionString ); - bool ret = mqtt->publish(topic + "/state", json); + bool ret = mqtt.publish(topic + "/state", json); loop(); return ret; } @@ -345,7 +351,7 @@ void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) snprintf_P(json, BufferSize, HADISCOVER_JSON, sensorNamePrefix.c_str(), sensor.name, - topic.c_str(), sensor.topic, + mqttConfig.publishTopic, sensor.topic, deviceUid.c_str(), uid.c_str(), deviceUid.c_str(), uid.c_str(), sensor.uom, @@ -363,7 +369,7 @@ void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : "", strlen_P(sensor.stacl) > 0 ? "\"" : "" ); - mqtt->publish(discoveryTopic + deviceUid + "_" + uid.c_str() + "/config", json, true, 0); + mqtt.publish(discoveryTopic + deviceUid + "_" + uid.c_str() + "/config", json, true, 0); loop(); } @@ -540,14 +546,10 @@ void HomeAssistantMqttHandler::publishSystemSensors() { sInit = true; } -bool HomeAssistantMqttHandler::loop() { - bool ret = mqtt->loop(); - delay(10); - yield(); - #if defined(ESP32) - esp_task_wdt_reset(); - #elif defined(ESP8266) - ESP.wdtFeed(); - #endif - return ret; +uint8_t HomeAssistantMqttHandler::getFormat() { + return 4; +} + +bool HomeAssistantMqttHandler::publishRaw(String data) { + return false; } diff --git a/lib/HwTools/include/HwTools.h b/lib/HwTools/include/HwTools.h index 29085a02..945555bf 100644 --- a/lib/HwTools/include/HwTools.h +++ b/lib/HwTools/include/HwTools.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _HWTOOLS_H #define _HWTOOLS_H @@ -48,6 +54,7 @@ public: bool ledOn(uint8_t color); bool ledOff(uint8_t color); bool ledBlink(uint8_t color, uint8_t blink); + void setBootSuccessful(); HwTools() {}; private: @@ -64,6 +71,8 @@ private: uint8_t sensorCount = 0; TempSensorData** tempSensors = NULL; + bool bootSuccessful = false; + bool writeLedPin(uint8_t color, uint8_t state); bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]); void getAdcChannel(uint8_t pin, AdcConfig&); diff --git a/lib/HwTools/src/HwTools.cpp b/lib/HwTools/src/HwTools.cpp index a6ab2ec2..dd807f92 100644 --- a/lib/HwTools/src/HwTools.cpp +++ b/lib/HwTools/src/HwTools.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "HwTools.h" void HwTools::setup(GpioConfig* config, AmsConfiguration* amsConf) { @@ -92,6 +98,22 @@ void HwTools::setup(GpioConfig* config, AmsConfiguration* amsConf) { } else { config->ledPinBlue = 0xFF; } + if(config->ledDisablePin > 0 && config->ledDisablePin < 40) { + pinMode(config->ledDisablePin, OUTPUT_OPEN_DRAIN); + switch(config->ledBehaviour) { + case LED_BEHAVIOUR_ERROR_ONLY: + case LED_BEHAVIOUR_OFF: + digitalWrite(config->ledDisablePin, LOW); + break; + case LED_BEHAVIOUR_BOOT: + if(bootSuccessful) { + digitalWrite(config->ledDisablePin, LOW); + } + break; + default: + digitalWrite(config->ledDisablePin, HIGH); + } + } } void HwTools::getAdcChannel(uint8_t pin, AdcConfig& config) { @@ -358,8 +380,7 @@ float HwTools::getTemperature() { } for(int x = 0; x < sensorCount; x++) { TempSensorData data = *tempSensors[x]; - TempSensorConfig* conf = amsConf->getTempSensorConfig(data.address); - if((conf == NULL || conf->common) && data.lastValidRead > -85) { + if(data.lastValidRead > -85) { ret += data.lastValidRead; c++; } @@ -380,7 +401,19 @@ int HwTools::getWifiRssi() { return isnan(rssi) ? -100.0 : rssi; } +void HwTools::setBootSuccessful() { + if(bootSuccessful) return; + bootSuccessful = true; + if(config->ledBehaviour != LED_BEHAVIOUR_DEFAULT) { + digitalWrite(config->ledDisablePin, LOW); + } +} + bool HwTools::ledOn(uint8_t color) { + if(config->ledBehaviour == LED_BEHAVIOUR_OFF) return false; + if(config->ledBehaviour == LED_BEHAVIOUR_ERROR_ONLY && color != LED_RED) return false; + if(config->ledBehaviour == LED_BEHAVIOUR_BOOT && color != LED_RED && bootSuccessful) return false; + if(color == LED_INTERNAL) { return writeLedPin(color, config->ledInverted ? LOW : HIGH); } else { diff --git a/lib/JsonMqttHandler/include/JsonMqttHandler.h b/lib/JsonMqttHandler/include/JsonMqttHandler.h index 8bccdc3b..d2b5cd22 100644 --- a/lib/JsonMqttHandler/include/JsonMqttHandler.h +++ b/lib/JsonMqttHandler/include/JsonMqttHandler.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _JSONMQTTHANDLER_H #define _JSONMQTTHANDLER_H @@ -5,22 +11,18 @@ class JsonMqttHandler : public AmsMqttHandler { public: - JsonMqttHandler(MQTTClient* mqtt, char* buf, const char* clientId, const char* topic, HwTools* hw) : AmsMqttHandler(mqtt, buf) { - this->clientId = clientId; - this->topic = String(topic); + JsonMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, HwTools* hw) : AmsMqttHandler(mqttConfig, debugger, buf) { this->hw = hw; }; bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); + bool publishRaw(String data); -protected: - bool loop(); + uint8_t getFormat(); private: - String clientId; - String topic; HwTools* hw; bool publishList1(AmsData* data, EnergyAccounting* ea); diff --git a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp index 3bb6bdf6..fb1fd980 100644 --- a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp +++ b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "JsonMqttHandler.h" #include "FirmwareVersion.h" #include "hexutils.h" @@ -10,11 +16,18 @@ #include "json/jsonprices_json.h" bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(strlen(mqttConfig.publishTopic) == 0) { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Unable to publish data, no publish topic\n")); + return false; + } + if(!mqtt.connected()) { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Unable to publish data, not connected\n")); return false; + } bool ret = false; + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Publishing list ID %d!\n"), data->getListType()); if(data->getListType() == 1) { ret = publishList1(data, ea); } else if(data->getListType() == 2) { @@ -31,7 +44,7 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou bool JsonMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) { snprintf_P(json, BufferSize, JSON1_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), data->getPackageTimestamp(), hw->getVcc(), @@ -45,13 +58,13 @@ bool JsonMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) { ea->getProducedThisHour(), ea->getProducedToday() ); - return mqtt->publish(topic, json); + return mqtt.publish(mqttConfig.publishTopic, json); } bool JsonMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { snprintf_P(json, BufferSize, JSON2_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), data->getPackageTimestamp(), hw->getVcc(), @@ -77,13 +90,13 @@ bool JsonMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { ea->getProducedThisHour(), ea->getProducedToday() ); - return mqtt->publish(topic, json); + return mqtt.publish(mqttConfig.publishTopic, json); } bool JsonMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { snprintf_P(json, BufferSize, JSON3_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), data->getPackageTimestamp(), hw->getVcc(), @@ -114,13 +127,13 @@ bool JsonMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { ea->getProducedThisHour(), ea->getProducedToday() ); - return mqtt->publish(topic, json); + return mqtt.publish(mqttConfig.publishTopic, json); } bool JsonMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { snprintf_P(json, BufferSize, JSON4_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), data->getPackageTimestamp(), hw->getVcc(), @@ -161,7 +174,7 @@ bool JsonMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { ea->getProducedThisHour(), ea->getProducedToday() ); - return mqtt->publish(topic, json); + return mqtt.publish(mqttConfig.publishTopic, json); } String JsonMqttHandler::getMeterModel(AmsData* data) { @@ -191,13 +204,13 @@ bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) } char* pos = json+strlen(json); snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}")); - bool ret = mqtt->publish(topic, json); + bool ret = mqtt.publish(mqttConfig.publishTopic, json); loop(); return ret; } bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(strlen(mqttConfig.publishTopic) == 0 || !mqtt.connected()) return false; if(eapi->getValueForHour(0) == ENTSOE_NO_VALUE) return false; @@ -325,37 +338,33 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { ts3hr, ts6hr ); - bool ret = mqtt->publish(topic, json); + bool ret = mqtt.publish(mqttConfig.publishTopic, json); loop(); return ret; } bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { - if(topic.isEmpty() || !mqtt->connected()) + if(strlen(mqttConfig.publishTopic) == 0 || !mqtt.connected()) return false; snprintf_P(json, BufferSize, JSONSYS_JSON, WiFi.macAddress().c_str(), - clientId.c_str(), + mqttConfig.clientId, (uint32_t) (millis64()/1000), hw->getVcc(), hw->getWifiRssi(), hw->getTemperature(), FirmwareVersion::VersionString ); - bool ret = mqtt->publish(topic, json); + bool ret = mqtt.publish(mqttConfig.publishTopic, json); loop(); return ret; } -bool JsonMqttHandler::loop() { - bool ret = mqtt->loop(); - delay(10); - yield(); - #if defined(ESP32) - esp_task_wdt_reset(); - #elif defined(ESP8266) - ESP.wdtFeed(); - #endif - return ret; +uint8_t JsonMqttHandler::getFormat() { + return 0; +} + +bool JsonMqttHandler::publishRaw(String data) { + return false; } diff --git a/lib/RawMqttHandler/include/RawMqttHandler.h b/lib/RawMqttHandler/include/RawMqttHandler.h index 5ab9b1bb..fd2500c2 100644 --- a/lib/RawMqttHandler/include/RawMqttHandler.h +++ b/lib/RawMqttHandler/include/RawMqttHandler.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _RAWMQTTHANDLER_H #define _RAWMQTTHANDLER_H @@ -5,21 +11,21 @@ class RawMqttHandler : public AmsMqttHandler { public: - RawMqttHandler(MQTTClient* mqtt, char* buf, const char* topic, bool full) : AmsMqttHandler(mqtt, buf) { - this->topic = String(topic); - this->full = full; + RawMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf) : AmsMqttHandler(mqttConfig, debugger, buf) { + full = mqttConfig.payloadFormat == 2; + topic = String(mqttConfig.publishTopic); }; bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); + bool publishRaw(String data); -protected: - bool loop(); + uint8_t getFormat(); private: - String topic; bool full; + String topic; bool publishList1(AmsData* data, AmsData* meterState); bool publishList2(AmsData* data, AmsData* meterState); diff --git a/lib/RawMqttHandler/src/RawMqttHandler.cpp b/lib/RawMqttHandler/src/RawMqttHandler.cpp index 792c59ea..70c4a300 100644 --- a/lib/RawMqttHandler/src/RawMqttHandler.cpp +++ b/lib/RawMqttHandler/src/RawMqttHandler.cpp @@ -1,13 +1,19 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "RawMqttHandler.h" #include "hexutils.h" #include "Uptime.h" bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccounting* ea, EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; if(data->getPackageTimestamp() > 0) { - mqtt->publish(topic + "/meter/dlms/timestamp", String(data->getPackageTimestamp())); + mqtt.publish(topic + "/meter/dlms/timestamp", String(data->getPackageTimestamp())); } switch(data->getListType()) { case 4: @@ -32,7 +38,7 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin bool RawMqttHandler::publishList1(AmsData* data, AmsData* meterState) { if(full || meterState->getActiveImportPower() != data->getActiveImportPower()) { - mqtt->publish(topic + "/meter/import/active", String(data->getActiveImportPower())); + mqtt.publish(topic + "/meter/import/active", String(data->getActiveImportPower())); } return true; } @@ -40,101 +46,101 @@ bool RawMqttHandler::publishList1(AmsData* data, AmsData* meterState) { bool RawMqttHandler::publishList2(AmsData* data, AmsData* meterState) { // Only send data if changed. ID and Type is sent on the 10s interval only if changed if(full || meterState->getMeterId() != data->getMeterId()) { - mqtt->publish(topic + "/meter/id", data->getMeterId()); + mqtt.publish(topic + "/meter/id", data->getMeterId()); } if(full || meterState->getMeterModel() != data->getMeterModel()) { - mqtt->publish(topic + "/meter/type", data->getMeterModel()); + mqtt.publish(topic + "/meter/type", data->getMeterModel()); } if(full || meterState->getL1Current() != data->getL1Current()) { - mqtt->publish(topic + "/meter/l1/current", String(data->getL1Current(), 2)); + mqtt.publish(topic + "/meter/l1/current", String(data->getL1Current(), 2)); } if(full || meterState->getL1Voltage() != data->getL1Voltage()) { - mqtt->publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2)); + mqtt.publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2)); } if(full || meterState->getL2Current() != data->getL2Current()) { - mqtt->publish(topic + "/meter/l2/current", String(data->getL2Current(), 2)); + mqtt.publish(topic + "/meter/l2/current", String(data->getL2Current(), 2)); } if(full || meterState->getL2Voltage() != data->getL2Voltage()) { - mqtt->publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2)); + mqtt.publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2)); } if(full || meterState->getL3Current() != data->getL3Current()) { - mqtt->publish(topic + "/meter/l3/current", String(data->getL3Current(), 2)); + mqtt.publish(topic + "/meter/l3/current", String(data->getL3Current(), 2)); } if(full || meterState->getL3Voltage() != data->getL3Voltage()) { - mqtt->publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2)); + mqtt.publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2)); } if(full || meterState->getReactiveExportPower() != data->getReactiveExportPower()) { - mqtt->publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower())); + mqtt.publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower())); } if(full || meterState->getActiveExportPower() != data->getActiveExportPower()) { - mqtt->publish(topic + "/meter/export/active", String(data->getActiveExportPower())); + mqtt.publish(topic + "/meter/export/active", String(data->getActiveExportPower())); } if(full || meterState->getReactiveImportPower() != data->getReactiveImportPower()) { - mqtt->publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower())); + mqtt.publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower())); } return true; } bool RawMqttHandler::publishList3(AmsData* data, AmsData* meterState) { // ID and type belongs to List 2, but I see no need to send that every 10s - mqtt->publish(topic + "/meter/id", data->getMeterId(), true, 0); - mqtt->publish(topic + "/meter/type", data->getMeterModel(), true, 0); - mqtt->publish(topic + "/meter/clock", String(data->getMeterTimestamp())); - mqtt->publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0); + mqtt.publish(topic + "/meter/id", data->getMeterId(), true, 0); + mqtt.publish(topic + "/meter/type", data->getMeterModel(), true, 0); + mqtt.publish(topic + "/meter/clock", String(data->getMeterTimestamp())); + mqtt.publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0); + mqtt.publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0); + mqtt.publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0); + mqtt.publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0); return true; } bool RawMqttHandler::publishList4(AmsData* data, AmsData* meterState) { if(full || meterState->getL1ActiveImportPower() != data->getL1ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l1", String(data->getL1ActiveImportPower(), 2)); + mqtt.publish(topic + "/meter/import/l1", String(data->getL1ActiveImportPower(), 2)); } if(full || meterState->getL2ActiveImportPower() != data->getL2ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l2", String(data->getL2ActiveImportPower(), 2)); + mqtt.publish(topic + "/meter/import/l2", String(data->getL2ActiveImportPower(), 2)); } if(full || meterState->getL3ActiveImportPower() != data->getL3ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l3", String(data->getL3ActiveImportPower(), 2)); + mqtt.publish(topic + "/meter/import/l3", String(data->getL3ActiveImportPower(), 2)); } if(full || meterState->getL1ActiveExportPower() != data->getL1ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l1", String(data->getL1ActiveExportPower(), 2)); + mqtt.publish(topic + "/meter/export/l1", String(data->getL1ActiveExportPower(), 2)); } if(full || meterState->getL2ActiveExportPower() != data->getL2ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l2", String(data->getL2ActiveExportPower(), 2)); + mqtt.publish(topic + "/meter/export/l2", String(data->getL2ActiveExportPower(), 2)); } if(full || meterState->getL3ActiveExportPower() != data->getL3ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l3", String(data->getL3ActiveExportPower(), 2)); + mqtt.publish(topic + "/meter/export/l3", String(data->getL3ActiveExportPower(), 2)); } if(full || meterState->getPowerFactor() != data->getPowerFactor()) { - mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2)); + mqtt.publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2)); } if(full || meterState->getL1PowerFactor() != data->getL1PowerFactor()) { - mqtt->publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2)); + mqtt.publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2)); } if(full || meterState->getL2PowerFactor() != data->getL2PowerFactor()) { - mqtt->publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2)); + mqtt.publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2)); } if(full || meterState->getL3PowerFactor() != data->getL3PowerFactor()) { - mqtt->publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2)); + mqtt.publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2)); } return true; } bool RawMqttHandler::publishRealtime(EnergyAccounting* ea) { - mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3)); - mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2)); - mqtt->publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1)); + mqtt.publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3)); + mqtt.publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2)); + mqtt.publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1)); uint8_t peakCount = ea->getConfig()->hours; if(peakCount > 5) peakCount = 5; for(uint8_t i = 1; i <= peakCount; i++) { - mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0); + mqtt.publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0); } - mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0); - mqtt->publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0); - mqtt->publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3)); - mqtt->publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2)); - mqtt->publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1)); + mqtt.publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0); + mqtt.publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0); + mqtt.publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3)); + mqtt.publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2)); + mqtt.publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1)); return true; } @@ -144,7 +150,7 @@ bool RawMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) TempSensorData* data = hw->getTempSensorData(i); if(data != NULL && data->lastValidRead > -85) { if(data->changed || full) { - mqtt->publish(topic + "/temperature/" + toHex(data->address), String(data->lastValidRead, 2)); + mqtt.publish(topic + "/temperature/" + toHex(data->address), String(data->lastValidRead, 2)); data->changed = false; } } @@ -153,7 +159,7 @@ bool RawMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) } bool RawMqttHandler::publishPrices(EntsoeApi* eapi) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; if(eapi->getValueForHour(0) == ENTSOE_NO_VALUE) return false; @@ -236,58 +242,54 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) { for(int i = 0; i < 34; i++) { float val = values[i]; if(val == ENTSOE_NO_VALUE) { - mqtt->publish(topic + "/price/" + String(i), "", true, 0); + mqtt.publish(topic + "/price/" + String(i), "", true, 0); } else { - mqtt->publish(topic + "/price/" + String(i), String(val, 4), true, 0); + mqtt.publish(topic + "/price/" + String(i), String(val, 4), true, 0); } - mqtt->loop(); + mqtt.loop(); delay(10); } if(min != INT16_MAX) { - mqtt->publish(topic + "/price/min", String(min, 4), true, 0); + mqtt.publish(topic + "/price/min", String(min, 4), true, 0); } if(max != INT16_MIN) { - mqtt->publish(topic + "/price/max", String(max, 4), true, 0); + mqtt.publish(topic + "/price/max", String(max, 4), true, 0); } if(min1hrIdx != -1) { - mqtt->publish(topic + "/price/cheapest/1hr", String(ts1hr), true, 0); + mqtt.publish(topic + "/price/cheapest/1hr", String(ts1hr), true, 0); } if(min3hrIdx != -1) { - mqtt->publish(topic + "/price/cheapest/3hr", String(ts3hr), true, 0); + mqtt.publish(topic + "/price/cheapest/3hr", String(ts3hr), true, 0); } if(min6hrIdx != -1) { - mqtt->publish(topic + "/price/cheapest/6hr", String(ts6hr), true, 0); + mqtt.publish(topic + "/price/cheapest/6hr", String(ts6hr), true, 0); } return true; } bool RawMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { - if(topic.isEmpty() || !mqtt->connected()) + if(topic.isEmpty() || !mqtt.connected()) return false; - mqtt->publish(topic + "/id", WiFi.macAddress(), true, 0); - mqtt->publish(topic + "/uptime", String((uint32_t) (millis64()/1000))); + mqtt.publish(topic + "/id", WiFi.macAddress(), true, 0); + mqtt.publish(topic + "/uptime", String((uint32_t) (millis64()/1000))); float vcc = hw->getVcc(); if(vcc > 0) { - mqtt->publish(topic + "/vcc", String(vcc, 2)); + mqtt.publish(topic + "/vcc", String(vcc, 2)); } - mqtt->publish(topic + "/mem", String(ESP.getFreeHeap())); - mqtt->publish(topic + "/rssi", String(hw->getWifiRssi())); + mqtt.publish(topic + "/mem", String(ESP.getFreeHeap())); + mqtt.publish(topic + "/rssi", String(hw->getWifiRssi())); if(hw->getTemperature() > -85) { - mqtt->publish(topic + "/temperature", String(hw->getTemperature(), 2)); + mqtt.publish(topic + "/temperature", String(hw->getTemperature(), 2)); } return true; } -bool RawMqttHandler::loop() { - bool ret = mqtt->loop(); - delay(10); - yield(); - #if defined(ESP32) - esp_task_wdt_reset(); - #elif defined(ESP8266) - ESP.wdtFeed(); - #endif - return ret; +uint8_t RawMqttHandler::getFormat() { + return full ? 3 : 2; +} + +bool RawMqttHandler::publishRaw(String data) { + return false; } diff --git a/lib/RealtimePlot/include/RealtimePlot.h b/lib/RealtimePlot/include/RealtimePlot.h new file mode 100644 index 00000000..fc73c426 --- /dev/null +++ b/lib/RealtimePlot/include/RealtimePlot.h @@ -0,0 +1,31 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _REALTIMEPLOT_H +#define _REALTIMEPLOT_H + +#include +#include "AmsData.h" + +#define REALTIME_SAMPLE 10000 +#define REALTIME_SIZE 360 + +class RealtimePlot { +public: + RealtimePlot(); + void update(AmsData& data); + int32_t getValue(uint16_t req); + int16_t getSize(); + +private: + int8_t* values; + uint8_t* scaling; + + unsigned long lastMillis = 0; + double lastReading = 0; + uint16_t lastPos = 0; +}; +#endif diff --git a/lib/RealtimePlot/src/RealtimePlot.cpp b/lib/RealtimePlot/src/RealtimePlot.cpp new file mode 100644 index 00000000..684d15fc --- /dev/null +++ b/lib/RealtimePlot/src/RealtimePlot.cpp @@ -0,0 +1,82 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "RealtimePlot.h" +#include + +RealtimePlot::RealtimePlot() { + values = (int8_t*) malloc(REALTIME_SIZE); + scaling = (uint8_t*) malloc(REALTIME_SIZE); + memset(values, 0, REALTIME_SIZE); + memset(scaling, 0, REALTIME_SIZE); +} + +void RealtimePlot::update(AmsData& data) { + unsigned long now = millis(); + uint16_t pos = (now / REALTIME_SAMPLE) % REALTIME_SIZE; + if(lastMillis == 0) { + lastMillis = now; + lastReading = data.getActiveImportCounter() - data.getActiveExportCounter(); + lastPos = pos; + return; + } + if(pos == lastPos && data.isCounterEstimated()) return; + + unsigned long ms = now - lastMillis; + int32_t val; // A bit hacky this one, but just to avoid spikes at end of hour. Will mostly be correct + if(data.isCounterEstimated()) { + val = ((data.getActiveImportCounter() - data.getActiveExportCounter() - lastReading) * 1000) / (((float) ms) / 3600000.0); + } else { + val = data.getActiveImportPower() - data.getActiveExportPower(); + } + uint8_t scale = 0; + int32_t update = val / pow(10, scale); + while(update > INT8_MAX || update < INT8_MIN) { + update = val / pow(10, ++scale); + } + if(pos < lastPos) { + for(uint16_t i = lastPos+1; i < REALTIME_SIZE; i++) { + values[i] = update; + scaling[i] = scale; + } + for(uint16_t i = 0; i <= pos; i++) { + values[i] = update; + scaling[i] = scale; + } + } else { + for(uint16_t i = lastPos+1; i <= pos; i++) { + values[i] = update; + scaling[i] = scale; + } + } + + lastMillis = now; + lastReading = data.getActiveImportCounter() - data.getActiveExportCounter(); + lastPos = pos; +} + +int32_t RealtimePlot::getValue(uint16_t req) { + if(req > REALTIME_SAMPLE) return 0; + + unsigned long now = millis(); + if(req * REALTIME_SAMPLE > now) return 0; + unsigned long reqTime = now - (req * REALTIME_SAMPLE); + + uint16_t pos = (now / REALTIME_SAMPLE) % REALTIME_SIZE; + uint16_t getPos; + if(reqTime > lastMillis) { + getPos = lastPos; + } else if(req > pos) { + getPos = REALTIME_SIZE + pos - req; + } else { + getPos = pos - req; + } + return values[getPos] * pow(10, scaling[getPos]); +} + +int16_t RealtimePlot::getSize() { + return REALTIME_SIZE; +} diff --git a/lib/SvelteUi/app/.gitignore b/lib/SvelteUi/app/.gitignore index 234f2f1b..23fe4cad 100644 --- a/lib/SvelteUi/app/.gitignore +++ b/lib/SvelteUi/app/.gitignore @@ -10,6 +10,8 @@ lerna-debug.log* node_modules *.local +vite.config.local.js + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/lib/SvelteUi/app/dist/index.css b/lib/SvelteUi/app/dist/index.css index 700c8d47..51dcb81c 100644 --- a/lib/SvelteUi/app/dist/index.css +++ b/lib/SvelteUi/app/dist/index.css @@ -1 +1 @@ -/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#6b7280;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:transparent}[type=checkbox]:indeterminate{background-color:currentColor;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:transparent}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.static{position:static}.fixed{position:fixed}.inset-0{top:0;right:0;bottom:0;left:0}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.float-right{float:right}.clear-both{clear:both}.m-1{margin:.25rem}.m-2{margin:.5rem}.m-3{margin:.75rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-auto{margin-bottom:auto;margin-top:auto}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-6{height:1.5rem}.h-64{height:16rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-4{width:1rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-96{width:24rem}.w-full{width:100%}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-violet-600{--tw-bg-opacity:1;background-color:rgb(124 58 237/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-500{--tw-bg-opacity:1;background-color:rgb(234 179 8/var(--tw-bg-opacity))}.bg-opacity-50{--tw-bg-opacity:.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.text-center{text-align:center}.text-right{text-align:right}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-semibold{font-weight:600}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-green-100{--tw-text-opacity:1;color:rgb(220 252 231/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity))}.text-red-100{--tw-text-opacity:1;color:rgb(254 226 226/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.gh-logo{height:2rem;width:2rem}.cnt{--tw-bg-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity));border-radius:.25rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);margin:.5rem;min-height:268px;padding:.5rem}.gwf{height:16rem}@media (min-width:640px){.gwf{grid-column:span 2/span 2}}@media (min-width:768px){.gwf{grid-column:span 3/span 3}}@media (min-width:1024px){.gwf{grid-column:span 4/span 4}}@media (min-width:1280px){.gwf{grid-column:span 5/span 5}}@media (min-width:1536px){.gwf{grid-column:span 6/span 6}}.in-pre{border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;border-width:1px 0 1px 1px}.in-post,.in-pre{--tw-border-opacity:1;--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity));display:flex;font-size:.875rem;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem;white-space:nowrap}.in-post{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem;border-width:1px 1px 1px 0}.in-post,.in-txt{border-color:rgb(209 213 219/var(--tw-border-opacity))}.in-txt{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-txt:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.in-f{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-f:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.in-m{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-color:rgb(209 213 219/var(--tw-border-opacity));border-left-width:0;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-m:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.in-l{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-bottom-right-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-left-width:0;border-top-right-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-l:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.in-s{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-color:rgb(209 213 219/var(--tw-border-opacity));border-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem;width:100%}.in-s:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.tr{text-align:right}.bd-green{background-color:rgb(34 197 94/var(--tw-bg-opacity));color:rgb(220 252 231/var(--tw-text-opacity))}.bd-green,.bd-yellow{--tw-bg-opacity:1;--tw-text-opacity:1;border-radius:.25rem;font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.bd-yellow{background-color:rgb(234 179 8/var(--tw-bg-opacity));color:rgb(254 249 195/var(--tw-text-opacity))}.bd-red{background-color:rgb(239 68 68/var(--tw-bg-opacity));color:rgb(254 226 226/var(--tw-text-opacity))}.bd-blue,.bd-red{--tw-bg-opacity:1;--tw-text-opacity:1;border-radius:.25rem;font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.bd-blue{background-color:rgb(59 130 246/var(--tw-bg-opacity));color:rgb(219 234 254/var(--tw-text-opacity))}.bd-gray{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity));border-radius:.25rem;color:rgb(243 244 246/var(--tw-text-opacity));font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.btn-pri{padding:.5rem 1rem}.btn-pri,.btn-pri-sm{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity));border-radius:.25rem;color:rgb(255 255 255/var(--tw-text-opacity));margin-right:.75rem}.btn-pri-sm{font-size:.75rem;line-height:1rem;padding:.25rem .5rem}.pl-root{position:relative}.pl-ov{left:25%;position:absolute;text-align:center;top:27%;width:50%}.pl-val{font-size:1.7rem}.pl-unt{color:gray;font-size:1rem}.pl-sub{font-size:1rem;padding-top:10px}.pl-snt{color:gray;font-size:.7rem}.pl-lab{font-size:1rem}.chart{height:100%;margin:0 auto;width:100%}svg{position:relative;width:100%}.tick{font-family:Helvetica,Arial;font-size:.85em;font-weight:200}.tick line{stroke:#e2e2e2;stroke-dasharray:2}.tick text{fill:#999;text-anchor:start}.tick.tick-0 line{stroke-dasharray:0}.tick.tick-green line{stroke:#32d900!important}.tick.tick-green text{fill:#32d900!important}.tick.tick-orange line{stroke:#d95600!important}.tick.tick-orange text{fill:#d95600!important}.x-axis .tick text{text-anchor:middle}.bars rect{stroke:#000;stroke-opacity:.25;opacity:.9}.bars text{display:block;font-family:Helvetica,Arial;font-size:.85em;text-align:center}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity))}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media (min-width:1536px){.\32xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}} +/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#6b7280;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:transparent}[type=checkbox]:indeterminate{background-color:currentColor;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:transparent}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.static{position:static}.fixed{position:fixed}.inset-0{top:0;right:0;bottom:0;left:0}.z-40{z-index:40}.z-50{z-index:50}.col-span-2{grid-column:span 2/span 2}.float-right{float:right}.clear-both{clear:both}.m-1{margin:.25rem}.m-2{margin:.5rem}.m-3{margin:.75rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-auto{margin-bottom:auto;margin-top:auto}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-4{height:1rem}.h-6{height:1.5rem}.h-64{height:16rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-4{width:1rem}.w-40{width:10rem}.w-6{width:1.5rem}.w-96{width:24rem}.w-full{width:100%}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-violet-600{--tw-bg-opacity:1;background-color:rgb(124 58 237/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-500{--tw-bg-opacity:1;background-color:rgb(234 179 8/var(--tw-bg-opacity))}.bg-opacity-50{--tw-bg-opacity:.5}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pl-5{padding-left:1.25rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.text-center{text-align:center}.text-right{text-align:right}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-semibold{font-weight:600}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-green-100{--tw-text-opacity:1;color:rgb(220 252 231/var(--tw-text-opacity))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity))}.text-red-100{--tw-text-opacity:1;color:rgb(254 226 226/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.gh-logo{height:2rem;width:2rem}.cnt{--tw-bg-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity));border-radius:.25rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);margin:.5rem;padding:.5rem}:is(.dark .cnt){--tw-bg-opacity:1;--tw-text-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);--tw-shadow-color:#111827;--tw-shadow:var(--tw-shadow-colored);--tw-drop-shadow:drop-shadow(0 4px 3px rgba(0,0,0,.07)) drop-shadow(0 2px 2px rgba(0,0,0,.06));background-color:rgb(31 41 55/var(--tw-bg-opacity));box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgb(255 255 255/var(--tw-text-opacity));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.cnt{min-height:268px}.gwf{height:16rem}@media (min-width:640px){.gwf{grid-column:span 2/span 2}}@media (min-width:768px){.gwf{grid-column:span 3/span 3}}@media (min-width:1024px){.gwf{grid-column:span 4/span 4}}@media (min-width:1280px){.gwf{grid-column:span 5/span 5}}@media (min-width:1536px){.gwf{grid-column:span 6/span 6}}.in-pre{--tw-border-opacity:1;--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity));border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;border-width:1px 0 1px 1px;display:flex;font-size:.875rem;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem;white-space:nowrap}:is(.dark .in-pre){--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity))}.in-post{--tw-border-opacity:1;--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity));border-bottom-right-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-right-radius:.375rem;border-width:1px 1px 1px 0;display:flex;font-size:.875rem;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem;white-space:nowrap}:is(.dark .in-post){--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity))}.in-txt{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-color:rgb(209 213 219/var(--tw-border-opacity));box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-txt:disabled{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));cursor:not-allowed}:is(.dark .in-txt){--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1));background-color:rgb(55 65 81/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity));border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgb(255 255 255/var(--tw-text-opacity));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}:is(.dark .in-txt:focus){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:is(.dark .in-txt:disabled){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.in-f{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-f:disabled{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity));cursor:not-allowed}:is(.dark .in-f){--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1));background-color:rgb(55 65 81/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity));border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgb(255 255 255/var(--tw-text-opacity));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}:is(.dark .in-f:focus){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:is(.dark .in-f:disabled){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.in-f:default{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.in-f:disabled{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}:is(.dark .in-f)::-moz-placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .in-f)::placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .in-f:default){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.in-m{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-color:rgb(209 213 219/var(--tw-border-opacity));border-left-width:0;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-m:disabled{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));cursor:not-allowed}:is(.dark .in-m){--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1));background-color:rgb(55 65 81/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity));border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgb(255 255 255/var(--tw-text-opacity));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}:is(.dark .in-m:focus){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:is(.dark .in-m:disabled){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.in-l{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-bottom-right-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-left-width:0;border-top-right-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem}.in-l:disabled{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));cursor:not-allowed}:is(.dark .in-l){--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1));background-color:rgb(55 65 81/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity));border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);color:rgb(255 255 255/var(--tw-text-opacity));filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}:is(.dark .in-l:focus){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:is(.dark .in-l:disabled){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}:is(.dark .in-l)::-moz-placeholder{--tw-placeholder-opacity:1;color:rgb(255 255 255/var(--tw-placeholder-opacity))}:is(.dark .in-l)::placeholder{--tw-placeholder-opacity:1;color:rgb(255 255 255/var(--tw-placeholder-opacity))}.in-s{--tw-border-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-color:rgb(209 213 219/var(--tw-border-opacity));border-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:2.5rem;width:100%}.in-s:disabled{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));cursor:not-allowed}:is(.dark .in-s){--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-drop-shadow:drop-shadow(0 10px 8px rgba(0,0,0,.04)) drop-shadow(0 4px 3px rgba(0,0,0,.1));background-color:rgb(55 65 81/var(--tw-bg-opacity));border-color:rgb(31 41 55/var(--tw-border-opacity));border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}:is(.dark .in-s:focus){--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}:is(.dark .in-s:disabled){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.in-s::-moz-placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.in-s::placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}:is(.dark .in-s){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.tr{text-align:right}.bd-green{background-color:rgb(34 197 94/var(--tw-bg-opacity));color:rgb(220 252 231/var(--tw-text-opacity))}.bd-green,.bd-yellow{--tw-bg-opacity:1;--tw-text-opacity:1;border-radius:.25rem;font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.bd-yellow{background-color:rgb(234 179 8/var(--tw-bg-opacity));color:rgb(254 249 195/var(--tw-text-opacity))}.bd-red{background-color:rgb(239 68 68/var(--tw-bg-opacity));color:rgb(254 226 226/var(--tw-text-opacity))}.bd-blue,.bd-red{--tw-bg-opacity:1;--tw-text-opacity:1;border-radius:.25rem;font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.bd-blue{background-color:rgb(59 130 246/var(--tw-bg-opacity));color:rgb(219 234 254/var(--tw-text-opacity))}.bd-gray{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity));border-radius:.25rem;color:rgb(243 244 246/var(--tw-text-opacity));font-size:.75rem;font-weight:600;line-height:1rem;margin-bottom:auto;margin-right:.5rem;margin-top:auto;padding:.125rem .625rem}.btn-pri{padding:.5rem 1rem}.btn-pri,.btn-pri-sm{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity));border-radius:.25rem;color:rgb(255 255 255/var(--tw-text-opacity));margin-right:.75rem}.btn-pri-sm{font-size:.75rem;line-height:1rem;padding:.25rem .5rem}.pl-root{position:relative}.pl-ov{left:25%;position:absolute;text-align:center;top:27%;width:50%}.pl-val{font-size:1.7rem}.pl-unt{color:gray;font-size:1rem}:is(.dark .pl-unt){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.pl-sub{font-size:1rem;padding-top:10px}.pl-snt{color:gray;font-size:.7rem}:is(.dark .pl-snt){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}.pl-lab{font-size:1rem}.chart{height:100%;margin:0 auto;width:100%}svg{position:relative;width:100%}.tick{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity));font-family:Helvetica,Arial;font-size:.85em;font-weight:200}:is(.dark .tick){fill:#fff}.tick line{stroke:#e2e2e2;stroke-dasharray:2}.tick text{fill:#999;text-anchor:start}:is(.dark .tick text){fill:#fff}.tick.tick-0 line{stroke-dasharray:0}.tick.tick-green line{stroke:#32d900!important}.tick.tick-green text{fill:#32d900!important}.tick.tick-orange line{stroke:#d95600!important}.tick.tick-orange text{fill:#d95600!important}.x-axis .tick text{text-anchor:middle}.bars rect{stroke:#000;stroke-opacity:.25;opacity:.9}.bars text{display:block;font-family:Helvetica,Arial;font-size:.85em;text-align:center}.hover\:text-blue-800:hover{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity))}:is(.dark .dark\:bg-gray-600){--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media (min-width:1536px){.\32xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}} diff --git a/lib/SvelteUi/app/dist/index.html b/lib/SvelteUi/app/dist/index.html index 6a9fa71d..cb031439 100644 --- a/lib/SvelteUi/app/dist/index.html +++ b/lib/SvelteUi/app/dist/index.html @@ -9,7 +9,7 @@ - +
diff --git a/lib/SvelteUi/app/dist/index.js b/lib/SvelteUi/app/dist/index.js index 78948083..d412c847 100644 --- a/lib/SvelteUi/app/dist/index.js +++ b/lib/SvelteUi/app/dist/index.js @@ -1,14 +1,22 @@ -(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const r of o.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&n(r)}).observe(document,{childList:!0,subtree:!0});function l(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(i){if(i.ep)return;i.ep=!0;const o=l(i);fetch(i.href,o)}})();function ne(){}function xt(t,e){for(const l in e)t[l]=e[l];return t}function ec(t){return t()}function Or(){return Object.create(null)}function Be(t){t.forEach(ec)}function co(t){return typeof t=="function"}function we(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}let vs;function Xc(t,e){return vs||(vs=document.createElement("a")),vs.href=e,t===vs.href}function Zc(t){return Object.keys(t).length===0}function mo(t,...e){if(t==null)return ne;const l=t.subscribe(...e);return l.unsubscribe?()=>l.unsubscribe():l}function ri(t){let e;return mo(t,l=>e=l)(),e}function al(t,e,l){t.$$.on_destroy.push(mo(e,l))}function po(t,e,l,n){if(t){const i=tc(t,e,l,n);return t[0](i)}}function tc(t,e,l,n){return t[1]&&n?xt(l.ctx.slice(),t[1](n(e))):l.ctx}function _o(t,e,l,n){if(t[2]&&n){const i=t[2](n(l));if(e.dirty===void 0)return i;if(typeof i=="object"){const o=[],r=Math.max(e.dirty.length,i.length);for(let a=0;a32){const e=[],l=t.ctx.length/32;for(let n=0;nt.removeEventListener(e,l,n)}function Ms(t){return function(e){return e.preventDefault(),t.call(this,e)}}function u(t,e,l){l==null?t.removeAttribute(e):t.getAttribute(e)!==l&&t.setAttribute(e,l)}const xc=["width","height"];function ai(t,e){const l=Object.getOwnPropertyDescriptors(t.__proto__);for(const n in e)e[n]==null?t.removeAttribute(n):n==="style"?t.style.cssText=e[n]:n==="__value"?t.value=t[n]=e[n]:l[n]&&l[n].set&&xc.indexOf(n)===-1?t[n]=e[n]:u(t,n,e[n])}function fe(t){return t===""?null:+t}function e1(t){return Array.from(t.childNodes)}function W(t,e){e=""+e,t.data!==e&&(t.data=e)}function t1(t,e){e=""+e,t.wholeText!==e&&(t.data=e)}function l1(t,e,l){~Jc.indexOf(l)?t1(t,e):W(t,e)}function V(t,e){t.value=e??""}function lc(t,e,l,n){l==null?t.style.removeProperty(e):t.style.setProperty(e,l,n?"important":"")}function qe(t,e,l){for(let n=0;n{r.source===n.contentWindow&&e()})):(n.src="about:blank",n.onload=()=>{o=K(n.contentWindow,"resize",e),e()}),s(t,n),()=>{(i||o&&n.contentWindow)&&o(),k(n)}}function s1(t,e,{bubbles:l=!1,cancelable:n=!1}={}){const i=document.createEvent("CustomEvent");return i.initCustomEvent(t,l,n,e),i}function qr(t,e){return new t(e)}let Si;function Ci(t){Si=t}function Mi(){if(!Si)throw new Error("Function called outside component initialization");return Si}function o1(t){Mi().$$.on_mount.push(t)}function u1(t){Mi().$$.on_destroy.push(t)}function r1(){const t=Mi();return(e,l,{cancelable:n=!1}={})=>{const i=t.$$.callbacks[e];if(i){const o=s1(e,l,{cancelable:n});return i.slice().forEach(r=>{r.call(t,o)}),!o.defaultPrevented}return!0}}function Ti(t,e){return Mi().$$.context.set(t,e),e}function Ul(t){return Mi().$$.context.get(t)}const ii=[],$s=[];let si=[];const Ur=[],nc=Promise.resolve();let xs=!1;function ic(){xs||(xs=!0,nc.then(sc))}function a1(){return ic(),nc}function tt(t){si.push(t)}const Ks=new Set;let li=0;function sc(){if(li!==0)return;const t=Si;do{try{for(;lit.indexOf(n)===-1?e.push(n):l.push(n)),l.forEach(n=>n()),si=e}const ks=new Set;let un;function Ae(){un={r:0,c:[],p:un}}function Ee(){un.r||Be(un.c),un=un.p}function P(t,e){t&&t.i&&(ks.delete(t),t.i(e))}function I(t,e,l,n){if(t&&t.o){if(ks.has(t))return;ks.add(t),un.c.push(()=>{ks.delete(t),n&&(l&&t.d(1),n())}),t.o(e)}else n&&n()}function oc(t,e){const l={},n={},i={$$scope:1};let o=t.length;for(;o--;){const r=t[o],a=e[o];if(a){for(const c in r)c in a||(n[c]=1);for(const c in a)i[c]||(l[c]=a[c],i[c]=1);t[o]=a}else for(const c in r)i[c]=1}for(const r in n)r in l||(l[r]=void 0);return l}function Hr(t){return typeof t=="object"&&t!==null?t:{}}function Z(t){t&&t.c()}function Q(t,e,l,n){const{fragment:i,after_update:o}=t.$$;i&&i.m(e,l),n||tt(()=>{const r=t.$$.on_mount.map(ec).filter(co);t.$$.on_destroy?t.$$.on_destroy.push(...r):Be(r),t.$$.on_mount=[]}),o.forEach(tt)}function X(t,e){const l=t.$$;l.fragment!==null&&(c1(l.after_update),Be(l.on_destroy),l.fragment&&l.fragment.d(e),l.on_destroy=l.fragment=null,l.ctx=[])}function m1(t,e){t.$$.dirty[0]===-1&&(ii.push(t),ic(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{const v=d.length?d[0]:b;return f.ctx&&i(f.ctx[_],f.ctx[_]=v)&&(!f.skip_bound&&f.bound[_]&&f.bound[_](v),p&&m1(t,_)),b}):[],f.update(),p=!0,Be(f.before_update),f.fragment=n?n(f.ctx):!1,e.target){if(e.hydrate){const _=e1(e.target);f.fragment&&f.fragment.l(_),_.forEach(k)}else f.fragment&&f.fragment.c();e.intro&&P(t.$$.fragment),Q(t,e.target,e.anchor,e.customElement),sc()}Ci(c)}class Me{$destroy(){X(this,1),this.$destroy=ne}$on(e,l){if(!co(l))return ne;const n=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return n.push(l),()=>{const i=n.indexOf(l);i!==-1&&n.splice(i,1)}}$set(e){this.$$set&&!Zc(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}}const jr=t=>typeof t>"u",uc=t=>typeof t=="function",rc=t=>typeof t=="number";function p1(t){return!t.defaultPrevented&&t.button===0&&!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function ac(){let t=0;return()=>t++}function _1(){return Math.random().toString(36).substring(2)}const Hl=typeof window>"u";function fc(t,e,l){return t.addEventListener(e,l),()=>t.removeEventListener(e,l)}const cc=(t,e)=>t?{}:{style:e},eo=t=>({"aria-hidden":"true",...cc(t,"display:none;")}),ni=[];function mc(t,e){return{subscribe:rt(t,e).subscribe}}function rt(t,e=ne){let l;const n=new Set;function i(a){if(we(t,a)&&(t=a,l)){const c=!ni.length;for(const f of n)f[1](),ni.push(f,t);if(c){for(let f=0;f{n.delete(f),n.size===0&&l&&(l(),l=null)}}return{set:i,update:o,subscribe:r}}function d1(t,e,l){const n=!Array.isArray(t),i=n?[t]:t,o=e.length<2;return mc(l,r=>{let a=!1;const c=[];let f=0,p=ne;const _=()=>{if(f)return;p();const d=e(n?c[0]:c,r);o?r(d):p=co(d)?d:ne},b=i.map((d,v)=>mo(d,g=>{c[v]=g,f&=~(1<{f|=1<`@@svnav-ctx__${t}`,to=Pi("LOCATION"),fi=Pi("ROUTER"),pc=Pi("ROUTE"),v1=Pi("ROUTE_PARAMS"),h1=Pi("FOCUS_ELEM"),_c=/^:(.+)/,wi=(t,e,l)=>t.substr(e,l),lo=(t,e)=>wi(t,0,e.length)===e,b1=t=>t==="",g1=t=>_c.test(t),dc=t=>t[0]==="*",k1=t=>t.replace(/\*.*$/,""),vc=t=>t.replace(/(^\/+|\/+$)/g,"");function ml(t,e=!1){const l=vc(t).split("/");return e?l.filter(Boolean):l}const Vs=(t,e)=>t+(e?`?${e}`:""),bo=t=>`/${vc(t)}`;function Ni(...t){const e=n=>ml(n,!0).join("/"),l=t.map(e).join("/");return bo(l)}const go=1,Ps=2,mn=3,w1=4,hc=5,y1=6,bc=7,$1=8,C1=9,gc=10,kc=11,T1={[go]:"Link",[Ps]:"Route",[mn]:"Router",[w1]:"useFocus",[hc]:"useLocation",[y1]:"useMatch",[bc]:"useNavigate",[$1]:"useParams",[C1]:"useResolvable",[gc]:"useResolve",[kc]:"navigate"},ko=t=>T1[t];function S1(t,e){let l;return t===Ps?l=e.path?`path="${e.path}"`:"default":t===go?l=`to="${e.to}"`:t===mn&&(l=`basepath="${e.basepath||""}"`),`<${ko(t)} ${l||""} />`}function M1(t,e,l,n){const i=l&&S1(n||t,l),o=i?` +(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const u of o.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&n(u)}).observe(document,{childList:!0,subtree:!0});function l(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(i){if(i.ep)return;i.ep=!0;const o=l(i);fetch(i.href,o)}})();function _e(){}function sl(t,e){for(const l in e)t[l]=e[l];return t}function tc(t){return t()}function wa(){return Object.create(null)}function Ge(t){t.forEach(tc)}function co(t){return typeof t=="function"}function $e(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}let ps;function Xs(t,e){return ps||(ps=document.createElement("a")),ps.href=e,t===ps.href}function t0(t){return Object.keys(t).length===0}function mo(t,...e){if(t==null)return _e;const l=t.subscribe(...e);return l.unsubscribe?()=>l.unsubscribe():l}function ri(t){let e;return mo(t,l=>e=l)(),e}function _l(t,e,l){t.$$.on_destroy.push(mo(e,l))}function po(t,e,l,n){if(t){const i=lc(t,e,l,n);return t[0](i)}}function lc(t,e,l,n){return t[1]&&n?sl(l.ctx.slice(),t[1](n(e))):l.ctx}function _o(t,e,l,n){if(t[2]&&n){const i=t[2](n(l));if(e.dirty===void 0)return i;if(typeof i=="object"){const o=[],u=Math.max(e.dirty.length,i.length);for(let a=0;a32){const e=[],l=t.ctx.length/32;for(let n=0;nt.removeEventListener(e,l,n)}function Ms(t){return function(e){return e.preventDefault(),t.call(this,e)}}function r(t,e,l){l==null?t.removeAttribute(e):t.getAttribute(e)!==l&&t.setAttribute(e,l)}const n0=["width","height"];function ai(t,e){const l=Object.getOwnPropertyDescriptors(t.__proto__);for(const n in e)e[n]==null?t.removeAttribute(n):n==="style"?t.style.cssText=e[n]:n==="__value"?t.value=t[n]=e[n]:l[n]&&l[n].set&&n0.indexOf(n)===-1?t[n]=e[n]:r(t,n,e[n])}function he(t){return t===""?null:+t}function i0(t){return Array.from(t.childNodes)}function X(t,e){e=""+e,t.data!==e&&(t.data=e)}function s0(t,e){e=""+e,t.wholeText!==e&&(t.data=e)}function o0(t,e,l){~l0.indexOf(l)?s0(t,e):X(t,e)}function ne(t,e){t.value=e??""}function nc(t,e,l,n){l==null?t.style.removeProperty(e):t.style.setProperty(e,l,n?"important":"")}function Se(t,e,l){for(let n=0;n{u.source===n.contentWindow&&e()})):(n.src="about:blank",n.onload=()=>{o=le(n.contentWindow,"resize",e),e()}),s(t,n),()=>{(i||o&&n.contentWindow)&&o(),w(n)}}function a0(t,e,{bubbles:l=!1,cancelable:n=!1}={}){const i=document.createEvent("CustomEvent");return i.initCustomEvent(t,l,n,e),i}function ya(t,e){return new t(e)}let Si;function Ci(t){Si=t}function Ti(){if(!Si)throw new Error("Function called outside component initialization");return Si}function sc(t){Ti().$$.on_mount.push(t)}function u0(t){Ti().$$.on_destroy.push(t)}function f0(){const t=Ti();return(e,l,{cancelable:n=!1}={})=>{const i=t.$$.callbacks[e];if(i){const o=a0(e,l,{cancelable:n});return i.slice().forEach(u=>{u.call(t,o)}),!o.defaultPrevented}return!0}}function Mi(t,e){return Ti().$$.context.set(t,e),e}function Hl(t){return Ti().$$.context.get(t)}const ni=[],ks=[];let ii=[];const Ca=[],oc=Promise.resolve();let Zs=!1;function rc(){Zs||(Zs=!0,oc.then(ac))}function c0(){return rc(),oc}function Ke(t){ii.push(t)}const zs=new Set;let ti=0;function ac(){if(ti!==0)return;const t=Si;do{try{for(;tit.indexOf(n)===-1?e.push(n):l.push(n)),l.forEach(n=>n()),ii=e}const hs=new Set;let rn;function Ie(){rn={r:0,c:[],p:rn}}function Oe(){rn.r||Ge(rn.c),rn=rn.p}function O(t,e){t&&t.i&&(hs.delete(t),t.i(e))}function B(t,e,l,n){if(t&&t.o){if(hs.has(t))return;hs.add(t),rn.c.push(()=>{hs.delete(t),n&&(l&&t.d(1),n())}),t.o(e)}else n&&n()}function uc(t,e){const l={},n={},i={$$scope:1};let o=t.length;for(;o--;){const u=t[o],a=e[o];if(a){for(const c in u)c in a||(n[c]=1);for(const c in a)i[c]||(l[c]=a[c],i[c]=1);t[o]=a}else for(const c in u)i[c]=1}for(const u in n)u in l||(l[u]=void 0);return l}function Ma(t){return typeof t=="object"&&t!==null?t:{}}function re(t){t&&t.c()}function se(t,e,l,n){const{fragment:i,after_update:o}=t.$$;i&&i.m(e,l),n||Ke(()=>{const u=t.$$.on_mount.map(tc).filter(co);t.$$.on_destroy?t.$$.on_destroy.push(...u):Ge(u),t.$$.on_mount=[]}),o.forEach(Ke)}function oe(t,e){const l=t.$$;l.fragment!==null&&(p0(l.after_update),Ge(l.on_destroy),l.fragment&&l.fragment.d(e),l.on_destroy=l.fragment=null,l.ctx=[])}function _0(t,e){t.$$.dirty[0]===-1&&(ni.push(t),rc(),t.$$.dirty.fill(0)),t.$$.dirty[e/31|0]|=1<{const v=d.length?d[0]:h;return f.ctx&&i(f.ctx[_],f.ctx[_]=v)&&(!f.skip_bound&&f.bound[_]&&f.bound[_](v),p&&_0(t,_)),h}):[],f.update(),p=!0,Ge(f.before_update),f.fragment=n?n(f.ctx):!1,e.target){if(e.hydrate){const _=i0(e.target);f.fragment&&f.fragment.l(_),_.forEach(w)}else f.fragment&&f.fragment.c();e.intro&&O(t.$$.fragment),se(t,e.target,e.anchor,e.customElement),ac()}Ci(c)}class De{$destroy(){oe(this,1),this.$destroy=_e}$on(e,l){if(!co(l))return _e;const n=this.$$.callbacks[e]||(this.$$.callbacks[e]=[]);return n.push(l),()=>{const i=n.indexOf(l);i!==-1&&n.splice(i,1)}}$set(e){this.$$set&&!t0(e)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}}const Sa=t=>typeof t>"u",fc=t=>typeof t=="function",cc=t=>typeof t=="number";function d0(t){return!t.defaultPrevented&&t.button===0&&!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function mc(){let t=0;return()=>t++}function v0(){return Math.random().toString(36).substring(2)}const Wl=typeof window>"u";function pc(t,e,l){return t.addEventListener(e,l),()=>t.removeEventListener(e,l)}const _c=(t,e)=>t?{}:{style:e},Js=t=>({"aria-hidden":"true",..._c(t,"display:none;")}),li=[];function dc(t,e){return{subscribe:it(t,e).subscribe}}function it(t,e=_e){let l;const n=new Set;function i(a){if($e(t,a)&&(t=a,l)){const c=!li.length;for(const f of n)f[1](),li.push(f,t);if(c){for(let f=0;f{n.delete(f),n.size===0&&l&&(l(),l=null)}}return{set:i,update:o,subscribe:u}}function h0(t,e,l){const n=!Array.isArray(t),i=n?[t]:t,o=e.length<2;return dc(l,u=>{let a=!1;const c=[];let f=0,p=_e;const _=()=>{if(f)return;p();const d=e(n?c[0]:c,u);o?u(d):p=co(d)?d:_e},h=i.map((d,v)=>mo(d,g=>{c[v]=g,f&=~(1<{f|=1<`@@svnav-ctx__${t}`,xs=$i("LOCATION"),ui=$i("ROUTER"),vc=$i("ROUTE"),b0=$i("ROUTE_PARAMS"),g0=$i("FOCUS_ELEM"),hc=/^:(.+)/,ki=(t,e,l)=>t.substr(e,l),eo=(t,e)=>ki(t,0,e.length)===e,k0=t=>t==="",w0=t=>hc.test(t),bc=t=>t[0]==="*",y0=t=>t.replace(/\*.*$/,""),gc=t=>t.replace(/(^\/+|\/+$)/g,"");function vl(t,e=!1){const l=gc(t).split("/");return e?l.filter(Boolean):l}const Gs=(t,e)=>t+(e?`?${e}`:""),bo=t=>`/${gc(t)}`;function Ni(...t){const e=n=>vl(n,!0).join("/"),l=t.map(e).join("/");return bo(l)}const go=1,Ss=2,mn=3,C0=4,kc=5,M0=6,wc=7,S0=8,T0=9,yc=10,Cc=11,$0={[go]:"Link",[Ss]:"Route",[mn]:"Router",[C0]:"useFocus",[kc]:"useLocation",[M0]:"useMatch",[wc]:"useNavigate",[S0]:"useParams",[T0]:"useResolvable",[yc]:"useResolve",[Cc]:"navigate"},ko=t=>$0[t];function N0(t,e){let l;return t===Ss?l=e.path?`path="${e.path}"`:"default":t===go?l=`to="${e.to}"`:t===mn&&(l=`basepath="${e.basepath||""}"`),`<${ko(t)} ${l||""} />`}function A0(t,e,l,n){const i=l&&N0(n||t,l),o=i?` -Occurred in: ${i}`:"",r=ko(t),a=uc(e)?e(r):e;return`<${r}> ${a}${o}`}const wc=t=>(...e)=>t(M1(...e)),yc=wc(t=>{throw new Error(t)}),Cs=wc(console.warn),Wr=4,P1=3,N1=2,D1=1,A1=1;function E1(t,e){const l=t.default?0:ml(t.fullPath).reduce((n,i)=>{let o=n;return o+=Wr,b1(i)?o+=A1:g1(i)?o+=N1:dc(i)?o-=Wr+D1:o+=P1,o},0);return{route:t,score:l,index:e}}function I1(t){return t.map(E1).sort((e,l)=>e.scorel.score?-1:e.index-l.index)}function $c(t,e){let l,n;const[i]=e.split("?"),o=ml(i),r=o[0]==="",a=I1(t);for(let c=0,f=a.length;c({...p,params:b,uri:C});if(p.default){n=d(e);continue}const v=ml(p.fullPath),g=Math.max(o.length,v.length);let T=0;for(;T{f===".."?c.pop():f!=="."&&c.push(f)}),Vs(`/${c.join("/")}`,n)}function Gr(t,e){const{pathname:l,hash:n="",search:i="",state:o}=t,r=ml(e,!0),a=ml(l,!0);for(;r.length;)r[0]!==a[0]&&yc(mn,`Invalid state: All locations must begin with the basepath "${e}", found "${l}"`),r.shift(),a.shift();return{pathname:Ni(...a),hash:n,search:i,state:o}}const Br=t=>t.length===1?"":t,wo=t=>{const e=t.indexOf("?"),l=t.indexOf("#"),n=e!==-1,i=l!==-1,o=i?Br(wi(t,l)):"",r=i?wi(t,0,l):t,a=n?Br(wi(r,e)):"";return{pathname:(n?wi(r,0,e):r)||"/",search:a,hash:o}},R1=t=>{const{pathname:e,search:l,hash:n}=t;return e+l+n};function L1(t,e,l){return Ni(l,F1(t,e))}function O1(t,e){const l=bo(k1(t)),n=ml(l,!0),i=ml(e,!0).slice(0,n.length),o=Cc({fullPath:l},Ni(...i));return o&&o.uri}const Qs="POP",q1="PUSH",U1="REPLACE";function Xs(t){return{...t.location,pathname:encodeURI(decodeURI(t.location.pathname)),state:t.history.state,_key:t.history.state&&t.history.state._key||"initial"}}function H1(t){let e=[],l=Xs(t),n=Qs;const i=(o=e)=>o.forEach(r=>r({location:l,action:n}));return{get location(){return l},listen(o){e.push(o);const r=()=>{l=Xs(t),n=Qs,i([o])};i([o]);const a=fc(t,"popstate",r);return()=>{a(),e=e.filter(c=>c!==o)}},navigate(o,r){const{state:a={},replace:c=!1}=r||{};if(n=c?U1:q1,rc(o))r&&Cs(kc,"Navigation options (state or replace) are not supported, when passing a number as the first argument to navigate. They are ignored."),n=Qs,t.history.go(o);else{const f={...a,_key:_1()};try{t.history[c?"replaceState":"pushState"](f,"",o)}catch{t.location[c?"replace":"assign"](o)}}l=Xs(t),i()}}}function Zs(t,e){return{...wo(e),state:t}}function j1(t="/"){let e=0,l=[Zs(null,t)];return{get entries(){return l},get location(){return l[e]},addEventListener(){},removeEventListener(){},history:{get state(){return l[e].state},pushState(n,i,o){e++,l=l.slice(0,e),l.push(Zs(n,o))},replaceState(n,i,o){l[e]=Zs(n,o)},go(n){const i=e+n;i<0||i>l.length-1||(e=i)}}}}const W1=!!(!Hl&&window.document&&window.document.createElement),G1=!Hl&&window.location.origin==="null",Tc=H1(W1&&!G1?window:j1()),{navigate:oi}=Tc;let Sl=null,Sc=!0;function B1(t,e){const l=document.querySelectorAll("[data-svnav-router]");for(let n=0;nSl.level||t.level===Sl.level&&B1(t.routerId,Sl.routerId))&&(Sl=t)}function Y1(){Sl=null}function K1(){Sc=!1}function zr(t){if(!t)return!1;const e="tabindex";try{if(!t.hasAttribute(e)){t.setAttribute(e,"-1");let l;l=fc(t,"blur",()=>{t.removeAttribute(e),l()})}return t.focus(),document.activeElement===t}catch{return!1}}function V1(t,e){return Number(t.dataset.svnavRouteEnd)===e}function Q1(t){return/^H[1-6]$/i.test(t.tagName)}function Yr(t,e=document){return e.querySelector(t)}function X1(t){let l=Yr(`[data-svnav-route-start="${t}"]`).nextElementSibling;for(;!V1(l,t);){if(Q1(l))return l;const n=Yr("h1,h2,h3,h4,h5,h6",l);if(n)return n;l=l.nextElementSibling}return null}function Z1(t){Promise.resolve(ri(t.focusElement)).then(e=>{const l=e||X1(t.id);l||Cs(mn,`Could not find an element to focus. You should always render a header for accessibility reasons, or set a custom focus element via the "useFocus" hook. If you don't want this Route or Router to manage focus, pass "primary={false}" to it.`,t,Ps),!zr(l)&&zr(document.documentElement)})}const J1=(t,e,l)=>(n,i)=>a1().then(()=>{if(!Sl||Sc){K1();return}if(n&&Z1(Sl.route),t.announcements&&i){const{path:o,fullPath:r,meta:a,params:c,uri:f}=Sl.route,p=t.createAnnouncement({path:o,fullPath:r,meta:a,params:c,uri:f},ri(l));Promise.resolve(p).then(_=>{e.set(_)})}Y1()}),x1="position:fixed;top:-1px;left:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;";function em(t){let e,l,n=[{role:"status"},{"aria-atomic":"true"},{"aria-live":"polite"},{"data-svnav-announcer":""},cc(t[6],x1)],i={};for(let o=0;o`Navigated to ${le.uri}`,announcements:!0,...v},C=p,$=bo(p),M=Ul(to),F=Ul(fi),S=!M,D=lm(),A=d&&!(F&&!F.manageFocus),E=rt("");al(t,E,le=>l(0,a=le));const Y=F?F.disableInlineStyles:g,R=rt([]);al(t,R,le=>l(20,r=le));const U=rt(null);al(t,U,le=>l(18,i=le));let H=!1;const z=S?0:F.level+1,L=S?rt((()=>Gr(Hl?wo(_):b.location,$))()):M;al(t,L,le=>l(17,n=le));const B=rt(n);al(t,B,le=>l(19,o=le));const O=J1(T,E,L),j=le=>pe=>pe.filter(ie=>ie.id!==le);function G(le){if(Hl){if(H)return;const pe=Cc(le,n.pathname);if(pe)return H=!0,pe}else R.update(pe=>{const ie=j(le.id)(pe);return ie.push(le),ie})}function te(le){R.update(j(le))}return!S&&p!==Kr&&Cs(mn,'Only top-level Routers can have a "basepath" prop. It is ignored.',{basepath:p}),S&&(o1(()=>b.listen(pe=>{const ie=Gr(pe.location,$);B.set(n),L.set(ie)})),Ti(to,L)),Ti(fi,{activeRoute:U,registerRoute:G,unregisterRoute:te,manageFocus:A,level:z,id:D,history:S?b:F.history,basepath:S?$:F.basepath,disableInlineStyles:Y}),t.$$set=le=>{"basepath"in le&&l(11,p=le.basepath),"url"in le&&l(12,_=le.url),"history"in le&&l(13,b=le.history),"primary"in le&&l(14,d=le.primary),"a11y"in le&&l(15,v=le.a11y),"disableInlineStyles"in le&&l(16,g=le.disableInlineStyles),"$$scope"in le&&l(21,f=le.$$scope)},t.$$.update=()=>{if(t.$$.dirty[0]&2048&&p!==C&&Cs(mn,'You cannot change the "basepath" prop. It is ignored.'),t.$$.dirty[0]&1179648){const le=$c(r,n.pathname);U.set(le)}if(t.$$.dirty[0]&655360&&S){const le=!!n.hash,pe=!le&&A,ie=!le||n.pathname!==o.pathname;O(pe,ie)}t.$$.dirty[0]&262144&&A&&i&&i.primary&&z1({level:z,routerId:D,route:i})},[a,T,S,D,A,E,Y,R,U,L,B,p,_,b,d,v,g,n,i,o,r,f,c]}class im extends Me{constructor(e){super(),Se(this,e,nm,tm,we,{basepath:11,url:12,history:13,primary:14,a11y:15,disableInlineStyles:16},null,[-1,-1])}}const Mc=im;function Di(t,e,l=fi,n=mn){Ul(l)||yc(t,o=>`You cannot use ${o} outside of a ${ko(n)}.`,e)}const sm=t=>{const{subscribe:e}=Ul(t);return{subscribe:e}};function Pc(){return Di(hc),sm(to)}function Nc(){const{history:t}=Ul(fi);return t}function Dc(){const t=Ul(pc);return t?d1(t,e=>e.base):rt("/")}function Ac(){Di(gc);const t=Dc(),{basepath:e}=Ul(fi);return n=>L1(n,ri(t),e)}function om(){Di(bc);const t=Ac(),{navigate:e}=Nc();return(n,i)=>{const o=rc(n)?n:t(n);return e(o,i)}}const um=t=>({params:t&16,location:t&8}),Vr=t=>({params:Hl?ri(t[10]):t[4],location:t[3],navigate:t[11]});function Qr(t){let e,l;return e=new Mc({props:{primary:t[1],$$slots:{default:[fm]},$$scope:{ctx:t}}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&2&&(o.primary=n[1]),i&528409&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function rm(t){let e;const l=t[18].default,n=po(l,t,t[19],Vr);return{c(){n&&n.c()},m(i,o){n&&n.m(i,o),e=!0},p(i,o){n&&n.p&&(!e||o&524312)&&vo(n,l,i,i[19],e?_o(l,i[19],o,um):ho(i[19]),Vr)},i(i){e||(P(n,i),e=!0)},o(i){I(n,i),e=!1},d(i){n&&n.d(i)}}}function am(t){let e,l,n;const i=[{location:t[3]},{navigate:t[11]},Hl?ri(t[10]):t[4],t[12]];var o=t[0];function r(a){let c={};for(let f=0;f{X(p,1)}),Ee()}o?(e=qr(o,r()),Z(e.$$.fragment),P(e.$$.fragment,1),Q(e,l.parentNode,l)):e=null}else o&&e.$set(f)},i(a){n||(e&&P(e.$$.fragment,a),n=!0)},o(a){e&&I(e.$$.fragment,a),n=!1},d(a){a&&k(l),e&&X(e,a)}}}function fm(t){let e,l,n,i;const o=[am,rm],r=[];function a(c,f){return c[0]!==null?0:1}return e=a(t),l=r[e]=o[e](t),{c(){l.c(),n=Ke()},m(c,f){r[e].m(c,f),w(c,n,f),i=!0},p(c,f){let p=e;e=a(c),e===p?r[e].p(c,f):(Ae(),I(r[p],1,1,()=>{r[p]=null}),Ee(),l=r[e],l?l.p(c,f):(l=r[e]=o[e](c),l.c()),P(l,1),l.m(n.parentNode,n))},i(c){i||(P(l),i=!0)},o(c){I(l),i=!1},d(c){r[e].d(c),c&&k(n)}}}function cm(t){let e,l,n,i,o,r=[eo(t[7]),{"data-svnav-route-start":t[5]}],a={};for(let _=0;_{c=null}),Ee())},i(_){o||(P(c),o=!0)},o(_){I(c),o=!1},d(_){_&&k(e),_&&k(l),c&&c.d(_),_&&k(n),_&&k(i)}}}const mm=ac();function pm(t,e,l){let n;const i=["path","component","meta","primary"];let o=ys(e,i),r,a,c,f,{$$slots:p={},$$scope:_}=e,{path:b=""}=e,{component:d=null}=e,{meta:v={}}=e,{primary:g=!0}=e;Di(Ps,e);const T=mm(),{registerRoute:C,unregisterRoute:$,activeRoute:M,disableInlineStyles:F}=Ul(fi);al(t,M,H=>l(16,r=H));const S=Dc();al(t,S,H=>l(17,c=H));const D=Pc();al(t,D,H=>l(3,a=H));const A=rt(null);let E;const Y=rt(),R=rt({});al(t,R,H=>l(4,f=H)),Ti(pc,Y),Ti(v1,R),Ti(h1,A);const U=om();return Hl||u1(()=>$(T)),t.$$set=H=>{l(24,e=xt(xt({},e),ws(H))),l(12,o=ys(e,i)),"path"in H&&l(13,b=H.path),"component"in H&&l(0,d=H.component),"meta"in H&&l(14,v=H.meta),"primary"in H&&l(1,g=H.primary),"$$scope"in H&&l(19,_=H.$$scope)},t.$$.update=()=>{if(t.$$.dirty&155658){const H=b==="",z=Ni(c,b),q={id:T,path:b,meta:v,default:H,fullPath:H?"":z,base:H?c:O1(z,a.pathname),primary:g,focusElement:A};Y.set(q),l(15,E=C(q))}if(t.$$.dirty&98304&&l(2,n=!!(E||r&&r.id===T)),t.$$.dirty&98308&&n){const{params:H}=E||r;R.set(H)}},e=ws(e),[d,g,n,a,f,T,M,F,S,D,R,U,o,b,v,E,r,c,p,_]}class _m extends Me{constructor(e){super(),Se(this,e,pm,cm,we,{path:13,component:0,meta:14,primary:1})}}const Tl=_m;function dm(t){let e,l,n,i;const o=t[13].default,r=po(o,t,t[12],null);let a=[{href:t[0]},t[2],t[1]],c={};for(let f=0;fl(11,_=A));const M=r1(),F=Ac(),{navigate:S}=Nc();function D(A){M("click",A),p1(A)&&(A.preventDefault(),S(n,{state:T,replace:r||g}))}return t.$$set=A=>{l(19,e=xt(xt({},e),ws(A))),l(18,p=ys(e,f)),"to"in A&&l(5,v=A.to),"replace"in A&&l(6,g=A.replace),"state"in A&&l(7,T=A.state),"getProps"in A&&l(8,C=A.getProps),"$$scope"in A&&l(12,d=A.$$scope)},t.$$.update=()=>{t.$$.dirty&2080&&l(0,n=F(v,_)),t.$$.dirty&2049&&l(10,i=lo(_.pathname,n)),t.$$.dirty&2049&&l(9,o=n===_.pathname),t.$$.dirty&2049&&(r=wo(n)===R1(_)),t.$$.dirty&512&&l(2,a=o?{"aria-current":"page"}:{}),l(1,c=(()=>{if(uc(C)){const A=C({location:_,href:n,isPartiallyCurrent:i,isCurrent:o});return{...p,...A}}return p})())},e=ws(e),[n,c,a,$,D,v,g,T,C,o,i,_,d,b]}class hm extends Me{constructor(e){super(),Se(this,e,vm,dm,we,{to:5,replace:6,state:7,getProps:8})}}const el=hm;let no=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function ql(t){return t===1?"green":t===2?"yellow":t===3?"red":"gray"}function bm(t){return t>218&&t<242?"#32d900":t>212&&t<248?"#b1d900":t>208&&t<252?"#ffb800":"#d90000"}function Ec(t){return t>90?"#d90000":t>85?"#e32100":t>80?"#ffb800":t>75?"#dcd800":"#32d900"}function gm(t){return t>75?"#32d900":t>50?"#77d900":t>25?"#94d900":"#dcd800"}function Ts(t){switch(t){case 1:return"Aidon";case 2:return"Kaifa";case 3:return"Kamstrup";case 8:return"Iskra";case 9:return"Landis+Gyr";case 10:return"Sagemcom";default:return""}}function Ie(t){for(t=t.toString();t.length<2;)t="0"+t;return t}function ce(t,e){switch(e){case 5:switch(t){case"esp8266":return"Pow-K (GPIO12)";case"esp32s2":return"Pow-K+"}case 7:switch(t){case"esp8266":return"Pow-U (GPIO12)";case"esp32s2":return"Pow-U+"}case 6:return"Pow-P1";case 51:return"Wemos S2 mini";case 50:return"Generic ESP32-S2";case 201:return"Wemos LOLIN D32";case 202:return"Adafruit HUZZAH32";case 203:return"DevKitC";case 200:return"Generic ESP32";case 2:return"HAN Reader 2.0 by Max Spencer";case 0:return"Custom hardware by Roar Fredriksen";case 1:return"Kamstrup module by Egil Opsahl";case 8:return"µHAN mosquito by dbeinder";case 3:return"Pow-K (UART0)";case 4:return"Pow-U (UART0)";case 101:return"Wemos D1 mini";case 100:return"Generic ESP8266";case 70:return"Generic ESP32-C3";case 71:return"ESP32-C3-DevKitM-1"}}function Xr(t){switch(t){case-1:return"Parse error";case-2:return"Incomplete data received";case-3:return"Payload boundry flag missing";case-4:return"Header checksum error";case-5:return"Footer checksum error";case-9:return"Unknown data received, check meter config";case-41:return"Frame length not equal";case-51:return"Authentication failed";case-52:return"Decryption failed";case-53:return"Encryption key invalid";case 90:return"No HAN data received for at least 30s";case 91:return"Serial break";case 92:return"Serial buffer full";case 93:return"Serial FIFO overflow";case 94:return"Serial frame error";case 95:return"Serial parity error";case 96:return"RX error";case 98:return"Exception in code, debugging necessary";case 99:return"Autodetection failed"}return t<0?"Unspecified error "+t:""}function Zr(t){switch(t){case-3:return"Connection failed";case-4:return"Network timeout";case-10:return"Connection denied";case-11:return"Failed to subscribe";case-13:return"Connection lost"}return t<0?"Unspecified error "+t:""}function Jr(t){switch(t){case 400:return"Unrecognized data in request";case 401:case 403:return"Unauthorized, check API key";case 404:return"Price unavailable, not found";case 425:return"Server says its too early";case 429:return"Exceeded API rate limit";case 500:return"Internal server error";case-1:return"Connection error";case-2:return"Incomplete data received";case-3:return"Invalid data, tag missing";case-51:return"Authentication failed";case-52:return"Decryption failed";case-53:return"Encryption key invalid"}return t<0?"Unspecified error "+t:""}function ui(t){switch(t){case 2:case 4:case 7:return!0}return!1}function Ye(t,e){return t==1||t==2&&e}function Ut(t){return"https://github.com/UtilitechAS/amsreader-firmware/wiki/"+t}function me(t,e){return isNaN(t)?"-":(isNaN(e)&&(e=t<10?1:0),t.toFixed(e))}function fl(t,e){return t.setTime(t.getTime()+e*36e5),t}function xr(t){if(t.chip=="esp8266")switch(t.boot_reason){case 0:return"Normal";case 1:return"WDT reset";case 2:return"Exception reset";case 3:return"Soft WDT reset";case 4:return"Software restart";case 5:return"Deep sleep";case 6:return"External reset";default:return"Unknown (8266)"}else switch(t.boot_reason){case 1:return"Vbat power on reset";case 3:return"Software reset";case 4:return"WDT reset";case 5:return"Deep sleep";case 6:return"SLC reset";case 7:return"Timer Group0 WDT reset";case 8:return"Timer Group1 WDT reset";case 9:return"RTC WDT reset";case 10:return"Instrusion test reset CPU";case 11:return"Time Group reset CPU";case 12:return"Software reset CPU";case 13:return"RTC WTD reset CPU";case 14:return"PRO CPU";case 15:return"Brownout";case 16:return"RTC reset";default:return"Unknown"}}function ea(t){return t=="EOE"?"ENTSO-E":t=="HKS"?"hvakosterstrommen.no":t=="EDS"?"Energy Data Service":t=="MIX"?"Mixed sources":"Unknown ("+t+")"}async function jl(t,e={}){const{timeout:l=8e3}=e,n=new AbortController,i=setTimeout(()=>n.abort(),l),o=await fetch(t,{...e,signal:n.signal});return clearTimeout(i),o}let rl={version:"",chip:"",mac:null,apmac:null,vndcfg:null,usrcfg:null,fwconsent:null,booting:!1,upgrading:!1,ui:{},security:0,boot_reason:0,upgrade:{x:-1,e:0,f:null,t:null},trying:null};const Ht=rt(rl);async function yo(){rl=await(await jl("/sysinfo.json?t="+Math.floor(Date.now()/1e3))).json(),Ht.set(rl)}let bs=0,ta=-127,la=null,km={};const wm=mc(km,t=>{let e;async function l(){jl("/data.json").then(n=>n.json()).then(n=>{t(n),ta!=n.t&&(ta=n.t,setTimeout(Oc,2e3)),la==null&&n.pe&&n.p!=null&&(la=n.p,Fc()),rl.upgrading?window.location.reload():(!rl||!rl.chip||rl.booting||bs>1&&!ui(rl.board))&&(yo(),rn&&clearTimeout(rn),rn=setTimeout(Co,2e3),an&&clearTimeout(an),an=setTimeout(To,3e3));let i=5e3;if(ui(rl.board)&&n.v>2.5){let o=3.3-Math.min(3.3,n.v);o>0&&(i=Math.max(o,.1)*10*5e3)}i>5e3&&console.log("Scheduling next data fetch in "+i+"ms"),e&&clearTimeout(e),e=setTimeout(l,i),bs=0}).catch(n=>{bs++,bs>3?(t({em:3,hm:0,wm:0,mm:0}),e=setTimeout(l,15e3)):e=setTimeout(l,ui(rl.board)?1e4:5e3)})}return l(),function(){clearTimeout(e)}});let io={},yi;const $o=rt(io);async function Ic(){let t=!1;$o.update(e=>{for(var l=0;l<36;l++){if(e[Ie(l)]==null){t=l<12;break}e[Ie(l)]=e[Ie(l+1)]}return e}),t?Fc():yi=setTimeout(Ic,(60-new Date().getMinutes())*6e4)}async function Fc(){yi&&(clearTimeout(yi),yi=0),io=await(await jl("/energyprice.json")).json(),$o.set(io),yi=setTimeout(Ic,(60-new Date().getMinutes())*6e4)}let so={},rn;async function Co(){rn&&(clearTimeout(rn),rn=0),so=await(await jl("/dayplot.json")).json(),Rc.set(so),rn=setTimeout(Co,(60-new Date().getMinutes())*6e4+20)}const Rc=rt(so,t=>(Co(),function(){}));let oo={},an;async function To(){an&&(clearTimeout(an),an=0),oo=await(await jl("/monthplot.json")).json(),Lc.set(oo),an=setTimeout(To,(24-new Date().getHours())*36e5+40)}const Lc=rt(oo,t=>(To(),function(){}));let uo={};async function Oc(){uo=await(await jl("/temperature.json")).json(),qc.set(uo)}const qc=rt(uo,t=>(Oc(),function(){}));let ro={},gs;async function Uc(){gs&&(clearTimeout(gs),gs=0),ro=await(await jl("/tariff.json")).json(),Hc.set(ro),gs=setTimeout(Uc,(60-new Date().getMinutes())*6e4+30)}const Hc=rt(ro,t=>function(){});let ao=[];const So=rt(ao);async function ym(){ao=await(await jl("https://api.github.com/repos/UtilitechAS/amsreader-firmware/releases")).json(),So.set(ao)}function Ss(t){return"WARNING: "+t+" must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit."}async function jc(t){await(await fetch("/upgrade?expected_version="+t,{method:"POST"})).json()}function Wc(t,e){if(/^v\d{1,2}\.\d{1,2}\.\d{1,2}$/.test(t)){let l=t.substring(1).split("."),n=parseInt(l[0]),i=parseInt(l[1]),o=parseInt(l[2]),r=[...e];r.reverse();let a,c,f;for(let p=0;po&&(a=_):g==i+1&&(c=_);else if(v==n+1)if(f){let C=f.tag_name.substring(1).split(".");parseInt(C[0]);let $=parseInt(C[1]);parseInt(C[2]),g==$&&(f=_)}else f=_}return c||f||a||!1}else return e[0]}const $m="/github.svg";function na(t){let e,l;function n(r,a){return r[1]>1?Dm:r[1]>0?Nm:r[2]>1?Pm:r[2]>0?Mm:r[3]>1?Sm:r[3]>0?Tm:Cm}let i=n(t),o=i(t);return{c(){e=y(`Up - `),o.c(),l=Ke()},m(r,a){w(r,e,a),o.m(r,a),w(r,l,a)},p(r,a){i===(i=n(r))&&o?o.p(r,a):(o.d(1),o=i(r),o&&(o.c(),o.m(l.parentNode,l)))},d(r){r&&k(e),o.d(r),r&&k(l)}}}function Cm(t){let e,l;return{c(){e=y(t[0]),l=y(" seconds")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&1&&W(e,n[0])},d(n){n&&k(e),n&&k(l)}}}function Tm(t){let e,l;return{c(){e=y(t[3]),l=y(" minute")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&8&&W(e,n[3])},d(n){n&&k(e),n&&k(l)}}}function Sm(t){let e,l;return{c(){e=y(t[3]),l=y(" minutes")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&8&&W(e,n[3])},d(n){n&&k(e),n&&k(l)}}}function Mm(t){let e,l;return{c(){e=y(t[2]),l=y(" hour")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&4&&W(e,n[2])},d(n){n&&k(e),n&&k(l)}}}function Pm(t){let e,l;return{c(){e=y(t[2]),l=y(" hours")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&4&&W(e,n[2])},d(n){n&&k(e),n&&k(l)}}}function Nm(t){let e,l;return{c(){e=y(t[1]),l=y(" day")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&2&&W(e,n[1])},d(n){n&&k(e),n&&k(l)}}}function Dm(t){let e,l;return{c(){e=y(t[1]),l=y(" days")},m(n,i){w(n,e,i),w(n,l,i)},p(n,i){i&2&&W(e,n[1])},d(n){n&&k(e),n&&k(l)}}}function Am(t){let e,l=t[0]&&na(t);return{c(){l&&l.c(),e=Ke()},m(n,i){l&&l.m(n,i),w(n,e,i)},p(n,[i]){n[0]?l?l.p(n,i):(l=na(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},i:ne,o:ne,d(n){l&&l.d(n),n&&k(e)}}}function Em(t,e,l){let{epoch:n}=e,i=0,o=0,r=0;return t.$$set=a=>{"epoch"in a&&l(0,n=a.epoch)},t.$$.update=()=>{t.$$.dirty&1&&(l(1,i=Math.floor(n/86400)),l(2,o=Math.floor(n/3600)),l(3,r=Math.floor(n/60)))},[n,i,o,r]}class Im extends Me{constructor(e){super(),Se(this,e,Em,Am,we,{epoch:0})}}function Fm(t){let e,l,n;return{c(){e=m("span"),l=y(t[2]),u(e,"title",t[1]),u(e,"class",n="bd-"+t[0])},m(i,o){w(i,e,o),s(e,l)},p(i,[o]){o&4&&W(l,i[2]),o&2&&u(e,"title",i[1]),o&1&&n!==(n="bd-"+i[0])&&u(e,"class",n)},i:ne,o:ne,d(i){i&&k(e)}}}function Rm(t,e,l){let{color:n}=e,{title:i}=e,{text:o}=e;return t.$$set=r=>{"color"in r&&l(0,n=r.color),"title"in r&&l(1,i=r.title),"text"in r&&l(2,o=r.text)},[n,i,o]}class fn extends Me{constructor(e){super(),Se(this,e,Rm,Fm,we,{color:0,title:1,text:2})}}function Lm(t){let e,l=`${Ie(t[0].getDate())}.${Ie(t[0].getMonth()+1)}.${t[0].getFullYear()} ${Ie(t[0].getHours())}:${Ie(t[0].getMinutes())}`,n;return{c(){e=m("span"),n=y(l),u(e,"class",t[1])},m(i,o){w(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l=`${Ie(i[0].getDate())}.${Ie(i[0].getMonth()+1)}.${i[0].getFullYear()} ${Ie(i[0].getHours())}:${Ie(i[0].getMinutes())}`)&&W(n,l),o&2&&u(e,"class",i[1])},d(i){i&&k(e)}}}function Om(t){let e=`${Ie(t[0].getDate())}. ${no[t[0].getMonth()]} ${Ie(t[0].getHours())}:${Ie(t[0].getMinutes())}`,l;return{c(){l=y(e)},m(n,i){w(n,l,i)},p(n,i){i&1&&e!==(e=`${Ie(n[0].getDate())}. ${no[n[0].getMonth()]} ${Ie(n[0].getHours())}:${Ie(n[0].getMinutes())}`)&&W(l,e)},d(n){n&&k(l)}}}function qm(t){let e;function l(o,r){return o[2]?Om:Lm}let n=l(t),i=n(t);return{c(){i.c(),e=Ke()},m(o,r){i.m(o,r),w(o,e,r)},p(o,[r]){n===(n=l(o))&&i?i.p(o,r):(i.d(1),i=n(o),i&&(i.c(),i.m(e.parentNode,e)))},i:ne,o:ne,d(o){i.d(o),o&&k(e)}}}function Um(t,e,l){let{timestamp:n}=e,{fullTimeColor:i}=e,{offset:o}=e,r;return t.$$set=a=>{"timestamp"in a&&l(0,n=a.timestamp),"fullTimeColor"in a&&l(1,i=a.fullTimeColor),"offset"in a&&l(3,o=a.offset)},t.$$.update=()=>{t.$$.dirty&9&&(l(2,r=Math.abs(new Date().getTime()-n.getTime())<3e5),isNaN(o)||fl(n,o-(24+n.getHours()-n.getUTCHours())%24))},[n,i,r,o]}class Gc extends Me{constructor(e){super(),Se(this,e,Um,qm,we,{timestamp:0,fullTimeColor:1,offset:3})}}function Hm(t){let e,l,n;return{c(){e=Oe("svg"),l=Oe("path"),n=Oe("path"),u(l,"stroke-linecap","round"),u(l,"stroke-linejoin","round"),u(l,"d","M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"),u(n,"stroke-linecap","round"),u(n,"stroke-linejoin","round"),u(n,"d","M15 12a3 3 0 11-6 0 3 3 0 016 0z"),u(e,"xmlns","http://www.w3.org/2000/svg"),u(e,"fill","none"),u(e,"viewBox","0 0 24 24"),u(e,"stroke-width","1.5"),u(e,"stroke","currentColor"),u(e,"class","w-6 h-6")},m(i,o){w(i,e,o),s(e,l),s(e,n)},p:ne,i:ne,o:ne,d(i){i&&k(e)}}}class jm extends Me{constructor(e){super(),Se(this,e,null,Hm,we,{})}}function Wm(t){let e,l;return{c(){e=Oe("svg"),l=Oe("path"),u(l,"stroke-linecap","round"),u(l,"stroke-linejoin","round"),u(l,"d","M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"),u(e,"xmlns","http://www.w3.org/2000/svg"),u(e,"fill","none"),u(e,"viewBox","0 0 24 24"),u(e,"stroke-width","1.5"),u(e,"stroke","currentColor"),u(e,"class","w-6 h-6")},m(n,i){w(n,e,i),s(e,l)},p:ne,i:ne,o:ne,d(n){n&&k(e)}}}class Gm extends Me{constructor(e){super(),Se(this,e,null,Wm,we,{})}}function Bm(t){let e,l;return{c(){e=Oe("svg"),l=Oe("path"),u(l,"stroke-linecap","round"),u(l,"stroke-linejoin","round"),u(l,"d","M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"),u(e,"xmlns","http://www.w3.org/2000/svg"),u(e,"fill","none"),u(e,"viewBox","0 0 24 24"),u(e,"stroke-width","1.5"),u(e,"stroke","currentColor"),u(e,"class","w-6 h-6")},m(n,i){w(n,e,i),s(e,l)},p:ne,i:ne,o:ne,d(n){n&&k(e)}}}class qt extends Me{constructor(e){super(),Se(this,e,null,Bm,we,{})}}function zm(t){let e,l;return{c(){e=Oe("svg"),l=Oe("path"),u(l,"stroke-linecap","round"),u(l,"stroke-linejoin","round"),u(l,"d","M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15M9 12l3 3m0 0l3-3m-3 3V2.25"),u(e,"xmlns","http://www.w3.org/2000/svg"),u(e,"fill","none"),u(e,"viewBox","0 0 24 24"),u(e,"stroke-width","1.5"),u(e,"stroke","currentColor"),u(e,"class","w-6 h-6")},m(n,i){w(n,e,i),s(e,l)},p:ne,i:ne,o:ne,d(n){n&&k(e)}}}class Bc extends Me{constructor(e){super(),Se(this,e,null,zm,we,{})}}function Ym(t){let e,l,n=t[1].version+"",i;return{c(){e=y("AMS reader "),l=m("span"),i=y(n)},m(o,r){w(o,e,r),w(o,l,r),s(l,i)},p(o,r){r&2&&n!==(n=o[1].version+"")&&W(i,n)},d(o){o&&k(e),o&&k(l)}}}function ia(t){let e,l=(t[0].t>-50?t[0].t.toFixed(1):"-")+"",n,i;return{c(){e=m("div"),n=y(l),i=y("°C"),u(e,"class","flex-none my-auto")},m(o,r){w(o,e,r),s(e,n),s(e,i)},p(o,r){r&1&&l!==(l=(o[0].t>-50?o[0].t.toFixed(1):"-")+"")&&W(n,l)},d(o){o&&k(e)}}}function sa(t){let e,l="HAN: "+Xr(t[0].he),n;return{c(){e=m("div"),n=y(l),u(e,"class","bd-red")},m(i,o){w(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="HAN: "+Xr(i[0].he))&&W(n,l)},d(i){i&&k(e)}}}function oa(t){let e,l="MQTT: "+Zr(t[0].me),n;return{c(){e=m("div"),n=y(l),u(e,"class","bd-red")},m(i,o){w(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="MQTT: "+Zr(i[0].me))&&W(n,l)},d(i){i&&k(e)}}}function ua(t){let e,l="PriceAPI: "+Jr(t[0].ee),n;return{c(){e=m("div"),n=y(l),u(e,"class","bd-red")},m(i,o){w(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="PriceAPI: "+Jr(i[0].ee))&&W(n,l)},d(i){i&&k(e)}}}function ra(t){let e,l,n,i,o,r;return l=new el({props:{to:"/configuration",$$slots:{default:[Km]},$$scope:{ctx:t}}}),o=new el({props:{to:"/status",$$slots:{default:[Vm]},$$scope:{ctx:t}}}),{c(){e=m("div"),Z(l.$$.fragment),n=h(),i=m("div"),Z(o.$$.fragment),u(e,"class","flex-none px-1 mt-1"),u(e,"title","Configuration"),u(i,"class","flex-none px-1 mt-1"),u(i,"title","Device information")},m(a,c){w(a,e,c),Q(l,e,null),w(a,n,c),w(a,i,c),Q(o,i,null),r=!0},i(a){r||(P(l.$$.fragment,a),P(o.$$.fragment,a),r=!0)},o(a){I(l.$$.fragment,a),I(o.$$.fragment,a),r=!1},d(a){a&&k(e),X(l),a&&k(n),a&&k(i),X(o)}}}function Km(t){let e,l;return e=new jm({}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function Vm(t){let e,l;return e=new Gm({}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function aa(t){let e,l,n,i,o;const r=[Xm,Qm],a=[];function c(f,p){return f[1].security==0||f[0].a?0:1}return l=c(t),n=a[l]=r[l](t),{c(){e=m("div"),n.c(),u(e,"class","flex-none mr-3 text-yellow-500"),u(e,"title",i="New version: "+t[2].tag_name)},m(f,p){w(f,e,p),a[l].m(e,null),o=!0},p(f,p){let _=l;l=c(f),l===_?a[l].p(f,p):(Ae(),I(a[_],1,1,()=>{a[_]=null}),Ee(),n=a[l],n?n.p(f,p):(n=a[l]=r[l](f),n.c()),P(n,1),n.m(e,null)),(!o||p&4&&i!==(i="New version: "+f[2].tag_name))&&u(e,"title",i)},i(f){o||(P(n),o=!0)},o(f){I(n),o=!1},d(f){f&&k(e),a[l].d()}}}function Qm(t){let e,l,n=t[2].tag_name+"",i;return{c(){e=m("span"),l=y("New version: "),i=y(n)},m(o,r){w(o,e,r),s(e,l),s(e,i)},p(o,r){r&4&&n!==(n=o[2].tag_name+"")&&W(i,n)},i:ne,o:ne,d(o){o&&k(e)}}}function Xm(t){let e,l,n,i=t[2].tag_name+"",o,r,a,c,f,p;return a=new Bc({}),{c(){e=m("button"),l=m("span"),n=y("New version: "),o=y(i),r=h(),Z(a.$$.fragment),u(l,"class","mt-1"),u(e,"class","flex")},m(_,b){w(_,e,b),s(e,l),s(l,n),s(l,o),s(e,r),Q(a,e,null),c=!0,f||(p=K(e,"click",t[3]),f=!0)},p(_,b){(!c||b&4)&&i!==(i=_[2].tag_name+"")&&W(o,i)},i(_){c||(P(a.$$.fragment,_),c=!0)},o(_){I(a.$$.fragment,_),c=!1},d(_){_&&k(e),X(a),f=!1,p()}}}function Zm(t){let e,l,n,i,o,r,a,c,f,p,_,b,d=(t[0].m?(t[0].m/1e3).toFixed(1):"-")+"",v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q,L,B,O,j,G,te,le,pe,ie,Pe,je,De,We;i=new el({props:{to:"/",$$slots:{default:[Ym]},$$scope:{ctx:t}}}),c=new Im({props:{epoch:t[0].u}});let be=t[0].t>-50&&ia(t);$=new fn({props:{title:"ESP",text:t[1].booting?"Booting":t[0].v>2?t[0].v.toFixed(2)+"V":"ESP",color:ql(t[1].booting?2:t[0].em)}}),F=new fn({props:{title:"HAN",text:"HAN",color:ql(t[1].booting?9:t[0].hm)}}),D=new fn({props:{title:"WiFi",text:t[0].r?t[0].r.toFixed(0)+"dBm":"WiFi",color:ql(t[1].booting?9:t[0].wm)}}),E=new fn({props:{title:"MQTT",text:"MQTT",color:ql(t[1].booting?9:t[0].mm)}});let ye=(t[0].he<0||t[0].he>0)&&sa(t),Re=t[0].me<0&&oa(t),ge=(t[0].ee>0||t[0].ee<0)&&ua(t);te=new Gc({props:{timestamp:t[0].c?new Date(t[0].c*1e3):new Date(0),offset:t[1].clock_offset,fullTimeColor:"text-red-500"}});let ae=t[1].vndcfg&&t[1].usrcfg&&ra(t);je=new qt({});let $e=t[1].fwconsent===1&&t[2]&&aa(t);return{c(){e=m("nav"),l=m("div"),n=m("div"),Z(i.$$.fragment),o=h(),r=m("div"),a=m("div"),Z(c.$$.fragment),f=h(),be&&be.c(),p=h(),_=m("div"),b=y("Free mem: "),v=y(d),g=y("kb"),T=h(),C=m("div"),Z($.$$.fragment),M=h(),Z(F.$$.fragment),S=h(),Z(D.$$.fragment),A=h(),Z(E.$$.fragment),Y=h(),ye&&ye.c(),R=h(),Re&&Re.c(),U=h(),ge&&ge.c(),H=h(),z=m("div"),q=m("div"),L=m("a"),B=m("img"),j=h(),G=m("div"),Z(te.$$.fragment),le=h(),ae&&ae.c(),pe=h(),ie=m("div"),Pe=m("a"),Z(je.$$.fragment),De=h(),$e&&$e.c(),u(n,"class","flex text-lg text-gray-100 p-2"),u(a,"class","flex-none my-auto"),u(_,"class","flex-none my-auto"),u(r,"class","flex-none my-auto p-2 flex space-x-4"),u(C,"class","flex-auto flex-wrap my-auto justify-center p-2"),u(B,"class","gh-logo"),Xc(B.src,O=$m)||u(B,"src",O),u(B,"alt","GitHub repo"),u(L,"class","float-right"),u(L,"href","https://github.com/UtilitechAS/amsreader-firmware"),u(L,"target","_blank"),u(L,"rel","noreferrer"),u(L,"aria-label","GitHub"),u(q,"class","flex-none"),u(G,"class","flex-none my-auto px-2"),u(Pe,"href",Ut("")),u(Pe,"target","_blank"),u(Pe,"rel","noreferrer"),u(ie,"class","flex-none px-1 mt-1"),u(ie,"title","Documentation"),u(z,"class","flex-auto p-2 flex flex-row-reverse flex-wrap"),u(l,"class","flex flex-wrap space-x-4 text-sm text-gray-300"),u(e,"class","bg-violet-600 p-1 rounded-md mx-2")},m(J,se){w(J,e,se),s(e,l),s(l,n),Q(i,n,null),s(l,o),s(l,r),s(r,a),Q(c,a,null),s(r,f),be&&be.m(r,null),s(r,p),s(r,_),s(_,b),s(_,v),s(_,g),s(l,T),s(l,C),Q($,C,null),s(C,M),Q(F,C,null),s(C,S),Q(D,C,null),s(C,A),Q(E,C,null),s(l,Y),ye&&ye.m(l,null),s(l,R),Re&&Re.m(l,null),s(l,U),ge&&ge.m(l,null),s(l,H),s(l,z),s(z,q),s(q,L),s(L,B),s(z,j),s(z,G),Q(te,G,null),s(z,le),ae&&ae.m(z,null),s(z,pe),s(z,ie),s(ie,Pe),Q(je,Pe,null),s(z,De),$e&&$e.m(z,null),We=!0},p(J,[se]){const Fe={};se&18&&(Fe.$$scope={dirty:se,ctx:J}),i.$set(Fe);const Le={};se&1&&(Le.epoch=J[0].u),c.$set(Le),J[0].t>-50?be?be.p(J,se):(be=ia(J),be.c(),be.m(r,p)):be&&(be.d(1),be=null),(!We||se&1)&&d!==(d=(J[0].m?(J[0].m/1e3).toFixed(1):"-")+"")&&W(v,d);const _e={};se&3&&(_e.text=J[1].booting?"Booting":J[0].v>2?J[0].v.toFixed(2)+"V":"ESP"),se&3&&(_e.color=ql(J[1].booting?2:J[0].em)),$.$set(_e);const Ce={};se&3&&(Ce.color=ql(J[1].booting?9:J[0].hm)),F.$set(Ce);const Ne={};se&1&&(Ne.text=J[0].r?J[0].r.toFixed(0)+"dBm":"WiFi"),se&3&&(Ne.color=ql(J[1].booting?9:J[0].wm)),D.$set(Ne);const de={};se&3&&(de.color=ql(J[1].booting?9:J[0].mm)),E.$set(de),J[0].he<0||J[0].he>0?ye?ye.p(J,se):(ye=sa(J),ye.c(),ye.m(l,R)):ye&&(ye.d(1),ye=null),J[0].me<0?Re?Re.p(J,se):(Re=oa(J),Re.c(),Re.m(l,U)):Re&&(Re.d(1),Re=null),J[0].ee>0||J[0].ee<0?ge?ge.p(J,se):(ge=ua(J),ge.c(),ge.m(l,H)):ge&&(ge.d(1),ge=null);const Te={};se&1&&(Te.timestamp=J[0].c?new Date(J[0].c*1e3):new Date(0)),se&2&&(Te.offset=J[1].clock_offset),te.$set(Te),J[1].vndcfg&&J[1].usrcfg?ae?se&2&&P(ae,1):(ae=ra(J),ae.c(),P(ae,1),ae.m(z,pe)):ae&&(Ae(),I(ae,1,1,()=>{ae=null}),Ee()),J[1].fwconsent===1&&J[2]?$e?($e.p(J,se),se&6&&P($e,1)):($e=aa(J),$e.c(),P($e,1),$e.m(z,null)):$e&&(Ae(),I($e,1,1,()=>{$e=null}),Ee())},i(J){We||(P(i.$$.fragment,J),P(c.$$.fragment,J),P($.$$.fragment,J),P(F.$$.fragment,J),P(D.$$.fragment,J),P(E.$$.fragment,J),P(te.$$.fragment,J),P(ae),P(je.$$.fragment,J),P($e),We=!0)},o(J){I(i.$$.fragment,J),I(c.$$.fragment,J),I($.$$.fragment,J),I(F.$$.fragment,J),I(D.$$.fragment,J),I(E.$$.fragment,J),I(te.$$.fragment,J),I(ae),I(je.$$.fragment,J),I($e),We=!1},d(J){J&&k(e),X(i),X(c),be&&be.d(),X($),X(F),X(D),X(E),ye&&ye.d(),Re&&Re.d(),ge&&ge.d(),X(te),ae&&ae.d(),X(je),$e&&$e.d()}}}function Jm(t,e,l){let{data:n={}}=e,i={},o={};function r(){confirm("Do you want to upgrade this device to "+o.tag_name+"?")&&(!ui(i.board)||confirm(Ss(ce(i.chip,i.board))))&&(Ht.update(a=>(a.upgrading=!0,a)),jc(o.tag_name))}return Ht.subscribe(a=>{l(1,i=a),a.fwconsent===1&&ym()}),So.subscribe(a=>{l(2,o=Wc(i.version,a))}),t.$$set=a=>{"data"in a&&l(0,n=a.data)},[n,i,o,r]}class xm extends Me{constructor(e){super(),Se(this,e,Jm,Zm,we,{data:0})}}function ep(t){let e,l,n,i;return{c(){e=Oe("svg"),l=Oe("path"),n=Oe("path"),u(l,"d",Js(150,150,115,210,510)),u(l,"stroke","#eee"),u(l,"fill","none"),u(l,"stroke-width","55"),u(n,"d",i=Js(150,150,115,210,210+300*t[0]/100)),u(n,"stroke",t[1]),u(n,"fill","none"),u(n,"stroke-width","55"),u(e,"viewBox","0 0 300 300"),u(e,"xmlns","http://www.w3.org/2000/svg"),u(e,"height","100%")},m(o,r){w(o,e,r),s(e,l),s(e,n)},p(o,[r]){r&1&&i!==(i=Js(150,150,115,210,210+300*o[0]/100))&&u(n,"d",i),r&2&&u(n,"stroke",o[1])},i:ne,o:ne,d(o){o&&k(e)}}}function fa(t,e,l,n){var i=(n-90)*Math.PI/180;return{x:t+l*Math.cos(i),y:e+l*Math.sin(i)}}function Js(t,e,l,n,i){var o=fa(t,e,l,i),r=fa(t,e,l,n),a=i-n<=180?"0":"1",c=["M",o.x,o.y,"A",l,l,0,a,0,r.x,r.y].join(" ");return c}function tp(t,e,l){let{pct:n=0}=e,{color:i="red"}=e;return t.$$set=o=>{"pct"in o&&l(0,n=o.pct),"color"in o&&l(1,i=o.color)},[n,i]}class lp extends Me{constructor(e){super(),Se(this,e,tp,ep,we,{pct:0,color:1})}}function ca(t){let e,l,n,i,o,r,a,c;return{c(){e=m("br"),l=h(),n=m("span"),i=y(t[3]),o=h(),r=m("span"),a=y(t[4]),c=y("/kWh"),u(n,"class","pl-sub"),u(r,"class","pl-snt")},m(f,p){w(f,e,p),w(f,l,p),w(f,n,p),s(n,i),w(f,o,p),w(f,r,p),s(r,a),s(r,c)},p(f,p){p&8&&W(i,f[3]),p&16&&W(a,f[4])},d(f){f&&k(e),f&&k(l),f&&k(n),f&&k(o),f&&k(r)}}}function np(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T;l=new lp({props:{pct:t[6],color:t[5](t[6])}});let C=t[3]&&ca(t);return{c(){e=m("div"),Z(l.$$.fragment),n=h(),i=m("span"),o=m("span"),r=y(t[2]),a=h(),c=m("br"),f=h(),p=m("span"),_=y(t[0]),b=h(),d=m("span"),v=y(t[1]),g=h(),C&&C.c(),u(o,"class","pl-lab"),u(p,"class","pl-val"),u(d,"class","pl-unt"),u(i,"class","pl-ov"),u(e,"class","pl-root")},m($,M){w($,e,M),Q(l,e,null),s(e,n),s(e,i),s(i,o),s(o,r),s(i,a),s(i,c),s(i,f),s(i,p),s(p,_),s(i,b),s(i,d),s(d,v),s(i,g),C&&C.m(i,null),T=!0},p($,[M]){const F={};M&64&&(F.pct=$[6]),M&96&&(F.color=$[5]($[6])),l.$set(F),(!T||M&4)&&W(r,$[2]),(!T||M&1)&&W(_,$[0]),(!T||M&2)&&W(v,$[1]),$[3]?C?C.p($,M):(C=ca($),C.c(),C.m(i,null)):C&&(C.d(1),C=null)},i($){T||(P(l.$$.fragment,$),T=!0)},o($){I(l.$$.fragment,$),T=!1},d($){$&&k(e),X(l),C&&C.d()}}}function ip(t,e,l){let{val:n}=e,{max:i}=e,{unit:o}=e,{label:r}=e,{sub:a=""}=e,{subunit:c=""}=e,{colorFn:f}=e,p=0;return t.$$set=_=>{"val"in _&&l(0,n=_.val),"max"in _&&l(7,i=_.max),"unit"in _&&l(1,o=_.unit),"label"in _&&l(2,r=_.label),"sub"in _&&l(3,a=_.sub),"subunit"in _&&l(4,c=_.subunit),"colorFn"in _&&l(5,f=_.colorFn)},t.$$.update=()=>{t.$$.dirty&129&&l(6,p=Math.min(n,i)/i*100)},[n,o,r,a,c,f,p,i]}class zc extends Me{constructor(e){super(),Se(this,e,ip,np,we,{val:0,max:7,unit:1,label:2,sub:3,subunit:4,colorFn:5})}}function ma(t,e,l){const n=t.slice();return n[9]=e[l],n[11]=l,n}function pa(t,e,l){const n=t.slice();return n[9]=e[l],n[11]=l,n}function _a(t,e,l){const n=t.slice();return n[13]=e[l],n}function da(t){let e,l,n,i,o,r=t[0].title&&va(t),a=t[0].y.ticks,c=[];for(let d=0;d20||t[11]%2==0)&&ka(t);return{c(){e=Oe("g"),n&&n.c(),u(e,"class","tick"),u(e,"transform",l="translate("+t[5](t[11])+","+t[4]+")")},m(i,o){w(i,e,o),n&&n.m(e,null)},p(i,o){i[3]>20||i[11]%2==0?n?n.p(i,o):(n=ka(i),n.c(),n.m(e,null)):n&&(n.d(1),n=null),o&48&&l!==(l="translate("+i[5](i[11])+","+i[4]+")")&&u(e,"transform",l)},d(i){i&&k(e),n&&n.d()}}}function ka(t){let e,l=t[9].label+"",n,i;return{c(){e=Oe("text"),n=y(l),u(e,"x",i=t[3]/2),u(e,"y","-4")},m(o,r){w(o,e,r),s(e,n)},p(o,r){r&1&&l!==(l=o[9].label+"")&&W(n,l),r&8&&i!==(i=o[3]/2)&&u(e,"x",i)},d(o){o&&k(e)}}}function wa(t){let e=!isNaN(t[5](t[11])),l,n=e&&ga(t);return{c(){n&&n.c(),l=Ke()},m(i,o){n&&n.m(i,o),w(i,l,o)},p(i,o){o&32&&(e=!isNaN(i[5](i[11]))),e?n?n.p(i,o):(n=ga(i),n.c(),n.m(l.parentNode,l)):n&&(n.d(1),n=null)},d(i){n&&n.d(i),i&&k(l)}}}function ya(t){let e,l,n=t[9].value!==void 0&&$a(t),i=t[9].value2>1e-4&&Sa(t);return{c(){e=Oe("g"),n&&n.c(),l=Oe("g"),i&&i.c()},m(o,r){w(o,e,r),n&&n.m(e,null),w(o,l,r),i&&i.m(l,null)},p(o,r){o[9].value!==void 0?n?n.p(o,r):(n=$a(o),n.c(),n.m(e,null)):n&&(n.d(1),n=null),o[9].value2>1e-4?i?i.p(o,r):(i=Sa(o),i.c(),i.m(l,null)):i&&(i.d(1),i=null)},d(o){o&&k(e),n&&n.d(),o&&k(l),i&&i.d()}}}function $a(t){let e,l,n,i,o,r,a,c=t[3]>15&&Ca(t);return{c(){e=Oe("rect"),c&&c.c(),a=Ke(),u(e,"x",l=t[5](t[11])+2),u(e,"y",n=t[6](t[9].value)),u(e,"width",i=t[3]-4),u(e,"height",o=t[6](t[0].y.min)-t[6](Math.min(t[0].y.min,0)+t[9].value)),u(e,"fill",r=t[9].color)},m(f,p){w(f,e,p),c&&c.m(f,p),w(f,a,p)},p(f,p){p&32&&l!==(l=f[5](f[11])+2)&&u(e,"x",l),p&65&&n!==(n=f[6](f[9].value))&&u(e,"y",n),p&8&&i!==(i=f[3]-4)&&u(e,"width",i),p&65&&o!==(o=f[6](f[0].y.min)-f[6](Math.min(f[0].y.min,0)+f[9].value))&&u(e,"height",o),p&1&&r!==(r=f[9].color)&&u(e,"fill",r),f[3]>15?c?c.p(f,p):(c=Ca(f),c.c(),c.m(a.parentNode,a)):c&&(c.d(1),c=null)},d(f){f&&k(e),c&&c.d(f),f&&k(a)}}}function Ca(t){let e,l=t[9].label+"",n,i,o,r,a,c,f=t[9].title&&Ta(t);return{c(){e=Oe("text"),n=y(l),f&&f.c(),c=Ke(),u(e,"width",i=t[3]-4),u(e,"dominant-baseline","middle"),u(e,"text-anchor",o=t[3]t[6](0)-t[7]?t[9].color:"white"),u(e,"transform",a="translate("+(t[5](t[11])+t[3]/2)+" "+(t[6](t[9].value)>t[6](0)-t[7]?t[6](t[9].value)-t[7]:t[6](t[9].value)+10)+") rotate("+(t[3]p[6](0)-p[7]?p[9].color:"white")&&u(e,"fill",r),_&233&&a!==(a="translate("+(p[5](p[11])+p[3]/2)+" "+(p[6](p[9].value)>p[6](0)-p[7]?p[6](p[9].value)-p[7]:p[6](p[9].value)+10)+") rotate("+(p[3]15&&Ma(t);return{c(){e=Oe("rect"),c&&c.c(),a=Ke(),u(e,"x",l=t[5](t[11])+2),u(e,"y",n=t[6](0)),u(e,"width",i=t[3]-4),u(e,"height",o=t[6](t[0].y.min)-t[6](t[0].y.min+t[9].value2)),u(e,"fill",r=t[9].color2?t[9].color2:t[9].color)},m(f,p){w(f,e,p),c&&c.m(f,p),w(f,a,p)},p(f,p){p&32&&l!==(l=f[5](f[11])+2)&&u(e,"x",l),p&64&&n!==(n=f[6](0))&&u(e,"y",n),p&8&&i!==(i=f[3]-4)&&u(e,"width",i),p&65&&o!==(o=f[6](f[0].y.min)-f[6](f[0].y.min+f[9].value2))&&u(e,"height",o),p&1&&r!==(r=f[9].color2?f[9].color2:f[9].color)&&u(e,"fill",r),f[3]>15?c?c.p(f,p):(c=Ma(f),c.c(),c.m(a.parentNode,a)):c&&(c.d(1),c=null)},d(f){f&&k(e),c&&c.d(f),f&&k(a)}}}function Ma(t){let e,l=t[9].label2+"",n,i,o,r,a,c=t[9].title2&&Pa(t);return{c(){e=Oe("text"),n=y(l),c&&c.c(),a=Ke(),u(e,"width",i=t[3]-4),u(e,"dominant-baseline","middle"),u(e,"text-anchor","middle"),u(e,"fill",o=t[6](-t[9].value2)t[8].call(e))},m(i,o){w(i,e,o),n&&n.m(e,null),l=i1(e,t[8].bind(e))},p(i,[o]){i[0].x.ticks&&i[0].points&&i[4]?n?n.p(i,o):(n=da(i),n.c(),n.m(e,null)):n&&(n.d(1),n=null)},i:ne,o:ne,d(i){i&&k(e),n&&n.d(),l()}}}let cn=30;function op(t,e,l){let{config:n}=e,i,o,r,a,c,f,p;function _(){i=this.clientWidth,o=this.clientHeight,l(1,i),l(2,o)}return t.$$set=b=>{"config"in b&&l(0,n=b.config)},t.$$.update=()=>{if(t.$$.dirty&31){l(4,f=o-(n.title?20:0));let b=i-(n.padding.left+n.padding.right);l(3,r=b/n.points.length),l(7,p=rn.y.max?g=n.padding.bottom:vf||g<0?0:g})}},[n,i,o,r,f,a,c,p,_]}class pn extends Me{constructor(e){super(),Se(this,e,op,sp,we,{config:0})}}function up(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function rp(t,e,l){let{u1:n}=e,{u2:i}=e,{u3:o}=e,{ds:r}=e,a={};function c(f){return{label:me(f)+"V",title:f.toFixed(1)+" V",value:isNaN(f)?0:f,color:bm(f||0)}}return t.$$set=f=>{"u1"in f&&l(1,n=f.u1),"u2"in f&&l(2,i=f.u2),"u3"in f&&l(3,o=f.u3),"ds"in f&&l(4,r=f.ds)},t.$$.update=()=>{if(t.$$.dirty&30){let f=[],p=[];n>0&&(f.push({label:r===1?"L1-L2":"L1"}),p.push(c(n))),i>0&&(f.push({label:r===1?"L1-L3":"L2"}),p.push(c(i))),o>0&&(f.push({label:r===1?"L2-L3":"L3"}),p.push(c(o))),l(0,a={padding:{top:20,right:15,bottom:20,left:35},y:{min:200,max:260,ticks:[{value:207,label:"-10%"},{value:230,label:"230v"},{value:253,label:"+10%"}]},x:{ticks:f},points:p})}},[a,n,i,o,r]}class ap extends Me{constructor(e){super(),Se(this,e,rp,up,we,{u1:1,u2:2,u3:3,ds:4})}}function fp(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function cp(t,e,l){let{u1:n}=e,{u2:i}=e,{u3:o}=e,{i1:r}=e,{i2:a}=e,{i3:c}=e,{max:f}=e,p={};function _(b){return{label:me(b)+"A",title:b.toFixed(1)+" A",value:isNaN(b)?0:b,color:Ec(b?b/f*100:0)}}return t.$$set=b=>{"u1"in b&&l(1,n=b.u1),"u2"in b&&l(2,i=b.u2),"u3"in b&&l(3,o=b.u3),"i1"in b&&l(4,r=b.i1),"i2"in b&&l(5,a=b.i2),"i3"in b&&l(6,c=b.i3),"max"in b&&l(7,f=b.max)},t.$$.update=()=>{if(t.$$.dirty&254){let b=[],d=[];n>0&&(b.push({label:"L1"}),d.push(_(r))),i>0&&(b.push({label:"L2"}),d.push(_(a))),o>0&&(b.push({label:"L3"}),d.push(_(c))),l(0,p={padding:{top:20,right:15,bottom:20,left:35},y:{min:0,max:f,ticks:[{value:0,label:"0%"},{value:f/4,label:"25%"},{value:f/2,label:"50%"},{value:f/4*3,label:"75%"},{value:f,label:"100%"}]},x:{ticks:b},points:d})}},[p,n,i,o,r,a,c,f]}class mp extends Me{constructor(e){super(),Se(this,e,cp,fp,we,{u1:1,u2:2,u3:3,i1:4,i2:5,i3:6,max:7})}}function pp(t){let e,l,n,i,o,r,a,c=(typeof t[0]<"u"?t[0].toFixed(0):"-")+"",f,p,_,b,d,v,g=(typeof t[1]<"u"?t[1].toFixed(0):"-")+"",T,C,$,M,F,S,D,A=(typeof t[2]<"u"?t[2].toFixed(1):"-")+"",E,Y,R,U,H,z,q=(typeof t[3]<"u"?t[3].toFixed(1):"-")+"",L,B;return{c(){e=m("div"),l=m("strong"),l.textContent="Reactive",n=h(),i=m("div"),o=m("div"),o.textContent="Instant in",r=h(),a=m("div"),f=y(c),p=y(" VAr"),_=h(),b=m("div"),b.textContent="Instant out",d=h(),v=m("div"),T=y(g),C=y(" VAr"),$=h(),M=m("div"),F=m("div"),F.textContent="Total in",S=h(),D=m("div"),E=y(A),Y=y(" kVArh"),R=h(),U=m("div"),U.textContent="Total out",H=h(),z=m("div"),L=y(q),B=y(" kVArh"),u(a,"class","text-right"),u(v,"class","text-right"),u(i,"class","grid grid-cols-2 mt-4"),u(D,"class","text-right"),u(z,"class","text-right"),u(M,"class","grid grid-cols-2 mt-4"),u(e,"class","mx-2 text-sm")},m(O,j){w(O,e,j),s(e,l),s(e,n),s(e,i),s(i,o),s(i,r),s(i,a),s(a,f),s(a,p),s(i,_),s(i,b),s(i,d),s(i,v),s(v,T),s(v,C),s(e,$),s(e,M),s(M,F),s(M,S),s(M,D),s(D,E),s(D,Y),s(M,R),s(M,U),s(M,H),s(M,z),s(z,L),s(z,B)},p(O,[j]){j&1&&c!==(c=(typeof O[0]<"u"?O[0].toFixed(0):"-")+"")&&W(f,c),j&2&&g!==(g=(typeof O[1]<"u"?O[1].toFixed(0):"-")+"")&&W(T,g),j&4&&A!==(A=(typeof O[2]<"u"?O[2].toFixed(1):"-")+"")&&W(E,A),j&8&&q!==(q=(typeof O[3]<"u"?O[3].toFixed(1):"-")+"")&&W(L,q)},i:ne,o:ne,d(O){O&&k(e)}}}function _p(t,e,l){let{importInstant:n}=e,{exportInstant:i}=e,{importTotal:o}=e,{exportTotal:r}=e;return t.$$set=a=>{"importInstant"in a&&l(0,n=a.importInstant),"exportInstant"in a&&l(1,i=a.exportInstant),"importTotal"in a&&l(2,o=a.importTotal),"exportTotal"in a&&l(3,r=a.exportTotal)},[n,i,o,r]}class dp extends Me{constructor(e){super(),Se(this,e,_p,pp,we,{importInstant:0,exportInstant:1,importTotal:2,exportTotal:3})}}function Da(t){let e;function l(o,r){return o[3]?hp:vp}let n=l(t),i=n(t);return{c(){i.c(),e=Ke()},m(o,r){i.m(o,r),w(o,e,r)},p(o,r){n===(n=l(o))&&i?i.p(o,r):(i.d(1),i=n(o),i&&(i.c(),i.m(e.parentNode,e)))},d(o){i.d(o),o&&k(e)}}}function vp(t){let e,l,n,i,o,r,a=me(t[1].h.u,2)+"",c,f,p,_,b,d,v=me(t[1].d.u,1)+"",g,T,C,$,M,F,S=me(t[1].m.u)+"",D,A,E,Y,R,U,H=me(t[0].last_month.u)+"",z,q,L,B,O=t[4]&&Aa(t);return{c(){e=m("strong"),e.textContent="Consumption",l=h(),n=m("div"),i=m("div"),i.textContent="Hour",o=h(),r=m("div"),c=y(a),f=y(" kWh"),p=h(),_=m("div"),_.textContent="Day",b=h(),d=m("div"),g=y(v),T=y(" kWh"),C=h(),$=m("div"),$.textContent="Month",M=h(),F=m("div"),D=y(S),A=y(" kWh"),E=h(),Y=m("div"),Y.textContent="Last month",R=h(),U=m("div"),z=y(H),q=y(" kWh"),L=h(),O&&O.c(),B=Ke(),u(r,"class","text-right"),u(d,"class","text-right"),u(F,"class","text-right"),u(U,"class","text-right"),u(n,"class","grid grid-cols-2 mb-3")},m(j,G){w(j,e,G),w(j,l,G),w(j,n,G),s(n,i),s(n,o),s(n,r),s(r,c),s(r,f),s(n,p),s(n,_),s(n,b),s(n,d),s(d,g),s(d,T),s(n,C),s(n,$),s(n,M),s(n,F),s(F,D),s(F,A),s(n,E),s(n,Y),s(n,R),s(n,U),s(U,z),s(U,q),w(j,L,G),O&&O.m(j,G),w(j,B,G)},p(j,G){G&2&&a!==(a=me(j[1].h.u,2)+"")&&W(c,a),G&2&&v!==(v=me(j[1].d.u,1)+"")&&W(g,v),G&2&&S!==(S=me(j[1].m.u)+"")&&W(D,S),G&1&&H!==(H=me(j[0].last_month.u)+"")&&W(z,H),j[4]?O?O.p(j,G):(O=Aa(j),O.c(),O.m(B.parentNode,B)):O&&(O.d(1),O=null)},d(j){j&&k(e),j&&k(l),j&&k(n),j&&k(L),O&&O.d(j),j&&k(B)}}}function hp(t){let e,l,n,i,o,r,a=me(t[1].h.u,2)+"",c,f,p,_,b,d,v,g=me(t[1].d.u,1)+"",T,C,$,M,F,S,D,A=me(t[1].m.u)+"",E,Y,R,U,H,z,q,L=me(t[0].last_month.u)+"",B,O,j,G,te,le,pe,ie,Pe,je,De,We=me(t[1].h.p,2)+"",be,ye,Re,ge,ae,$e,J,se=me(t[1].d.p,1)+"",Fe,Le,_e,Ce,Ne,de,Te,ee=me(t[1].m.p)+"",oe,Ue,ue,ve,dt,Wl,tl,ct=me(t[0].last_month.p)+"",Ml,pl,jt,vt,Qe=t[4]&&Ea(t),Xe=t[4]&&Ia(t),Ze=t[4]&&Fa(t),He=t[4]&&Ra(t),Je=t[4]&&La(t),Ge=t[4]&&Oa(t),xe=t[4]&&qa(t),et=t[4]&&Ua(t);return{c(){e=m("strong"),e.textContent="Import",l=h(),n=m("div"),i=m("div"),i.textContent="Hour",o=h(),r=m("div"),c=y(a),f=y(" kWh"),p=h(),Qe&&Qe.c(),_=h(),b=m("div"),b.textContent="Day",d=h(),v=m("div"),T=y(g),C=y(" kWh"),$=h(),Xe&&Xe.c(),M=h(),F=m("div"),F.textContent="Month",S=h(),D=m("div"),E=y(A),Y=y(" kWh"),R=h(),Ze&&Ze.c(),U=h(),H=m("div"),H.textContent="Last mo.",z=h(),q=m("div"),B=y(L),O=y(" kWh"),j=h(),He&&He.c(),te=h(),le=m("strong"),le.textContent="Export",pe=h(),ie=m("div"),Pe=m("div"),Pe.textContent="Hour",je=h(),De=m("div"),be=y(We),ye=y(" kWh"),Re=h(),Je&&Je.c(),ge=h(),ae=m("div"),ae.textContent="Day",$e=h(),J=m("div"),Fe=y(se),Le=y(" kWh"),_e=h(),Ge&&Ge.c(),Ce=h(),Ne=m("div"),Ne.textContent="Month",de=h(),Te=m("div"),oe=y(ee),Ue=y(" kWh"),ue=h(),xe&&xe.c(),ve=h(),dt=m("div"),dt.textContent="Last mo.",Wl=h(),tl=m("div"),Ml=y(ct),pl=y(" kWh"),jt=h(),et&&et.c(),u(r,"class","text-right"),u(v,"class","text-right"),u(D,"class","text-right"),u(q,"class","text-right"),u(n,"class",G="grid grid-cols-"+t[5]+" mb-3"),u(De,"class","text-right"),u(J,"class","text-right"),u(Te,"class","text-right"),u(tl,"class","text-right"),u(ie,"class",vt="grid grid-cols-"+t[5])},m(re,he){w(re,e,he),w(re,l,he),w(re,n,he),s(n,i),s(n,o),s(n,r),s(r,c),s(r,f),s(n,p),Qe&&Qe.m(n,null),s(n,_),s(n,b),s(n,d),s(n,v),s(v,T),s(v,C),s(n,$),Xe&&Xe.m(n,null),s(n,M),s(n,F),s(n,S),s(n,D),s(D,E),s(D,Y),s(n,R),Ze&&Ze.m(n,null),s(n,U),s(n,H),s(n,z),s(n,q),s(q,B),s(q,O),s(n,j),He&&He.m(n,null),w(re,te,he),w(re,le,he),w(re,pe,he),w(re,ie,he),s(ie,Pe),s(ie,je),s(ie,De),s(De,be),s(De,ye),s(ie,Re),Je&&Je.m(ie,null),s(ie,ge),s(ie,ae),s(ie,$e),s(ie,J),s(J,Fe),s(J,Le),s(ie,_e),Ge&&Ge.m(ie,null),s(ie,Ce),s(ie,Ne),s(ie,de),s(ie,Te),s(Te,oe),s(Te,Ue),s(ie,ue),xe&&xe.m(ie,null),s(ie,ve),s(ie,dt),s(ie,Wl),s(ie,tl),s(tl,Ml),s(tl,pl),s(ie,jt),et&&et.m(ie,null)},p(re,he){he&2&&a!==(a=me(re[1].h.u,2)+"")&&W(c,a),re[4]?Qe?Qe.p(re,he):(Qe=Ea(re),Qe.c(),Qe.m(n,_)):Qe&&(Qe.d(1),Qe=null),he&2&&g!==(g=me(re[1].d.u,1)+"")&&W(T,g),re[4]?Xe?Xe.p(re,he):(Xe=Ia(re),Xe.c(),Xe.m(n,M)):Xe&&(Xe.d(1),Xe=null),he&2&&A!==(A=me(re[1].m.u)+"")&&W(E,A),re[4]?Ze?Ze.p(re,he):(Ze=Fa(re),Ze.c(),Ze.m(n,U)):Ze&&(Ze.d(1),Ze=null),he&1&&L!==(L=me(re[0].last_month.u)+"")&&W(B,L),re[4]?He?He.p(re,he):(He=Ra(re),He.c(),He.m(n,null)):He&&(He.d(1),He=null),he&32&&G!==(G="grid grid-cols-"+re[5]+" mb-3")&&u(n,"class",G),he&2&&We!==(We=me(re[1].h.p,2)+"")&&W(be,We),re[4]?Je?Je.p(re,he):(Je=La(re),Je.c(),Je.m(ie,ge)):Je&&(Je.d(1),Je=null),he&2&&se!==(se=me(re[1].d.p,1)+"")&&W(Fe,se),re[4]?Ge?Ge.p(re,he):(Ge=Oa(re),Ge.c(),Ge.m(ie,Ce)):Ge&&(Ge.d(1),Ge=null),he&2&&ee!==(ee=me(re[1].m.p)+"")&&W(oe,ee),re[4]?xe?xe.p(re,he):(xe=qa(re),xe.c(),xe.m(ie,ve)):xe&&(xe.d(1),xe=null),he&1&&ct!==(ct=me(re[0].last_month.p)+"")&&W(Ml,ct),re[4]?et?et.p(re,he):(et=Ua(re),et.c(),et.m(ie,null)):et&&(et.d(1),et=null),he&32&&vt!==(vt="grid grid-cols-"+re[5])&&u(ie,"class",vt)},d(re){re&&k(e),re&&k(l),re&&k(n),Qe&&Qe.d(),Xe&&Xe.d(),Ze&&Ze.d(),He&&He.d(),re&&k(te),re&&k(le),re&&k(pe),re&&k(ie),Je&&Je.d(),Ge&&Ge.d(),xe&&xe.d(),et&&et.d()}}}function Aa(t){let e,l,n,i,o,r,a=me(t[1].h.c,2)+"",c,f,p,_,b,d,v,g=me(t[1].d.c,1)+"",T,C,$,M,F,S,D,A=me(t[1].m.c)+"",E,Y,R,U,H,z,q,L=me(t[0].last_month.c)+"",B,O,j;return{c(){e=m("strong"),e.textContent="Cost",l=h(),n=m("div"),i=m("div"),i.textContent="Hour",o=h(),r=m("div"),c=y(a),f=h(),p=y(t[2]),_=h(),b=m("div"),b.textContent="Day",d=h(),v=m("div"),T=y(g),C=h(),$=y(t[2]),M=h(),F=m("div"),F.textContent="Month",S=h(),D=m("div"),E=y(A),Y=h(),R=y(t[2]),U=h(),H=m("div"),H.textContent="Last month",z=h(),q=m("div"),B=y(L),O=h(),j=y(t[2]),u(r,"class","text-right"),u(v,"class","text-right"),u(D,"class","text-right"),u(q,"class","text-right"),u(n,"class","grid grid-cols-2")},m(G,te){w(G,e,te),w(G,l,te),w(G,n,te),s(n,i),s(n,o),s(n,r),s(r,c),s(r,f),s(r,p),s(n,_),s(n,b),s(n,d),s(n,v),s(v,T),s(v,C),s(v,$),s(n,M),s(n,F),s(n,S),s(n,D),s(D,E),s(D,Y),s(D,R),s(n,U),s(n,H),s(n,z),s(n,q),s(q,B),s(q,O),s(q,j)},p(G,te){te&2&&a!==(a=me(G[1].h.c,2)+"")&&W(c,a),te&4&&W(p,G[2]),te&2&&g!==(g=me(G[1].d.c,1)+"")&&W(T,g),te&4&&W($,G[2]),te&2&&A!==(A=me(G[1].m.c)+"")&&W(E,A),te&4&&W(R,G[2]),te&1&&L!==(L=me(G[0].last_month.c)+"")&&W(B,L),te&4&&W(j,G[2])},d(G){G&&k(e),G&&k(l),G&&k(n)}}}function Ea(t){let e,l=me(t[1].h.c,2)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].h.c,2)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function Ia(t){let e,l=me(t[1].d.c,1)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].d.c,1)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function Fa(t){let e,l=me(t[1].m.c)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].m.c)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function Ra(t){let e,l=me(t[0].last_month.c)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&1&&l!==(l=me(r[0].last_month.c)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function La(t){let e,l=me(t[1].h.i,2)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].h.i,2)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function Oa(t){let e,l=me(t[1].d.i,1)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].d.i,1)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function qa(t){let e,l=me(t[1].m.i)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&2&&l!==(l=me(r[1].m.i)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function Ua(t){let e,l=me(t[0].last_month.i)+"",n,i,o;return{c(){e=m("div"),n=y(l),i=h(),o=y(t[2]),u(e,"class","text-right")},m(r,a){w(r,e,a),s(e,n),s(e,i),s(e,o)},p(r,a){a&1&&l!==(l=me(r[0].last_month.i)+"")&&W(n,l),a&4&&W(o,r[2])},d(r){r&&k(e)}}}function bp(t){let e,l,n,i,o,r,a=t[1]&&Da(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Real time calculation",n=h(),i=m("br"),o=m("br"),r=h(),a&&a.c(),u(e,"class","mx-2 text-sm")},m(c,f){w(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),s(e,r),a&&a.m(e,null)},p(c,[f]){c[1]?a?a.p(c,f):(a=Da(c),a.c(),a.m(e,null)):a&&(a.d(1),a=null)},i:ne,o:ne,d(c){c&&k(e),a&&a.d()}}}function gp(t,e,l){let{sysinfo:n}=e,{data:i}=e,{currency:o}=e,{hasExport:r}=e,a=!1,c=3;return t.$$set=f=>{"sysinfo"in f&&l(0,n=f.sysinfo),"data"in f&&l(1,i=f.data),"currency"in f&&l(2,o=f.currency),"hasExport"in f&&l(3,r=f.hasExport)},t.$$.update=()=>{t.$$.dirty&18&&(l(4,a=i&&i.h&&(Math.abs(i.h.c)>.01||Math.abs(i.d.c)>.01||Math.abs(i.m.c)>.01||Math.abs(i.h.i)>.01||Math.abs(i.d.i)>.01||Math.abs(i.m.i)>.01)),l(5,c=a?3:2))},[n,i,o,r,a,c]}class kp extends Me{constructor(e){super(),Se(this,e,gp,bp,we,{sysinfo:0,data:1,currency:2,hasExport:3})}}function wp(t){let e,l,n=ea(t[0].source)+"",i,o,r,a;return r=new pn({props:{config:t[1]}}),{c(){e=m("a"),l=y("Provided by: "),i=y(n),o=h(),Z(r.$$.fragment),u(e,"href","https://transparency.entsoe.eu/"),u(e,"target","_blank"),u(e,"class","text-xs float-right z-40")},m(c,f){w(c,e,f),s(e,l),s(e,i),w(c,o,f),Q(r,c,f),a=!0},p(c,[f]){(!a||f&1)&&n!==(n=ea(c[0].source)+"")&&W(i,n);const p={};f&2&&(p.config=c[1]),r.$set(p)},i(c){a||(P(r.$$.fragment,c),a=!0)},o(c){I(r.$$.fragment,c),a=!1},d(c){c&&k(e),c&&k(o),X(r,c)}}}function yp(t,e,l){let{json:n}=e,{sysinfo:i}=e,o={},r,a;return t.$$set=c=>{"json"in c&&l(0,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&29){let c=n.currency,f=new Date().getUTCHours(),p=0,_=0,b=0,d=[],v=[],g=[];l(4,a=l(3,r=0));let T=new Date;for(fl(T,i.clock_offset-(24+T.getHours()-T.getUTCHours())%24),p=f;p<24&&(_=n[Ie(b++)],_!=null);p++)v.push({label:Ie(T.getHours())}),g.push(_*100),l(4,a=Math.min(a,_*100)),l(3,r=Math.max(r,_*100)),fl(T,1);for(p=0;p<24&&(_=n[Ie(b++)],_!=null);p++)v.push({label:Ie(T.getHours())}),g.push(_*100),l(4,a=Math.min(a,_*100)),l(3,r=Math.max(r,_*100)),fl(T,1);if(a>-100&&r<100){switch(c){case"NOK":case"SEK":case"DKK":c="øre";break;case"EUR":c="cent";break;default:c=c+"/100"}for(l(4,a*=100),l(3,r*=100),p=0;p=0?S.toFixed(D):"",title:S>=0?S.toFixed(2)+" "+c:"",value:_>=0?Math.abs(_):0,label2:S<0?S.toFixed(D):"",title2:S<0?S.toFixed(2)+" "+c:"",value2:_<0?Math.abs(_):0,color:"#7c3aed"})}let $=Math.max(r,Math.abs(a));if(a<0){l(4,a=Math.min($/4*-1,a));let S=Math.ceil(Math.abs(a)/$*4),D=a/S;for(p=1;p{"json"in c&&l(1,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&30){let c=0,f=[],p=[],_=[];l(4,a=l(3,r=0));let b=fl(new Date,-24),d=new Date().getUTCHours();for(fl(b,i.clock_offset-(24+b.getHours()-b.getUTCHours())%24),c=d;c<24;c++){let C=n["i"+Ie(c)],$=n["e"+Ie(c)];C===void 0&&(C=0),$===void 0&&($=0),p.push({label:Ie(b.getHours())}),_.push({label:C.toFixed(1),title:C.toFixed(2)+" kWh",value:C*10,label2:$.toFixed(1),title2:$.toFixed(2)+" kWh",value2:$*10,color:"#7c3aed",color2:"#37829E"}),l(4,a=Math.max(a,$*10)),l(3,r=Math.max(r,C*10)),fl(b,1)}for(c=0;c{"json"in c&&l(1,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&30){let c=0,f=[],p=[],_=[];l(4,a=l(3,r=0));let b=new Date,d=new Date;for(fl(b,i.clock_offset-(24+b.getHours()-b.getUTCHours())%24),fl(d,i.clock_offset-(24+d.getHours()-d.getUTCHours())%24),d.setDate(0),c=b.getDate();c<=d.getDate();c++){let C=n["i"+Ie(c)],$=n["e"+Ie(c)];C===void 0&&(C=0),$===void 0&&($=0),p.push({label:Ie(c)}),_.push({label:C.toFixed(C<10?1:0),title:C.toFixed(2)+" kWh",value:C,label2:$.toFixed($<10?1:0),title2:$.toFixed(2)+" kWh",value2:$,color:"#7c3aed",color2:"#37829E"}),l(4,a=Math.max(a,$)),l(3,r=Math.max(r,C))}for(c=1;c{"json"in a&&l(1,n=a.json)},t.$$.update=()=>{if(t.$$.dirty&14){let a=0,c=0,f=[],p=[],_=[];n.s&&n.s.forEach((v,g)=>{var T=v.n?v.n:v.a;c=v.v,c==-127&&(c=0),p.push({label:T.slice(-4)}),_.push({label:c.toFixed(1),value:c,color:"#7c3aed"}),l(3,r=Math.min(r,c)),l(2,o=Math.max(o,c))}),l(2,o=Math.ceil(o)),l(3,r=Math.floor(r));let b=o;r<0&&(b+=Math.abs(r));let d=b/4;for(a=0;a<5;a++)c=r+d*a,f.push({value:c,label:c.toFixed(1)});l(0,i={title:"Temperature sensors (°C)",height:226,width:1520,padding:{top:20,right:15,bottom:20,left:35},y:{min:r,max:o,ticks:f},x:{ticks:p},points:_})}},[i,n,o,r]}class Ep extends Me{constructor(e){super(),Se(this,e,Ap,Dp,we,{json:1})}}function Ip(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}let Fp=0;function Rp(t,e,l){let n={},i=0,o;return Hc.subscribe(r=>{l(2,o=r)}),Uc(),t.$$.update=()=>{if(t.$$.dirty&6){let r=0,a=[],c=[],f=[];if(a.push({value:0,label:0}),o&&o.p)for(r=0;r0?Ie(p.d)+"."+no[new Date().getMonth()]:"-"}),l(1,i=Math.max(i,p.v))}if(o&&o.t){for(r=0;r=i)break;a.push({value:p,label:p})}a.push({label:o.m.toFixed(1),align:"right",color:"green",value:o.m})}o&&o.c&&(a.push({label:o.c.toFixed(0),color:"orange",value:o.c}),l(1,i=Math.max(i,o.c))),l(1,i=Math.ceil(i)),l(0,n={title:"Tariff peaks",padding:{top:20,right:35,bottom:20,left:35},y:{min:Fp,max:i,ticks:a},x:{ticks:c},points:f})}},[n,i,o]}class Lp extends Me{constructor(e){super(),Se(this,e,Rp,Ip,we,{})}}function Ha(t){let e,l,n,i,o,r,a=(t[0].mt?Ts(t[0].mt):"-")+"",c,f,p,_=(t[0].ic?t[0].ic.toFixed(1):"-")+"",b,d,v;return i=new zc({props:{val:t[0].i?t[0].i:0,max:t[0].im?t[0].im:15e3,unit:"W",label:"Import",sub:t[0].p,subunit:t[0].pc,colorFn:Ec}}),{c(){e=m("div"),l=m("div"),n=m("div"),Z(i.$$.fragment),o=h(),r=m("div"),c=y(a),f=h(),p=m("div"),b=y(_),d=y(" kWh"),u(n,"class","col-span-2"),u(p,"class","text-right"),u(l,"class","grid grid-cols-2"),u(e,"class","cnt")},m(g,T){w(g,e,T),s(e,l),s(l,n),Q(i,n,null),s(l,o),s(l,r),s(r,c),s(l,f),s(l,p),s(p,b),s(p,d),v=!0},p(g,T){const C={};T&1&&(C.val=g[0].i?g[0].i:0),T&1&&(C.max=g[0].im?g[0].im:15e3),T&1&&(C.sub=g[0].p),T&1&&(C.subunit=g[0].pc),i.$set(C),(!v||T&1)&&a!==(a=(g[0].mt?Ts(g[0].mt):"-")+"")&&W(c,a),(!v||T&1)&&_!==(_=(g[0].ic?g[0].ic.toFixed(1):"-")+"")&&W(b,_)},i(g){v||(P(i.$$.fragment,g),v=!0)},o(g){I(i.$$.fragment,g),v=!1},d(g){g&&k(e),X(i)}}}function ja(t){let e,l,n,i,o,r,a,c,f=(t[0].ec?t[0].ec.toFixed(1):"-")+"",p,_,b;return i=new zc({props:{val:t[0].e?t[0].e:0,max:t[0].om?t[0].om*1e3:1e4,unit:"W",label:"Export",colorFn:gm}}),{c(){e=m("div"),l=m("div"),n=m("div"),Z(i.$$.fragment),o=h(),r=m("div"),a=h(),c=m("div"),p=y(f),_=y(" kWh"),u(n,"class","col-span-2"),u(c,"class","text-right"),u(l,"class","grid grid-cols-2"),u(e,"class","cnt")},m(d,v){w(d,e,v),s(e,l),s(l,n),Q(i,n,null),s(l,o),s(l,r),s(l,a),s(l,c),s(c,p),s(c,_),b=!0},p(d,v){const g={};v&1&&(g.val=d[0].e?d[0].e:0),v&1&&(g.max=d[0].om?d[0].om*1e3:1e4),i.$set(g),(!b||v&1)&&f!==(f=(d[0].ec?d[0].ec.toFixed(1):"-")+"")&&W(p,f)},i(d){b||(P(i.$$.fragment,d),b=!0)},o(d){I(i.$$.fragment,d),b=!1},d(d){d&&k(e),X(i)}}}function Wa(t){let e,l,n;return l=new ap({props:{u1:t[0].u1,u2:t[0].u2,u3:t[0].u3,ds:t[0].ds}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&1&&(r.u1=i[0].u1),o&1&&(r.u2=i[0].u2),o&1&&(r.u3=i[0].u3),o&1&&(r.ds=i[0].ds),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Ga(t){let e,l,n;return l=new mp({props:{u1:t[0].u1,u2:t[0].u2,u3:t[0].u3,i1:t[0].i1,i2:t[0].i2,i3:t[0].i3,max:t[0].mf?t[0].mf:32}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&1&&(r.u1=i[0].u1),o&1&&(r.u2=i[0].u2),o&1&&(r.u3=i[0].u3),o&1&&(r.i1=i[0].i1),o&1&&(r.i2=i[0].i2),o&1&&(r.i3=i[0].i3),o&1&&(r.max=i[0].mf?i[0].mf:32),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Ba(t){let e,l,n;return l=new dp({props:{importInstant:t[0].ri,exportInstant:t[0].re,importTotal:t[0].ric,exportTotal:t[0].rec}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&1&&(r.importInstant=i[0].ri),o&1&&(r.exportInstant=i[0].re),o&1&&(r.importTotal=i[0].ric),o&1&&(r.exportTotal=i[0].rec),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function za(t){let e,l,n;return l=new kp({props:{sysinfo:t[1],data:t[0].ea,currency:t[0].pc,hasExport:t[0].om>0||t[0].e>0}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&2&&(r.sysinfo=i[1]),o&1&&(r.data=i[0].ea),o&1&&(r.currency=i[0].pc),o&1&&(r.hasExport=i[0].om>0||i[0].e>0),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Ya(t){let e,l,n;return l=new Lp({}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt h-64")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Ka(t){let e,l,n;return l=new $p({props:{json:t[2],sysinfo:t[1]}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt gwf")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&4&&(r.json=i[2]),o&2&&(r.sysinfo=i[1]),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Va(t){let e,l,n;return l=new Sp({props:{json:t[3],sysinfo:t[1]}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt gwf")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&8&&(r.json=i[3]),o&2&&(r.sysinfo=i[1]),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Qa(t){let e,l,n;return l=new Np({props:{json:t[4],sysinfo:t[1]}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt gwf")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&16&&(r.json=i[4]),o&2&&(r.sysinfo=i[1]),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Xa(t){let e,l,n;return l=new Ep({props:{json:t[5]}}),{c(){e=m("div"),Z(l.$$.fragment),u(e,"class","cnt gwf")},m(i,o){w(i,e,o),Q(l,e,null),n=!0},p(i,o){const r={};o&32&&(r.json=i[5]),l.$set(r)},i(i){n||(P(l.$$.fragment,i),n=!0)},o(i){I(l.$$.fragment,i),n=!1},d(i){i&&k(e),X(l)}}}function Op(t){let e,l=Ye(t[1].ui.i,t[0].i),n,i=Ye(t[1].ui.e,t[0].om||t[0].e>0),o,r=Ye(t[1].ui.v,t[0].u1>100||t[0].u2>100||t[0].u3>100),a,c=Ye(t[1].ui.a,t[0].i1>.01||t[0].i2>.01||t[0].i3>.01),f,p=Ye(t[1].ui.r,t[0].ri>0||t[0].re>0||t[0].ric>0||t[0].rec>0),_,b=Ye(t[1].ui.c,t[0].ea),d,v=Ye(t[1].ui.t,t[0].pr&&(t[0].pr.startsWith("10YNO")||t[0].pr=="10Y1001A1001A48H")),g,T=Ye(t[1].ui.p,t[0].pe&&!Number.isNaN(t[0].p)),C,$=Ye(t[1].ui.d,t[3]),M,F=Ye(t[1].ui.m,t[4]),S,D=Ye(t[1].ui.s,t[0].t&&t[0].t!=-127&&t[5].c>1),A,E=l&&Ha(t),Y=i&&ja(t),R=r&&Wa(t),U=c&&Ga(t),H=p&&Ba(t),z=b&&za(t),q=v&&Ya(),L=T&&Ka(t),B=$&&Va(t),O=F&&Qa(t),j=D&&Xa(t);return{c(){e=m("div"),E&&E.c(),n=h(),Y&&Y.c(),o=h(),R&&R.c(),a=h(),U&&U.c(),f=h(),H&&H.c(),_=h(),z&&z.c(),d=h(),q&&q.c(),g=h(),L&&L.c(),C=h(),B&&B.c(),M=h(),O&&O.c(),S=h(),j&&j.c(),u(e,"class","grid 2xl:grid-cols-6 xl:grid-cols-5 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2")},m(G,te){w(G,e,te),E&&E.m(e,null),s(e,n),Y&&Y.m(e,null),s(e,o),R&&R.m(e,null),s(e,a),U&&U.m(e,null),s(e,f),H&&H.m(e,null),s(e,_),z&&z.m(e,null),s(e,d),q&&q.m(e,null),s(e,g),L&&L.m(e,null),s(e,C),B&&B.m(e,null),s(e,M),O&&O.m(e,null),s(e,S),j&&j.m(e,null),A=!0},p(G,[te]){te&3&&(l=Ye(G[1].ui.i,G[0].i)),l?E?(E.p(G,te),te&3&&P(E,1)):(E=Ha(G),E.c(),P(E,1),E.m(e,n)):E&&(Ae(),I(E,1,1,()=>{E=null}),Ee()),te&3&&(i=Ye(G[1].ui.e,G[0].om||G[0].e>0)),i?Y?(Y.p(G,te),te&3&&P(Y,1)):(Y=ja(G),Y.c(),P(Y,1),Y.m(e,o)):Y&&(Ae(),I(Y,1,1,()=>{Y=null}),Ee()),te&3&&(r=Ye(G[1].ui.v,G[0].u1>100||G[0].u2>100||G[0].u3>100)),r?R?(R.p(G,te),te&3&&P(R,1)):(R=Wa(G),R.c(),P(R,1),R.m(e,a)):R&&(Ae(),I(R,1,1,()=>{R=null}),Ee()),te&3&&(c=Ye(G[1].ui.a,G[0].i1>.01||G[0].i2>.01||G[0].i3>.01)),c?U?(U.p(G,te),te&3&&P(U,1)):(U=Ga(G),U.c(),P(U,1),U.m(e,f)):U&&(Ae(),I(U,1,1,()=>{U=null}),Ee()),te&3&&(p=Ye(G[1].ui.r,G[0].ri>0||G[0].re>0||G[0].ric>0||G[0].rec>0)),p?H?(H.p(G,te),te&3&&P(H,1)):(H=Ba(G),H.c(),P(H,1),H.m(e,_)):H&&(Ae(),I(H,1,1,()=>{H=null}),Ee()),te&3&&(b=Ye(G[1].ui.c,G[0].ea)),b?z?(z.p(G,te),te&3&&P(z,1)):(z=za(G),z.c(),P(z,1),z.m(e,d)):z&&(Ae(),I(z,1,1,()=>{z=null}),Ee()),te&3&&(v=Ye(G[1].ui.t,G[0].pr&&(G[0].pr.startsWith("10YNO")||G[0].pr=="10Y1001A1001A48H"))),v?q?te&3&&P(q,1):(q=Ya(),q.c(),P(q,1),q.m(e,g)):q&&(Ae(),I(q,1,1,()=>{q=null}),Ee()),te&3&&(T=Ye(G[1].ui.p,G[0].pe&&!Number.isNaN(G[0].p))),T?L?(L.p(G,te),te&3&&P(L,1)):(L=Ka(G),L.c(),P(L,1),L.m(e,C)):L&&(Ae(),I(L,1,1,()=>{L=null}),Ee()),te&10&&($=Ye(G[1].ui.d,G[3])),$?B?(B.p(G,te),te&10&&P(B,1)):(B=Va(G),B.c(),P(B,1),B.m(e,M)):B&&(Ae(),I(B,1,1,()=>{B=null}),Ee()),te&18&&(F=Ye(G[1].ui.m,G[4])),F?O?(O.p(G,te),te&18&&P(O,1)):(O=Qa(G),O.c(),P(O,1),O.m(e,S)):O&&(Ae(),I(O,1,1,()=>{O=null}),Ee()),te&35&&(D=Ye(G[1].ui.s,G[0].t&&G[0].t!=-127&&G[5].c>1)),D?j?(j.p(G,te),te&35&&P(j,1)):(j=Xa(G),j.c(),P(j,1),j.m(e,null)):j&&(Ae(),I(j,1,1,()=>{j=null}),Ee())},i(G){A||(P(E),P(Y),P(R),P(U),P(H),P(z),P(q),P(L),P(B),P(O),P(j),A=!0)},o(G){I(E),I(Y),I(R),I(U),I(H),I(z),I(q),I(L),I(B),I(O),I(j),A=!1},d(G){G&&k(e),E&&E.d(),Y&&Y.d(),R&&R.d(),U&&U.d(),H&&H.d(),z&&z.d(),q&&q.d(),L&&L.d(),B&&B.d(),O&&O.d(),j&&j.d()}}}function qp(t,e,l){let{data:n={}}=e,{sysinfo:i={}}=e,o={},r={},a={},c={};return $o.subscribe(f=>{l(2,o=f)}),Rc.subscribe(f=>{l(3,r=f)}),Lc.subscribe(f=>{l(4,a=f)}),qc.subscribe(f=>{l(5,c=f)}),t.$$set=f=>{"data"in f&&l(0,n=f.data),"sysinfo"in f&&l(1,i=f.sysinfo)},[n,i,o,r,a,c]}class Up extends Me{constructor(e){super(),Se(this,e,qp,Op,we,{data:0,sysinfo:1})}}let fo={};const $i=rt(fo);async function Hp(){fo=await(await fetch("/configuration.json")).json(),$i.set(fo)}function Za(t,e,l){const n=t.slice();return n[2]=e[l],n[4]=l,n}function jp(t){let e;return{c(){e=m("option"),e.textContent="UART0",e.__value=3,e.value=e.__value},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function Wp(t){let e;return{c(){e=m("option"),e.textContent="UART0",e.__value=20,e.value=e.__value},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function Ja(t){let e;return{c(){e=m("option"),e.textContent="UART2",e.__value=113,e.value=e.__value},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function xa(t){let e,l,n;return{c(){e=m("option"),e.textContent="UART1",l=h(),n=m("option"),n.textContent="UART2",e.__value=9,e.value=e.__value,n.__value=16,n.value=n.__value},m(i,o){w(i,e,o),w(i,l,o),w(i,n,o)},d(i){i&&k(e),i&&k(l),i&&k(n)}}}function ef(t){let e;return{c(){e=m("option"),e.textContent="UART1",e.__value=18,e.value=e.__value},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function tf(t){let e,l,n;return{c(){e=m("option"),l=y("GPIO"),n=y(t[4]),e.__value=t[4],e.value=e.__value},m(i,o){w(i,e,o),s(e,l),s(e,n)},d(i){i&&k(e)}}}function lf(t){let e,l=t[4]>3&&!(t[0]=="esp32"&&(t[4]==9||t[4]==16))&&!(t[0]=="esp32s2"&&t[4]==18)&&!(t[0]=="esp8266"&&(t[4]==3||t[4]==113))&&tf(t);return{c(){l&&l.c(),e=Ke()},m(n,i){l&&l.m(n,i),w(n,e,i)},p(n,i){n[4]>3&&!(n[0]=="esp32"&&(n[4]==9||n[4]==16))&&!(n[0]=="esp32s2"&&n[4]==18)&&!(n[0]=="esp8266"&&(n[4]==3||n[4]==113))?l||(l=tf(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},d(n){l&&l.d(n),n&&k(e)}}}function Gp(t){let e,l,n,i,o;function r(v,g){return v[0]=="esp32c3"?Wp:jp}let a=r(t),c=a(t),f=t[0]=="esp8266"&&Ja(),p=(t[0]=="esp32"||t[0]=="esp32solo")&&xa(),_=t[0]=="esp32s2"&&ef(),b={length:t[1]+1},d=[];for(let v=0;v{"chip"in o&&l(0,n=o.chip)},t.$$.update=()=>{if(t.$$.dirty&1)switch(n){case"esp8266":l(1,i=16);break;case"esp32s2":l(1,i=44);break;case"esp32c3":l(1,i=19);break}},[n,i]}class Yc extends Me{constructor(e){super(),Se(this,e,Bp,Gp,we,{chip:0})}}function nf(t){let e,l,n=t[1]&&sf(t);return{c(){e=m("div"),l=m("div"),n&&n.c(),u(l,"class","fixed inset-0 bg-gray-500 bg-opacity-50 flex items-center justify-center"),u(e,"class","z-50"),u(e,"aria-modal","true")},m(i,o){w(i,e,o),s(e,l),n&&n.m(l,null)},p(i,o){i[1]?n?n.p(i,o):(n=sf(i),n.c(),n.m(l,null)):n&&(n.d(1),n=null)},d(i){i&&k(e),n&&n.d()}}}function sf(t){let e,l;return{c(){e=m("div"),l=y(t[1]),u(e,"class","bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700 w-96")},m(n,i){w(n,e,i),s(e,l)},p(n,i){i&2&&W(l,n[1])},d(n){n&&k(e)}}}function zp(t){let e,l=t[0]&&nf(t);return{c(){l&&l.c(),e=Ke()},m(n,i){l&&l.m(n,i),w(n,e,i)},p(n,[i]){n[0]?l?l.p(n,i):(l=nf(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},i:ne,o:ne,d(n){l&&l.d(n),n&&k(e)}}}function Yp(t,e,l){let{active:n}=e,{message:i}=e;return t.$$set=o=>{"active"in o&&l(0,n=o.active),"message"in o&&l(1,i=o.message)},[n,i]}class Et extends Me{constructor(e){super(),Se(this,e,Yp,zp,we,{active:0,message:1})}}function of(t,e,l){const n=t.slice();return n[1]=e[l],n}function uf(t){let e,l,n=t[1]+"",i;return{c(){e=m("option"),l=y("Europe/"),i=y(n),e.__value="Europe/"+t[1],e.value=e.__value},m(o,r){w(o,e,r),s(e,l),s(e,i)},p:ne,d(o){o&&k(e)}}}function Kp(t){let e,l,n,i=t[0],o=[];for(let r=0;r{g[Y]=null}),Ee(),i=g[n],i?i.p(A,E):(i=g[n]=v[n](A),i.c()),P(i,1),i.m(l,null));let R=a;a=M(A),a===R?$[a].p(A,E):(Ae(),I($[R],1,1,()=>{$[R]=null}),Ee(),c=$[a],c?c.p(A,E):(c=$[a]=C[a](A),c.c()),P(c,1),c.m(r,null));let U=_;_=D(A),_===U?S[_].p(A,E):(Ae(),I(S[U],1,1,()=>{S[U]=null}),Ee(),b=S[_],b?b.p(A,E):(b=S[_]=F[_](A),b.c()),P(b,1),b.m(p,null))},i(A){d||(P(i),P(c),P(b),d=!0)},o(A){I(i),I(c),I(b),d=!1},d(A){A&&k(e),g[n].d(),$[a].d(),S[_].d()}}}function l0(t){let e,l;return e=new el({props:{to:"/mqtt-ca",$$slots:{default:[i0]},$$scope:{ctx:t}}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i[3]&16384&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function n0(t){let e,l,n,i,o,r,a,c;return l=new el({props:{to:"/mqtt-ca",$$slots:{default:[s0]},$$scope:{ctx:t}}}),o=new Mo({}),{c(){e=m("span"),Z(l.$$.fragment),n=h(),i=m("span"),Z(o.$$.fragment),u(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),u(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){w(f,e,p),Q(l,e,null),w(f,n,p),w(f,i,p),Q(o,i,null),r=!0,a||(c=[K(i,"click",t[11]),K(i,"keypress",t[11])],a=!0)},p(f,p){const _={};p[3]&16384&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){r||(P(l.$$.fragment,f),P(o.$$.fragment,f),r=!0)},o(f){I(l.$$.fragment,f),I(o.$$.fragment,f),r=!1},d(f){f&&k(e),X(l),f&&k(n),f&&k(i),X(o),a=!1,Be(c)}}}function i0(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload CA",title:"Click here to upload CA"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function s0(t){let e;return{c(){e=y("CA OK")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function o0(t){let e,l;return e=new el({props:{to:"/mqtt-cert",$$slots:{default:[r0]},$$scope:{ctx:t}}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i[3]&16384&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function u0(t){let e,l,n,i,o,r,a,c;return l=new el({props:{to:"/mqtt-cert",$$slots:{default:[a0]},$$scope:{ctx:t}}}),o=new Mo({}),{c(){e=m("span"),Z(l.$$.fragment),n=h(),i=m("span"),Z(o.$$.fragment),u(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),u(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){w(f,e,p),Q(l,e,null),w(f,n,p),w(f,i,p),Q(o,i,null),r=!0,a||(c=[K(i,"click",t[12]),K(i,"keypress",t[12])],a=!0)},p(f,p){const _={};p[3]&16384&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){r||(P(l.$$.fragment,f),P(o.$$.fragment,f),r=!0)},o(f){I(l.$$.fragment,f),I(o.$$.fragment,f),r=!1},d(f){f&&k(e),X(l),f&&k(n),f&&k(i),X(o),a=!1,Be(c)}}}function r0(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload cert",title:"Click here to upload certificate"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function a0(t){let e;return{c(){e=y("Cert OK")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function f0(t){let e,l;return e=new el({props:{to:"/mqtt-key",$$slots:{default:[m0]},$$scope:{ctx:t}}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i[3]&16384&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function c0(t){let e,l,n,i,o,r,a,c;return l=new el({props:{to:"/mqtt-key",$$slots:{default:[p0]},$$scope:{ctx:t}}}),o=new Mo({}),{c(){e=m("span"),Z(l.$$.fragment),n=h(),i=m("span"),Z(o.$$.fragment),u(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),u(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){w(f,e,p),Q(l,e,null),w(f,n,p),w(f,i,p),Q(o,i,null),r=!0,a||(c=[K(i,"click",t[13]),K(i,"keypress",t[13])],a=!0)},p(f,p){const _={};p[3]&16384&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){r||(P(l.$$.fragment,f),P(o.$$.fragment,f),r=!0)},o(f){I(l.$$.fragment,f),I(o.$$.fragment,f),r=!1},d(f){f&&k(e),X(l),f&&k(n),f&&k(i),X(o),a=!1,Be(c)}}}function m0(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload key",title:"Click here to upload key"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function p0(t){let e;return{c(){e=y("Key OK")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function bf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q,L,B;return o=new qt({}),{c(){e=m("div"),l=m("strong"),l.textContent="Domoticz",n=h(),i=m("a"),Z(o.$$.fragment),r=h(),a=m("input"),c=h(),f=m("div"),p=m("div"),_=y("Electricity IDX"),b=m("br"),d=h(),v=m("input"),g=h(),T=m("div"),C=y("Current IDX"),$=m("br"),M=h(),F=m("input"),S=h(),D=m("div"),A=y(`Voltage IDX: L1, L2 & L3 - `),E=m("div"),Y=m("input"),R=h(),U=m("input"),H=h(),z=m("input"),u(l,"class","text-sm"),u(i,"href",Ut("MQTT-configuration#domoticz")),u(i,"target","_blank"),u(i,"class","float-right"),u(a,"type","hidden"),u(a,"name","o"),a.value="true",u(v,"name","oe"),u(v,"type","text"),u(v,"class","in-f tr w-full"),u(p,"class","w-1/2"),u(F,"name","oc"),u(F,"type","text"),u(F,"class","in-l tr w-full"),u(T,"class","w-1/2"),u(f,"class","my-1 flex"),u(Y,"name","ou1"),u(Y,"type","text"),u(Y,"class","in-f tr w-1/3"),u(U,"name","ou2"),u(U,"type","text"),u(U,"class","in-m tr w-1/3"),u(z,"name","ou3"),u(z,"type","text"),u(z,"class","in-l tr w-1/3"),u(E,"class","flex"),u(D,"class","my-1"),u(e,"class","cnt")},m(O,j){w(O,e,j),s(e,l),s(e,n),s(e,i),Q(o,i,null),s(e,r),s(e,a),s(e,c),s(e,f),s(f,p),s(p,_),s(p,b),s(p,d),s(p,v),V(v,t[3].o.e),s(f,g),s(f,T),s(T,C),s(T,$),s(T,M),s(T,F),V(F,t[3].o.c),s(e,S),s(e,D),s(D,A),s(D,E),s(E,Y),V(Y,t[3].o.u1),s(E,R),s(E,U),V(U,t[3].o.u2),s(E,H),s(E,z),V(z,t[3].o.u3),q=!0,L||(B=[K(v,"input",t[64]),K(F,"input",t[65]),K(Y,"input",t[66]),K(U,"input",t[67]),K(z,"input",t[68])],L=!0)},p(O,j){j[0]&8&&v.value!==O[3].o.e&&V(v,O[3].o.e),j[0]&8&&F.value!==O[3].o.c&&V(F,O[3].o.c),j[0]&8&&Y.value!==O[3].o.u1&&V(Y,O[3].o.u1),j[0]&8&&U.value!==O[3].o.u2&&V(U,O[3].o.u2),j[0]&8&&z.value!==O[3].o.u3&&V(z,O[3].o.u3)},i(O){q||(P(o.$$.fragment,O),q=!0)},o(O){I(o.$$.fragment,O),q=!1},d(O){O&&k(e),X(o),L=!1,Be(B)}}}function gf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z;return o=new qt({}),{c(){e=m("div"),l=m("strong"),l.textContent="Home-Assistant",n=h(),i=m("a"),Z(o.$$.fragment),r=h(),a=m("input"),c=h(),f=m("div"),p=y("Discovery topic prefix"),_=m("br"),b=h(),d=m("input"),v=h(),g=m("div"),T=y("Hostname for URL"),C=m("br"),$=h(),M=m("input"),S=h(),D=m("div"),A=y("Name tag"),E=m("br"),Y=h(),R=m("input"),u(l,"class","text-sm"),u(i,"href",Ut("MQTT-configuration#home-assistant")),u(i,"target","_blank"),u(i,"class","float-right"),u(a,"type","hidden"),u(a,"name","h"),a.value="true",u(d,"name","ht"),u(d,"type","text"),u(d,"class","in-s"),u(d,"placeholder","homeassistant"),u(f,"class","my-1"),u(M,"name","hh"),u(M,"type","text"),u(M,"class","in-s"),u(M,"placeholder",F=t[3].g.h+".local"),u(g,"class","my-1"),u(R,"name","hn"),u(R,"type","text"),u(R,"class","in-s"),u(D,"class","my-1"),u(e,"class","cnt")},m(q,L){w(q,e,L),s(e,l),s(e,n),s(e,i),Q(o,i,null),s(e,r),s(e,a),s(e,c),s(e,f),s(f,p),s(f,_),s(f,b),s(f,d),V(d,t[3].h.t),s(e,v),s(e,g),s(g,T),s(g,C),s(g,$),s(g,M),V(M,t[3].h.h),s(e,S),s(e,D),s(D,A),s(D,E),s(D,Y),s(D,R),V(R,t[3].h.n),U=!0,H||(z=[K(d,"input",t[69]),K(M,"input",t[70]),K(R,"input",t[71])],H=!0)},p(q,L){L[0]&8&&d.value!==q[3].h.t&&V(d,q[3].h.t),(!U||L[0]&8&&F!==(F=q[3].g.h+".local"))&&u(M,"placeholder",F),L[0]&8&&M.value!==q[3].h.h&&V(M,q[3].h.h),L[0]&8&&R.value!==q[3].h.n&&V(R,q[3].h.n)},i(q){U||(P(o.$$.fragment,q),U=!0)},o(q){I(o.$$.fragment,q),U=!1},d(q){q&&k(e),X(o),H=!1,Be(z)}}}function kf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M;o=new qt({});let F={length:9},S=[];for(let D=0;D20&&Cf(t),p=t[0].chip=="esp8266"&&Mf(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Hardware",n=h(),i=m("a"),Z(o.$$.fragment),r=h(),f&&f.c(),a=h(),p&&p.c(),u(l,"class","text-sm"),u(i,"href",Ut("GPIO-configuration")),u(i,"target","_blank"),u(i,"class","float-right"),u(e,"class","cnt")},m(_,b){w(_,e,b),s(e,l),s(e,n),s(e,i),Q(o,i,null),s(e,r),f&&f.m(e,null),s(e,a),p&&p.m(e,null),c=!0},p(_,b){_[0].board>20?f?(f.p(_,b),b[0]&1&&P(f,1)):(f=Cf(_),f.c(),P(f,1),f.m(e,a)):f&&(Ae(),I(f,1,1,()=>{f=null}),Ee()),_[0].chip=="esp8266"?p?p.p(_,b):(p=Mf(_),p.c(),p.m(e,null)):p&&(p.d(1),p=null)},i(_){c||(P(o.$$.fragment,_),P(f),c=!0)},o(_){I(o.$$.fragment,_),I(f),c=!1},d(_){_&&k(e),X(o),f&&f.d(),p&&p.d()}}}function Cf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q,L,B,O,j,G,te,le,pe,ie,Pe,je,De,We,be,ye,Re,ge,ae,$e,J,se,Fe,Le,_e,Ce,Ne,de,Te,ee;b=new Yc({props:{chip:t[0].chip}});let oe=t[0].chip!="esp8266"&&Tf(t),Ue=t[3].i.v.p>0&&Sf(t);return{c(){e=m("input"),l=h(),n=m("div"),i=m("div"),o=y("HAN"),r=m("label"),a=m("input"),c=y(" pullup"),f=m("br"),p=h(),_=m("select"),Z(b.$$.fragment),d=h(),v=m("div"),g=y("AP button"),T=m("br"),C=h(),$=m("input"),M=h(),F=m("div"),S=y("LED"),D=m("label"),A=m("input"),E=y(" inv"),Y=m("br"),R=h(),U=m("div"),H=m("input"),z=h(),q=m("div"),L=y("RGB"),B=m("label"),O=m("input"),j=y(" inverted"),G=m("br"),te=h(),le=m("div"),pe=m("input"),ie=h(),Pe=m("input"),je=h(),De=m("input"),We=h(),be=m("div"),ye=y("Temperature"),Re=m("br"),ge=h(),ae=m("input"),$e=h(),J=m("div"),se=y("Analog temp"),Fe=m("br"),Le=h(),_e=m("input"),Ce=h(),oe&&oe.c(),Ne=h(),Ue&&Ue.c(),u(e,"type","hidden"),u(e,"name","i"),e.value="true",u(a,"name","ihu"),a.__value="true",a.value=a.__value,u(a,"type","checkbox"),u(a,"class","rounded mb-1"),u(r,"class","ml-2"),u(_,"name","ihp"),u(_,"class","in-f w-full"),t[3].i.h.p===void 0&&tt(()=>t[76].call(_)),u(i,"class","w-1/3"),u($,"name","ia"),u($,"type","number"),u($,"min","0"),u($,"max",t[6]),u($,"class","in-m tr w-full"),u(v,"class","w-1/3"),u(A,"name","ili"),A.__value="true",A.value=A.__value,u(A,"type","checkbox"),u(A,"class","rounded mb-1"),u(D,"class","ml-4"),u(H,"name","ilp"),u(H,"type","number"),u(H,"min","0"),u(H,"max",t[6]),u(H,"class","in-l tr w-full"),u(U,"class","flex"),u(F,"class","w-1/3"),u(O,"name","iri"),O.__value="true",O.value=O.__value,u(O,"type","checkbox"),u(O,"class","rounded mb-1"),u(B,"class","ml-4"),u(pe,"name","irr"),u(pe,"type","number"),u(pe,"min","0"),u(pe,"max",t[6]),u(pe,"class","in-f tr w-1/3"),u(Pe,"name","irg"),u(Pe,"type","number"),u(Pe,"min","0"),u(Pe,"max",t[6]),u(Pe,"class","in-m tr w-1/3"),u(De,"name","irb"),u(De,"type","number"),u(De,"min","0"),u(De,"max",t[6]),u(De,"class","in-l tr w-1/3"),u(le,"class","flex"),u(q,"class","w-full"),u(ae,"name","itd"),u(ae,"type","number"),u(ae,"min","0"),u(ae,"max",t[6]),u(ae,"class","in-f tr w-full"),u(be,"class","my-1 w-1/3"),u(_e,"name","ita"),u(_e,"type","number"),u(_e,"min","0"),u(_e,"max",t[6]),u(_e,"class","in-l tr w-full"),u(J,"class","my-1 pr-1 w-1/3"),u(n,"class","flex flex-wrap")},m(ue,ve){w(ue,e,ve),w(ue,l,ve),w(ue,n,ve),s(n,i),s(i,o),s(i,r),s(r,a),a.checked=t[3].i.h.u,s(r,c),s(i,f),s(i,p),s(i,_),Q(b,_,null),qe(_,t[3].i.h.p,!0),s(n,d),s(n,v),s(v,g),s(v,T),s(v,C),s(v,$),V($,t[3].i.a),s(n,M),s(n,F),s(F,S),s(F,D),s(D,A),A.checked=t[3].i.l.i,s(D,E),s(F,Y),s(F,R),s(F,U),s(U,H),V(H,t[3].i.l.p),s(n,z),s(n,q),s(q,L),s(q,B),s(B,O),O.checked=t[3].i.r.i,s(B,j),s(q,G),s(q,te),s(q,le),s(le,pe),V(pe,t[3].i.r.r),s(le,ie),s(le,Pe),V(Pe,t[3].i.r.g),s(le,je),s(le,De),V(De,t[3].i.r.b),s(n,We),s(n,be),s(be,ye),s(be,Re),s(be,ge),s(be,ae),V(ae,t[3].i.t.d),s(n,$e),s(n,J),s(J,se),s(J,Fe),s(J,Le),s(J,_e),V(_e,t[3].i.t.a),s(n,Ce),oe&&oe.m(n,null),s(n,Ne),Ue&&Ue.m(n,null),de=!0,Te||(ee=[K(a,"change",t[75]),K(_,"change",t[76]),K($,"input",t[77]),K(A,"change",t[78]),K(H,"input",t[79]),K(O,"change",t[80]),K(pe,"input",t[81]),K(Pe,"input",t[82]),K(De,"input",t[83]),K(ae,"input",t[84]),K(_e,"input",t[85])],Te=!0)},p(ue,ve){ve[0]&8&&(a.checked=ue[3].i.h.u);const dt={};ve[0]&1&&(dt.chip=ue[0].chip),b.$set(dt),ve[0]&8&&qe(_,ue[3].i.h.p),(!de||ve[0]&64)&&u($,"max",ue[6]),ve[0]&8&&fe($.value)!==ue[3].i.a&&V($,ue[3].i.a),ve[0]&8&&(A.checked=ue[3].i.l.i),(!de||ve[0]&64)&&u(H,"max",ue[6]),ve[0]&8&&fe(H.value)!==ue[3].i.l.p&&V(H,ue[3].i.l.p),ve[0]&8&&(O.checked=ue[3].i.r.i),(!de||ve[0]&64)&&u(pe,"max",ue[6]),ve[0]&8&&fe(pe.value)!==ue[3].i.r.r&&V(pe,ue[3].i.r.r),(!de||ve[0]&64)&&u(Pe,"max",ue[6]),ve[0]&8&&fe(Pe.value)!==ue[3].i.r.g&&V(Pe,ue[3].i.r.g),(!de||ve[0]&64)&&u(De,"max",ue[6]),ve[0]&8&&fe(De.value)!==ue[3].i.r.b&&V(De,ue[3].i.r.b),(!de||ve[0]&64)&&u(ae,"max",ue[6]),ve[0]&8&&fe(ae.value)!==ue[3].i.t.d&&V(ae,ue[3].i.t.d),(!de||ve[0]&64)&&u(_e,"max",ue[6]),ve[0]&8&&fe(_e.value)!==ue[3].i.t.a&&V(_e,ue[3].i.t.a),ue[0].chip!="esp8266"?oe?oe.p(ue,ve):(oe=Tf(ue),oe.c(),oe.m(n,Ne)):oe&&(oe.d(1),oe=null),ue[3].i.v.p>0?Ue?Ue.p(ue,ve):(Ue=Sf(ue),Ue.c(),Ue.m(n,null)):Ue&&(Ue.d(1),Ue=null)},i(ue){de||(P(b.$$.fragment,ue),de=!0)},o(ue){I(b.$$.fragment,ue),de=!1},d(ue){ue&&k(e),ue&&k(l),ue&&k(n),X(b),oe&&oe.d(),Ue&&Ue.d(),Te=!1,Be(ee)}}}function Tf(t){let e,l,n,i,o,r,a;return{c(){e=m("div"),l=y("Vcc"),n=m("br"),i=h(),o=m("input"),u(o,"name","ivp"),u(o,"type","number"),u(o,"min","0"),u(o,"max",t[6]),u(o,"class","in-s tr w-full"),u(e,"class","my-1 pl-1 w-1/3")},m(c,f){w(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),V(o,t[3].i.v.p),r||(a=K(o,"input",t[86]),r=!0)},p(c,f){f[0]&64&&u(o,"max",c[6]),f[0]&8&&fe(o.value)!==c[3].i.v.p&&V(o,c[3].i.v.p)},d(c){c&&k(e),r=!1,a()}}}function Sf(t){let e,l,n,i,o,r,a,c,f,p;return{c(){e=m("div"),l=y("Voltage divider"),n=m("br"),i=h(),o=m("div"),r=m("input"),a=h(),c=m("input"),u(r,"name","ivdv"),u(r,"type","number"),u(r,"min","0"),u(r,"max","65535"),u(r,"class","in-f tr w-full"),u(r,"placeholder","VCC"),u(c,"name","ivdg"),u(c,"type","number"),u(c,"min","0"),u(c,"max","65535"),u(c,"class","in-l tr w-full"),u(c,"placeholder","GND"),u(o,"class","flex"),u(e,"class","my-1")},m(_,b){w(_,e,b),s(e,l),s(e,n),s(e,i),s(e,o),s(o,r),V(r,t[3].i.v.d.v),s(o,a),s(o,c),V(c,t[3].i.v.d.g),f||(p=[K(r,"input",t[87]),K(c,"input",t[88])],f=!0)},p(_,b){b[0]&8&&fe(r.value)!==_[3].i.v.d.v&&V(r,_[3].i.v.d.v),b[0]&8&&fe(c.value)!==_[3].i.v.d.g&&V(c,_[3].i.v.d.g)},d(_){_&&k(e),f=!1,Be(p)}}}function Mf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$=(t[0].board==2||t[0].board==100)&&Pf(t);return{c(){e=m("input"),l=h(),n=m("div"),i=m("div"),o=y("Vcc offset"),r=m("br"),a=h(),c=m("input"),f=h(),p=m("div"),_=y("Multiplier"),b=m("br"),d=h(),v=m("input"),g=h(),$&&$.c(),u(e,"type","hidden"),u(e,"name","iv"),e.value="true",u(c,"name","ivo"),u(c,"type","number"),u(c,"min","0.0"),u(c,"max","3.5"),u(c,"step","0.01"),u(c,"class","in-f tr w-full"),u(i,"class","w-1/3"),u(v,"name","ivm"),u(v,"type","number"),u(v,"min","0.1"),u(v,"max","10"),u(v,"step","0.01"),u(v,"class","in-l tr w-full"),u(p,"class","w-1/3 pr-1"),u(n,"class","my-1 flex flex-wrap")},m(M,F){w(M,e,F),w(M,l,F),w(M,n,F),s(n,i),s(i,o),s(i,r),s(i,a),s(i,c),V(c,t[3].i.v.o),s(n,f),s(n,p),s(p,_),s(p,b),s(p,d),s(p,v),V(v,t[3].i.v.m),s(n,g),$&&$.m(n,null),T||(C=[K(c,"input",t[89]),K(v,"input",t[90])],T=!0)},p(M,F){F[0]&8&&fe(c.value)!==M[3].i.v.o&&V(c,M[3].i.v.o),F[0]&8&&fe(v.value)!==M[3].i.v.m&&V(v,M[3].i.v.m),M[0].board==2||M[0].board==100?$?$.p(M,F):($=Pf(M),$.c(),$.m(n,null)):$&&($.d(1),$=null)},d(M){M&&k(e),M&&k(l),M&&k(n),$&&$.d(),T=!1,Be(C)}}}function Pf(t){let e,l,n,i,o,r,a;return{c(){e=m("div"),l=y("Boot limit"),n=m("br"),i=h(),o=m("input"),u(o,"name","ivb"),u(o,"type","number"),u(o,"min","2.5"),u(o,"max","3.5"),u(o,"step","0.1"),u(o,"class","in-s tr w-full"),u(e,"class","w-1/3 pl-1")},m(c,f){w(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),V(o,t[3].i.v.b),r||(a=K(o,"input",t[91]),r=!0)},p(c,f){f[0]&8&&fe(o.value)!==c[3].i.v.b&&V(o,c[3].i.v.b)},d(c){c&&k(e),r=!1,a()}}}function Nf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C=t[3].d.t&&Df();return{c(){e=m("div"),e.textContent="Debug can cause sudden reboots. Do not leave on!",l=h(),n=m("div"),i=m("label"),o=m("input"),r=y(" Enable telnet"),a=h(),C&&C.c(),c=h(),f=m("div"),p=m("select"),_=m("option"),_.textContent="Verbose",b=m("option"),b.textContent="Debug",d=m("option"),d.textContent="Info",v=m("option"),v.textContent="Warning",u(e,"class","bd-red"),u(o,"type","checkbox"),u(o,"name","dt"),o.__value="true",o.value=o.__value,u(o,"class","rounded mb-1"),u(n,"class","my-1"),_.__value=1,_.value=_.__value,b.__value=2,b.value=b.__value,d.__value=3,d.value=d.__value,v.__value=4,v.value=v.__value,u(p,"name","dl"),u(p,"class","in-s"),t[3].d.l===void 0&&tt(()=>t[94].call(p)),u(f,"class","my-1")},m($,M){w($,e,M),w($,l,M),w($,n,M),s(n,i),s(i,o),o.checked=t[3].d.t,s(i,r),w($,a,M),C&&C.m($,M),w($,c,M),w($,f,M),s(f,p),s(p,_),s(p,b),s(p,d),s(p,v),qe(p,t[3].d.l,!0),g||(T=[K(o,"change",t[93]),K(p,"change",t[94])],g=!0)},p($,M){M[0]&8&&(o.checked=$[3].d.t),$[3].d.t?C||(C=Df(),C.c(),C.m(c.parentNode,c)):C&&(C.d(1),C=null),M[0]&8&&qe(p,$[3].d.l)},d($){$&&k(e),$&&k(l),$&&k(n),$&&k(a),C&&C.d($),$&&k(c),$&&k(f),g=!1,Be(T)}}}function Df(t){let e;return{c(){e=m("div"),e.textContent="Telnet is unsafe and should be off when not in use",u(e,"class","bd-red")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function _0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q,L,B,O,j,G,te,le,pe,ie,Pe,je,De,We,be,ye,Re,ge,ae,$e,J,se,Fe,Le,_e,Ce,Ne,de,Te,ee,oe,Ue,ue,ve,dt,Wl,tl,ct,Ml,pl,jt,vt,Qe,Xe,Ze,He,Je,Ge,xe,et,re,he,Ai,_l,_n,St,Ei,Ii,Fi,dl,Ri,Li,Oi,Mt,Pl,Nl,Dl,qi,ze,ke,vl,Ns,Al,It,Ui,Gl,No,ll,Hi,Do,Ds,Ao,ci,Wt,Eo,Io,El,nl,Il,Fo,ji,Ro,mt,Fl,Lo,Wi,dn,vn,hn,bn,Gi,Oo,Pt,Bi,qo,Bl,Uo,Ho,jo,il,gn,kn,Wo,wn,zl,Go,Bo,zo,yn,Gt,Yo,zi,Ko,Yl,Vo,Qo,Xo,$n,Bt,Zo,Yi,Jo,As,xo,Kl,Ki,zt,eu,tu,lu,Es,Vi,Yt,nu,iu,su,lt,Qi,ou,Cn,Tn,uu,mi,ru,Vl,au,fu,cu,hl,mu,Ql,pu,_u,du,bl,vu,Sn,Xl,hu,bu,gu,Ft,Mn,Pn,Nn,Dn,ku,Zl,wu,yu,$u,An,Rt,Cu,Xi,Tu,Zi,Ji,Kt,Su,Mu,xi,es,Vt,Pu,Nu,at,ts,Du,En,In,Au,Jl,Eu,Iu,Fu,Rl,sl,Fn,Rn,Ru,Nt,ls,ns,Lu,Dt,Ln,is,ss,Ou,Is,os,us,Qt,qu,Uu,pi,Hu,Ll,ju,_i,Xt,Wu,Gu,Bu,rs,gl,zu,Ve,as,Yu,On,qn,Ku,di,Vu,ol,Qu,Fs,Xu,Zu,Un,kl,Ju,Zt,xu,Rs,xl,er,tr,lr,wl,nr,en,ir,sr,or,yl,ur,Hn,jn,rr,ar,fr,$l,cr,Wn,mr,pr,_r,ht,Gn,Bn,zn,Yn,Kn,Vn,dr,tn,vr,hr,br,Cl,gr,Ls,Os,qs=t[3].p.r.startsWith("10YNO")||t[3].p.r=="10Y1001A1001A48H",Us,ul,fs,kr,Qn,Xn,wr,vi,yr,hi,$r,Hs,At,cs,Cr,Zn,Jn,Tr,bi,Sr,ms,ps,Jt,Mr,Pr,Nr,Ol,js,xn,Dr,_s,ei,Ar,ds,Ws,ln,Gs,nn,Bs,sn,zs,on,Lt,Ys,Er;a=new qt({}),E=new Qp({});let Vc=["NOK","SEK","DKK","EUR"],gi=[];for(let N=0;N<4;N+=1)gi[N]=e0(xp(t,Vc,N));let bt=t[3].p.e&&t[0].chip!="esp8266"&&ff(t),gt=t[3].g.s>0&&cf(t);It=new qt({});let Qc=[24,48,96,192,384,576,1152],ki=[];for(let N=0;N<7;N+=1)ki[N]=t0(Jp(t,Qc,N));let kt=t[3].m.e.e&&mf(t),wt=t[3].m.e.e&&pf(t),yt=t[3].m.m.e&&_f(t);Tn=new qt({}),In=new qt({}),Ln=new Kc({});let $t=t[3].n.m=="static"&&df(t);qn=new qt({});let Ct=t[0].chip!="esp8266"&&vf(t),nt=t[3].q.s.e&&hf(t),it=t[3].q.m==3&&bf(t),st=t[3].q.m==4&&gf(t),ot=qs&&kf(t);Xn=new qt({});let ti=t[7],pt=[];for(let N=0;N20||t[0].chip=="esp8266")&&$f(t);Jn=new qt({});let Tt=t[3].d.s&&Nf(t);return ln=new Et({props:{active:t[1],message:"Loading configuration"}}),nn=new Et({props:{active:t[2],message:"Saving configuration"}}),sn=new Et({props:{active:t[4],message:"Performing factory reset"}}),on=new Et({props:{active:t[5],message:"Device have been factory reset and switched to AP mode"}}),{c(){e=m("form"),l=m("div"),n=m("div"),i=m("strong"),i.textContent="General",o=h(),r=m("a"),Z(a.$$.fragment),c=h(),f=m("input"),p=h(),_=m("div"),b=m("div"),d=m("div"),v=y("Hostname"),g=m("br"),T=h(),C=m("input"),$=h(),M=m("div"),F=y("Time zone"),S=m("br"),D=h(),A=m("select"),Z(E.$$.fragment),Y=h(),R=m("input"),U=h(),H=m("div"),z=m("div"),q=m("div"),L=y("Price region"),B=m("br"),O=h(),j=m("select"),G=m("optgroup"),te=m("option"),te.textContent="NO1",le=m("option"),le.textContent="NO2",pe=m("option"),pe.textContent="NO3",ie=m("option"),ie.textContent="NO4",Pe=m("option"),Pe.textContent="NO5",je=m("optgroup"),De=m("option"),De.textContent="SE1",We=m("option"),We.textContent="SE2",be=m("option"),be.textContent="SE3",ye=m("option"),ye.textContent="SE4",Re=m("optgroup"),ge=m("option"),ge.textContent="DK1",ae=m("option"),ae.textContent="DK2",$e=m("option"),$e.textContent="Austria",J=m("option"),J.textContent="Belgium",se=m("option"),se.textContent="Czech Republic",Fe=m("option"),Fe.textContent="Estonia",Le=m("option"),Le.textContent="Finland",_e=m("option"),_e.textContent="France",Ce=m("option"),Ce.textContent="Germany",Ne=m("option"),Ne.textContent="Great Britain",de=m("option"),de.textContent="Latvia",Te=m("option"),Te.textContent="Lithuania",ee=m("option"),ee.textContent="Netherland",oe=m("option"),oe.textContent="Poland",Ue=m("option"),Ue.textContent="Switzerland",ue=h(),ve=m("div"),dt=y("Currency"),Wl=m("br"),tl=h(),ct=m("select");for(let N=0;N<4;N+=1)gi[N].c();Ml=h(),pl=m("div"),jt=m("div"),vt=m("div"),Qe=y("Fixed price"),Xe=m("br"),Ze=h(),He=m("input"),Je=h(),Ge=m("div"),xe=y("Multiplier"),et=m("br"),re=h(),he=m("input"),Ai=h(),_l=m("div"),_n=m("label"),St=m("input"),Ei=y(" Enable price fetch from remote server"),Ii=h(),bt&&bt.c(),Fi=h(),dl=m("div"),Ri=y("Security"),Li=m("br"),Oi=h(),Mt=m("select"),Pl=m("option"),Pl.textContent="None",Nl=m("option"),Nl.textContent="Only configuration",Dl=m("option"),Dl.textContent="Everything",qi=h(),gt&>.c(),ze=h(),ke=m("div"),vl=m("strong"),vl.textContent="Meter",Ns=h(),Al=m("a"),Z(It.$$.fragment),Ui=h(),Gl=m("input"),No=h(),ll=m("div"),Hi=m("span"),Hi.textContent="Buffer size",Do=h(),Ds=m("span"),Ds.textContent="Serial conf.",Ao=h(),ci=m("label"),Wt=m("input"),Eo=y(" inverted"),Io=h(),El=m("div"),nl=m("select"),Il=m("option"),Fo=y("Autodetect");for(let N=0;N<7;N+=1)ki[N].c();Ro=h(),mt=m("select"),Fl=m("option"),Lo=y("-"),dn=m("option"),dn.textContent="7N1",vn=m("option"),vn.textContent="8N1",hn=m("option"),hn.textContent="7E1",bn=m("option"),bn.textContent="8E1",Oo=h(),Pt=m("input"),qo=h(),Bl=m("div"),Uo=y("Voltage"),Ho=m("br"),jo=h(),il=m("select"),gn=m("option"),gn.textContent="400V (TN)",kn=m("option"),kn.textContent="230V (IT/TT)",Wo=h(),wn=m("div"),zl=m("div"),Go=y("Main fuse"),Bo=m("br"),zo=h(),yn=m("label"),Gt=m("input"),Yo=h(),zi=m("span"),zi.textContent="A",Ko=h(),Yl=m("div"),Vo=y("Production"),Qo=m("br"),Xo=h(),$n=m("label"),Bt=m("input"),Zo=h(),Yi=m("span"),Yi.textContent="kWp",Jo=h(),As=m("div"),xo=h(),Kl=m("div"),Ki=m("label"),zt=m("input"),eu=y(" Meter is encrypted"),tu=h(),kt&&kt.c(),lu=h(),wt&&wt.c(),Es=h(),Vi=m("label"),Yt=m("input"),nu=y(" Multipliers"),iu=h(),yt&&yt.c(),su=h(),lt=m("div"),Qi=m("strong"),Qi.textContent="WiFi",ou=h(),Cn=m("a"),Z(Tn.$$.fragment),uu=h(),mi=m("input"),ru=h(),Vl=m("div"),au=y("SSID"),fu=m("br"),cu=h(),hl=m("input"),mu=h(),Ql=m("div"),pu=y("Password"),_u=m("br"),du=h(),bl=m("input"),vu=h(),Sn=m("div"),Xl=m("div"),hu=y("Power saving"),bu=m("br"),gu=h(),Ft=m("select"),Mn=m("option"),Mn.textContent="Default",Pn=m("option"),Pn.textContent="Off",Nn=m("option"),Nn.textContent="Minimum",Dn=m("option"),Dn.textContent="Maximum",ku=h(),Zl=m("div"),wu=y("Power"),yu=m("br"),$u=h(),An=m("div"),Rt=m("input"),Cu=h(),Xi=m("span"),Xi.textContent="dBm",Tu=h(),Zi=m("div"),Ji=m("label"),Kt=m("input"),Su=y(" Auto reboot on connection problem"),Mu=h(),xi=m("div"),es=m("label"),Vt=m("input"),Pu=y(" Allow 802.11b legacy rates"),Nu=h(),at=m("div"),ts=m("strong"),ts.textContent="Network",Du=h(),En=m("a"),Z(In.$$.fragment),Au=h(),Jl=m("div"),Eu=y("IP"),Iu=m("br"),Fu=h(),Rl=m("div"),sl=m("select"),Fn=m("option"),Fn.textContent="DHCP",Rn=m("option"),Rn.textContent="Static",Ru=h(),Nt=m("input"),Lu=h(),Dt=m("select"),Z(Ln.$$.fragment),Ou=h(),$t&&$t.c(),Is=h(),os=m("div"),us=m("label"),Qt=m("input"),qu=y(" enable mDNS"),Uu=h(),pi=m("input"),Hu=h(),Ll=m("div"),ju=y("NTP "),_i=m("label"),Xt=m("input"),Wu=y(" obtain from DHCP"),Gu=m("br"),Bu=h(),rs=m("div"),gl=m("input"),zu=h(),Ve=m("div"),as=m("strong"),as.textContent="MQTT",Yu=h(),On=m("a"),Z(qn.$$.fragment),Ku=h(),di=m("input"),Vu=h(),ol=m("div"),Qu=y(`Server - `),Ct&&Ct.c(),Fs=h(),Xu=m("br"),Zu=h(),Un=m("div"),kl=m("input"),Ju=h(),Zt=m("input"),xu=h(),nt&&nt.c(),Rs=h(),xl=m("div"),er=y("Username"),tr=m("br"),lr=h(),wl=m("input"),nr=h(),en=m("div"),ir=y("Password"),sr=m("br"),or=h(),yl=m("input"),ur=h(),Hn=m("div"),jn=m("div"),rr=y("Client ID"),ar=m("br"),fr=h(),$l=m("input"),cr=h(),Wn=m("div"),mr=y("Payload"),pr=m("br"),_r=h(),ht=m("select"),Gn=m("option"),Gn.textContent="JSON",Bn=m("option"),Bn.textContent="Raw (minimal)",zn=m("option"),zn.textContent="Raw (full)",Yn=m("option"),Yn.textContent="Domoticz",Kn=m("option"),Kn.textContent="HomeAssistant",Vn=m("option"),Vn.textContent="HEX dump",dr=h(),tn=m("div"),vr=y("Publish topic"),hr=m("br"),br=h(),Cl=m("input"),gr=h(),it&&it.c(),Ls=h(),st&&st.c(),Os=h(),ot&&ot.c(),Us=h(),ul=m("div"),fs=m("strong"),fs.textContent="User interface",kr=h(),Qn=m("a"),Z(Xn.$$.fragment),wr=h(),vi=m("input"),yr=h(),hi=m("div");for(let N=0;NSave',Ws=h(),Z(ln.$$.fragment),Gs=h(),Z(nn.$$.fragment),Bs=h(),Z(sn.$$.fragment),zs=h(),Z(on.$$.fragment),u(i,"class","text-sm"),u(r,"href",Ut("General-configuration")),u(r,"target","_blank"),u(r,"class","float-right"),u(f,"type","hidden"),u(f,"name","g"),f.value="true",u(C,"name","gh"),u(C,"type","text"),u(C,"class","in-f w-full"),u(C,"pattern","[A-Za-z0-9-]+"),u(A,"name","gt"),u(A,"class","in-l w-full"),t[3].g.t===void 0&&tt(()=>t[16].call(A)),u(b,"class","flex"),u(_,"class","my-1"),u(R,"type","hidden"),u(R,"name","p"),R.value="true",te.__value="10YNO-1--------2",te.value=te.__value,le.__value="10YNO-2--------T",le.value=le.__value,pe.__value="10YNO-3--------J",pe.value=pe.__value,ie.__value="10YNO-4--------9",ie.value=ie.__value,Pe.__value="10Y1001A1001A48H",Pe.value=Pe.__value,u(G,"label","Norway"),De.__value="10Y1001A1001A44P",De.value=De.__value,We.__value="10Y1001A1001A45N",We.value=We.__value,be.__value="10Y1001A1001A46L",be.value=be.__value,ye.__value="10Y1001A1001A47J",ye.value=ye.__value,u(je,"label","Sweden"),ge.__value="10YDK-1--------W",ge.value=ge.__value,ae.__value="10YDK-2--------M",ae.value=ae.__value,u(Re,"label","Denmark"),$e.__value="10YAT-APG------L",$e.value=$e.__value,J.__value="10YBE----------2",J.value=J.__value,se.__value="10YCZ-CEPS-----N",se.value=se.__value,Fe.__value="10Y1001A1001A39I",Fe.value=Fe.__value,Le.__value="10YFI-1--------U",Le.value=Le.__value,_e.__value="10YFR-RTE------C",_e.value=_e.__value,Ce.__value="10Y1001A1001A83F",Ce.value=Ce.__value,Ne.__value="10YGB----------A",Ne.value=Ne.__value,de.__value="10YLV-1001A00074",de.value=de.__value,Te.__value="10YLT-1001A0008Q",Te.value=Te.__value,ee.__value="10YNL----------L",ee.value=ee.__value,oe.__value="10YPL-AREA-----S",oe.value=oe.__value,Ue.__value="10YCH-SWISSGRIDZ",Ue.value=Ue.__value,u(j,"name","pr"),u(j,"class","in-f w-full"),t[3].p.r===void 0&&tt(()=>t[17].call(j)),u(q,"class","w-full"),u(ct,"name","pc"),u(ct,"class","in-l"),t[3].p.c===void 0&&tt(()=>t[18].call(ct)),u(z,"class","flex"),u(H,"class","my-1"),u(He,"name","pf"),u(He,"type","number"),u(He,"min","0.001"),u(He,"max","65"),u(He,"step","0.001"),u(He,"class","in-f tr w-full"),u(vt,"class","w-1/2"),u(he,"name","pm"),u(he,"type","number"),u(he,"min","0.001"),u(he,"max","1000"),u(he,"step","0.001"),u(he,"class","in-l tr w-full"),u(Ge,"class","w-1/2"),u(jt,"class","flex"),u(pl,"class","my-1"),u(St,"type","checkbox"),u(St,"name","pe"),St.__value="true",St.value=St.__value,u(St,"class","rounded mb-1"),u(_l,"class","my-1"),Pl.__value=0,Pl.value=Pl.__value,Nl.__value=1,Nl.value=Nl.__value,Dl.__value=2,Dl.value=Dl.__value,u(Mt,"name","gs"),u(Mt,"class","in-s"),t[3].g.s===void 0&&tt(()=>t[23].call(Mt)),u(dl,"class","my-1"),u(n,"class","cnt"),u(vl,"class","text-sm"),u(Al,"href",Ut("Meter-configuration")),u(Al,"target","_blank"),u(Al,"class","float-right"),u(Gl,"type","hidden"),u(Gl,"name","m"),Gl.value="true",u(Hi,"class","float-right"),u(Wt,"name","mi"),Wt.__value="true",Wt.value=Wt.__value,u(Wt,"type","checkbox"),u(Wt,"class","rounded mb-1"),u(ci,"class","mt-2 ml-3 whitespace-nowrap"),Il.__value=0,Il.value=Il.__value,Il.disabled=ji=t[3].m.b!=0,u(nl,"name","mb"),u(nl,"class","in-f tr w-1/2"),t[3].m.b===void 0&&tt(()=>t[27].call(nl)),Fl.__value=0,Fl.value=Fl.__value,Fl.disabled=Wi=t[3].m.b!=0,dn.__value=2,dn.value=dn.__value,vn.__value=3,vn.value=vn.__value,hn.__value=10,hn.value=hn.__value,bn.__value=11,bn.value=bn.__value,u(mt,"name","mp"),u(mt,"class","in-m"),mt.disabled=Gi=t[3].m.b==0,t[3].m.p===void 0&&tt(()=>t[28].call(mt)),u(Pt,"name","ms"),u(Pt,"type","number"),u(Pt,"min",64),u(Pt,"max",Bi=t[0].chip=="esp8266"?t[3].i.h.p==3||t[3].i.h.p==113?512:128:4096),u(Pt,"step",64),u(Pt,"class","in-l tr w-1/2"),u(El,"class","flex w-full"),u(ll,"class","my-1"),gn.__value=2,gn.value=gn.__value,kn.__value=1,kn.value=kn.__value,u(il,"name","md"),u(il,"class","in-s"),t[3].m.d===void 0&&tt(()=>t[30].call(il)),u(Bl,"class","my-1"),u(Gt,"name","mf"),u(Gt,"type","number"),u(Gt,"min","5"),u(Gt,"max","65535"),u(Gt,"class","in-f tr w-full"),u(zi,"class","in-post"),u(yn,"class","flex"),u(zl,"class","mx-1"),u(Bt,"name","mr"),u(Bt,"type","number"),u(Bt,"min","0"),u(Bt,"max","65535"),u(Bt,"class","in-f tr w-full"),u(Yi,"class","in-post"),u($n,"class","flex"),u(Yl,"class","mx-1"),u(wn,"class","my-1 flex"),u(As,"class","my-1"),u(zt,"type","checkbox"),u(zt,"name","me"),zt.__value="true",zt.value=zt.__value,u(zt,"class","rounded mb-1"),u(Kl,"class","my-1"),u(Yt,"type","checkbox"),u(Yt,"name","mm"),Yt.__value="true",Yt.value=Yt.__value,u(Yt,"class","rounded mb-1"),u(ke,"class","cnt"),u(Qi,"class","text-sm"),u(Cn,"href",Ut("WiFi-configuration")),u(Cn,"target","_blank"),u(Cn,"class","float-right"),u(mi,"type","hidden"),u(mi,"name","w"),mi.value="true",u(hl,"name","ws"),u(hl,"type","text"),u(hl,"class","in-s"),u(Vl,"class","my-1"),u(bl,"name","wp"),u(bl,"type","password"),u(bl,"class","in-s"),u(Ql,"class","my-1"),Mn.__value=255,Mn.value=Mn.__value,Pn.__value=0,Pn.value=Pn.__value,Nn.__value=1,Nn.value=Nn.__value,Dn.__value=2,Dn.value=Dn.__value,u(Ft,"name","wz"),u(Ft,"class","in-s"),t[3].w.z===void 0&&tt(()=>t[43].call(Ft)),u(Xl,"class","w-1/2"),u(Rt,"name","ww"),u(Rt,"type","number"),u(Rt,"min","0"),u(Rt,"max","20.5"),u(Rt,"step","0.5"),u(Rt,"class","in-f tr w-full"),u(Xi,"class","in-post"),u(An,"class","flex"),u(Zl,"class","ml-2 w-1/2"),u(Sn,"class","my-1 flex"),u(Kt,"type","checkbox"),u(Kt,"name","wa"),Kt.__value="true",Kt.value=Kt.__value,u(Kt,"class","rounded mb-1"),u(Zi,"class","my-3"),u(Vt,"type","checkbox"),u(Vt,"name","wb"),Vt.__value="true",Vt.value=Vt.__value,u(Vt,"class","rounded mb-1"),u(xi,"class","my-3"),u(lt,"class","cnt"),u(ts,"class","text-sm"),u(En,"href",Ut("Network-configuration")),u(En,"target","_blank"),u(En,"class","float-right"),Fn.__value="dhcp",Fn.value=Fn.__value,Rn.__value="static",Rn.value=Rn.__value,u(sl,"name","nm"),u(sl,"class","in-f"),t[3].n.m===void 0&&tt(()=>t[47].call(sl)),u(Nt,"name","ni"),u(Nt,"type","text"),u(Nt,"class","in-m w-full"),Nt.disabled=ls=t[3].n.m=="dhcp",Nt.required=ns=t[3].n.m=="static",u(Dt,"name","ns"),u(Dt,"class","in-l"),Dt.disabled=is=t[3].n.m=="dhcp",Dt.required=ss=t[3].n.m=="static",t[3].n.s===void 0&&tt(()=>t[49].call(Dt)),u(Rl,"class","flex"),u(Jl,"class","my-1"),u(Qt,"name","nd"),Qt.__value="true",Qt.value=Qt.__value,u(Qt,"type","checkbox"),u(Qt,"class","rounded mb-1"),u(os,"class","my-1"),u(pi,"type","hidden"),u(pi,"name","ntp"),pi.value="true",u(Xt,"name","ntpd"),Xt.__value="true",Xt.value=Xt.__value,u(Xt,"type","checkbox"),u(Xt,"class","rounded mb-1"),u(_i,"class","ml-4"),u(gl,"name","ntph"),u(gl,"type","text"),u(gl,"class","in-s"),u(rs,"class","flex"),u(Ll,"class","my-1"),u(at,"class","cnt"),u(as,"class","text-sm"),u(On,"href",Ut("MQTT-configuration")),u(On,"target","_blank"),u(On,"class","float-right"),u(di,"type","hidden"),u(di,"name","q"),di.value="true",u(kl,"name","qh"),u(kl,"type","text"),u(kl,"class","in-f w-3/4"),u(Zt,"name","qp"),u(Zt,"type","number"),u(Zt,"min","1024"),u(Zt,"max","65535"),u(Zt,"class","in-l tr w-1/4"),u(Un,"class","flex"),u(ol,"class","my-1"),u(wl,"name","qu"),u(wl,"type","text"),u(wl,"class","in-s"),u(xl,"class","my-1"),u(yl,"name","qa"),u(yl,"type","password"),u(yl,"class","in-s"),u(en,"class","my-1"),u($l,"name","qc"),u($l,"type","text"),u($l,"class","in-f w-full"),Gn.__value=0,Gn.value=Gn.__value,Bn.__value=1,Bn.value=Bn.__value,zn.__value=2,zn.value=zn.__value,Yn.__value=3,Yn.value=Yn.__value,Kn.__value=4,Kn.value=Kn.__value,Vn.__value=255,Vn.value=Vn.__value,u(ht,"name","qm"),u(ht,"class","in-l"),t[3].q.m===void 0&&tt(()=>t[62].call(ht)),u(Hn,"class","my-1 flex"),u(Cl,"name","qb"),u(Cl,"type","text"),u(Cl,"class","in-s"),u(tn,"class","my-1"),u(Ve,"class","cnt"),u(fs,"class","text-sm"),u(Qn,"href",Ut("User-interface")),u(Qn,"target","_blank"),u(Qn,"class","float-right"),u(vi,"type","hidden"),u(vi,"name","u"),vi.value="true",u(hi,"class","flex flex-wrap"),u(ul,"class","cnt"),u(cs,"class","text-sm"),u(Zn,"href","https://amsleser.no/blog/post/24-telnet-debug"),u(Zn,"target","_blank"),u(Zn,"class","float-right"),u(bi,"type","hidden"),u(bi,"name","d"),bi.value="true",u(Jt,"type","checkbox"),u(Jt,"name","ds"),Jt.__value="true",Jt.value=Jt.__value,u(Jt,"class","rounded mb-1"),u(ms,"class","mt-3"),u(At,"class","cnt"),u(l,"class","grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2"),u(xn,"type","button"),u(xn,"class","py-2 px-4 rounded bg-red-500 text-white ml-2"),u(ei,"type","button"),u(ei,"class","py-2 px-4 rounded bg-yellow-500 text-white"),u(_s,"class","text-center"),u(ds,"class","text-right"),u(Ol,"class","grid grid-cols-3"),u(e,"autocomplete","off")},m(N,x){w(N,e,x),s(e,l),s(l,n),s(n,i),s(n,o),s(n,r),Q(a,r,null),s(n,c),s(n,f),s(n,p),s(n,_),s(_,b),s(b,d),s(d,v),s(d,g),s(d,T),s(d,C),V(C,t[3].g.h),s(b,$),s(b,M),s(M,F),s(M,S),s(M,D),s(M,A),Q(E,A,null),qe(A,t[3].g.t,!0),s(n,Y),s(n,R),s(n,U),s(n,H),s(H,z),s(z,q),s(q,L),s(q,B),s(q,O),s(q,j),s(j,G),s(G,te),s(G,le),s(G,pe),s(G,ie),s(G,Pe),s(j,je),s(je,De),s(je,We),s(je,be),s(je,ye),s(j,Re),s(Re,ge),s(Re,ae),s(j,$e),s(j,J),s(j,se),s(j,Fe),s(j,Le),s(j,_e),s(j,Ce),s(j,Ne),s(j,de),s(j,Te),s(j,ee),s(j,oe),s(j,Ue),qe(j,t[3].p.r,!0),s(z,ue),s(z,ve),s(ve,dt),s(ve,Wl),s(ve,tl),s(ve,ct);for(let ft=0;ft<4;ft+=1)gi[ft]&&gi[ft].m(ct,null);qe(ct,t[3].p.c,!0),s(n,Ml),s(n,pl),s(pl,jt),s(jt,vt),s(vt,Qe),s(vt,Xe),s(vt,Ze),s(vt,He),V(He,t[3].p.f),s(jt,Je),s(jt,Ge),s(Ge,xe),s(Ge,et),s(Ge,re),s(Ge,he),V(he,t[3].p.m),s(n,Ai),s(n,_l),s(_l,_n),s(_n,St),St.checked=t[3].p.e,s(_n,Ei),s(_l,Ii),bt&&bt.m(_l,null),s(n,Fi),s(n,dl),s(dl,Ri),s(dl,Li),s(dl,Oi),s(dl,Mt),s(Mt,Pl),s(Mt,Nl),s(Mt,Dl),qe(Mt,t[3].g.s,!0),s(n,qi),gt&>.m(n,null),s(l,ze),s(l,ke),s(ke,vl),s(ke,Ns),s(ke,Al),Q(It,Al,null),s(ke,Ui),s(ke,Gl),s(ke,No),s(ke,ll),s(ll,Hi),s(ll,Do),s(ll,Ds),s(ll,Ao),s(ll,ci),s(ci,Wt),Wt.checked=t[3].m.i,s(ci,Eo),s(ll,Io),s(ll,El),s(El,nl),s(nl,Il),s(Il,Fo);for(let ft=0;ft<7;ft+=1)ki[ft]&&ki[ft].m(nl,null);qe(nl,t[3].m.b,!0),s(El,Ro),s(El,mt),s(mt,Fl),s(Fl,Lo),s(mt,dn),s(mt,vn),s(mt,hn),s(mt,bn),qe(mt,t[3].m.p,!0),s(El,Oo),s(El,Pt),V(Pt,t[3].m.s),s(ke,qo),s(ke,Bl),s(Bl,Uo),s(Bl,Ho),s(Bl,jo),s(Bl,il),s(il,gn),s(il,kn),qe(il,t[3].m.d,!0),s(ke,Wo),s(ke,wn),s(wn,zl),s(zl,Go),s(zl,Bo),s(zl,zo),s(zl,yn),s(yn,Gt),V(Gt,t[3].m.f),s(yn,Yo),s(yn,zi),s(wn,Ko),s(wn,Yl),s(Yl,Vo),s(Yl,Qo),s(Yl,Xo),s(Yl,$n),s($n,Bt),V(Bt,t[3].m.r),s($n,Zo),s($n,Yi),s(ke,Jo),s(ke,As),s(ke,xo),s(ke,Kl),s(Kl,Ki),s(Ki,zt),zt.checked=t[3].m.e.e,s(Ki,eu),s(Kl,tu),kt&&kt.m(Kl,null),s(ke,lu),wt&&wt.m(ke,null),s(ke,Es),s(ke,Vi),s(Vi,Yt),Yt.checked=t[3].m.m.e,s(Vi,nu),s(ke,iu),yt&&yt.m(ke,null),s(l,su),s(l,lt),s(lt,Qi),s(lt,ou),s(lt,Cn),Q(Tn,Cn,null),s(lt,uu),s(lt,mi),s(lt,ru),s(lt,Vl),s(Vl,au),s(Vl,fu),s(Vl,cu),s(Vl,hl),V(hl,t[3].w.s),s(lt,mu),s(lt,Ql),s(Ql,pu),s(Ql,_u),s(Ql,du),s(Ql,bl),V(bl,t[3].w.p),s(lt,vu),s(lt,Sn),s(Sn,Xl),s(Xl,hu),s(Xl,bu),s(Xl,gu),s(Xl,Ft),s(Ft,Mn),s(Ft,Pn),s(Ft,Nn),s(Ft,Dn),qe(Ft,t[3].w.z,!0),s(Sn,ku),s(Sn,Zl),s(Zl,wu),s(Zl,yu),s(Zl,$u),s(Zl,An),s(An,Rt),V(Rt,t[3].w.w),s(An,Cu),s(An,Xi),s(lt,Tu),s(lt,Zi),s(Zi,Ji),s(Ji,Kt),Kt.checked=t[3].w.a,s(Ji,Su),s(lt,Mu),s(lt,xi),s(xi,es),s(es,Vt),Vt.checked=t[3].w.b,s(es,Pu),s(l,Nu),s(l,at),s(at,ts),s(at,Du),s(at,En),Q(In,En,null),s(at,Au),s(at,Jl),s(Jl,Eu),s(Jl,Iu),s(Jl,Fu),s(Jl,Rl),s(Rl,sl),s(sl,Fn),s(sl,Rn),qe(sl,t[3].n.m,!0),s(Rl,Ru),s(Rl,Nt),V(Nt,t[3].n.i),s(Rl,Lu),s(Rl,Dt),Q(Ln,Dt,null),qe(Dt,t[3].n.s,!0),s(at,Ou),$t&&$t.m(at,null),s(at,Is),s(at,os),s(os,us),s(us,Qt),Qt.checked=t[3].n.d,s(us,qu),s(at,Uu),s(at,pi),s(at,Hu),s(at,Ll),s(Ll,ju),s(Ll,_i),s(_i,Xt),Xt.checked=t[3].n.h,s(_i,Wu),s(Ll,Gu),s(Ll,Bu),s(Ll,rs),s(rs,gl),V(gl,t[3].n.n1),s(l,zu),s(l,Ve),s(Ve,as),s(Ve,Yu),s(Ve,On),Q(qn,On,null),s(Ve,Ku),s(Ve,di),s(Ve,Vu),s(Ve,ol),s(ol,Qu),Ct&&Ct.m(ol,null),s(ol,Fs),s(ol,Xu),s(ol,Zu),s(ol,Un),s(Un,kl),V(kl,t[3].q.h),s(Un,Ju),s(Un,Zt),V(Zt,t[3].q.p),s(Ve,xu),nt&&nt.m(Ve,null),s(Ve,Rs),s(Ve,xl),s(xl,er),s(xl,tr),s(xl,lr),s(xl,wl),V(wl,t[3].q.u),s(Ve,nr),s(Ve,en),s(en,ir),s(en,sr),s(en,or),s(en,yl),V(yl,t[3].q.a),s(Ve,ur),s(Ve,Hn),s(Hn,jn),s(jn,rr),s(jn,ar),s(jn,fr),s(jn,$l),V($l,t[3].q.c),s(Hn,cr),s(Hn,Wn),s(Wn,mr),s(Wn,pr),s(Wn,_r),s(Wn,ht),s(ht,Gn),s(ht,Bn),s(ht,zn),s(ht,Yn),s(ht,Kn),s(ht,Vn),qe(ht,t[3].q.m,!0),s(Ve,dr),s(Ve,tn),s(tn,vr),s(tn,hr),s(tn,br),s(tn,Cl),V(Cl,t[3].q.b),s(l,gr),it&&it.m(l,null),s(l,Ls),st&&st.m(l,null),s(l,Os),ot&&ot.m(l,null),s(l,Us),s(l,ul),s(ul,fs),s(ul,kr),s(ul,Qn),Q(Xn,Qn,null),s(ul,wr),s(ul,vi),s(ul,yr),s(ul,hi);for(let ft=0;ft0?gt?gt.p(N,x):(gt=cf(N),gt.c(),gt.m(n,null)):gt&&(gt.d(1),gt=null),x[0]&8&&(Wt.checked=N[3].m.i),(!Lt||x[0]&8&&ji!==(ji=N[3].m.b!=0))&&(Il.disabled=ji),x[0]&8&&qe(nl,N[3].m.b),(!Lt||x[0]&8&&Wi!==(Wi=N[3].m.b!=0))&&(Fl.disabled=Wi),(!Lt||x[0]&8&&Gi!==(Gi=N[3].m.b==0))&&(mt.disabled=Gi),x[0]&8&&qe(mt,N[3].m.p),(!Lt||x[0]&9&&Bi!==(Bi=N[0].chip=="esp8266"?N[3].i.h.p==3||N[3].i.h.p==113?512:128:4096))&&u(Pt,"max",Bi),x[0]&8&&fe(Pt.value)!==N[3].m.s&&V(Pt,N[3].m.s),x[0]&8&&qe(il,N[3].m.d),x[0]&8&&fe(Gt.value)!==N[3].m.f&&V(Gt,N[3].m.f),x[0]&8&&fe(Bt.value)!==N[3].m.r&&V(Bt,N[3].m.r),x[0]&8&&(zt.checked=N[3].m.e.e),N[3].m.e.e?kt?kt.p(N,x):(kt=mf(N),kt.c(),kt.m(Kl,null)):kt&&(kt.d(1),kt=null),N[3].m.e.e?wt?wt.p(N,x):(wt=pf(N),wt.c(),wt.m(ke,Es)):wt&&(wt.d(1),wt=null),x[0]&8&&(Yt.checked=N[3].m.m.e),N[3].m.m.e?yt?yt.p(N,x):(yt=_f(N),yt.c(),yt.m(ke,null)):yt&&(yt.d(1),yt=null),x[0]&8&&hl.value!==N[3].w.s&&V(hl,N[3].w.s),x[0]&8&&bl.value!==N[3].w.p&&V(bl,N[3].w.p),x[0]&8&&qe(Ft,N[3].w.z),x[0]&8&&fe(Rt.value)!==N[3].w.w&&V(Rt,N[3].w.w),x[0]&8&&(Kt.checked=N[3].w.a),x[0]&8&&(Vt.checked=N[3].w.b),x[0]&8&&qe(sl,N[3].n.m),(!Lt||x[0]&8&&ls!==(ls=N[3].n.m=="dhcp"))&&(Nt.disabled=ls),(!Lt||x[0]&8&&ns!==(ns=N[3].n.m=="static"))&&(Nt.required=ns),x[0]&8&&Nt.value!==N[3].n.i&&V(Nt,N[3].n.i),(!Lt||x[0]&8&&is!==(is=N[3].n.m=="dhcp"))&&(Dt.disabled=is),(!Lt||x[0]&8&&ss!==(ss=N[3].n.m=="static"))&&(Dt.required=ss),x[0]&8&&qe(Dt,N[3].n.s),N[3].n.m=="static"?$t?$t.p(N,x):($t=df(N),$t.c(),$t.m(at,Is)):$t&&($t.d(1),$t=null),x[0]&8&&(Qt.checked=N[3].n.d),x[0]&8&&(Xt.checked=N[3].n.h),x[0]&8&&gl.value!==N[3].n.n1&&V(gl,N[3].n.n1),N[0].chip!="esp8266"?Ct?Ct.p(N,x):(Ct=vf(N),Ct.c(),Ct.m(ol,Fs)):Ct&&(Ct.d(1),Ct=null),x[0]&8&&kl.value!==N[3].q.h&&V(kl,N[3].q.h),x[0]&8&&fe(Zt.value)!==N[3].q.p&&V(Zt,N[3].q.p),N[3].q.s.e?nt?(nt.p(N,x),x[0]&8&&P(nt,1)):(nt=hf(N),nt.c(),P(nt,1),nt.m(Ve,Rs)):nt&&(Ae(),I(nt,1,1,()=>{nt=null}),Ee()),x[0]&8&&wl.value!==N[3].q.u&&V(wl,N[3].q.u),x[0]&8&&yl.value!==N[3].q.a&&V(yl,N[3].q.a),x[0]&8&&$l.value!==N[3].q.c&&V($l,N[3].q.c),x[0]&8&&qe(ht,N[3].q.m),x[0]&8&&Cl.value!==N[3].q.b&&V(Cl,N[3].q.b),N[3].q.m==3?it?(it.p(N,x),x[0]&8&&P(it,1)):(it=bf(N),it.c(),P(it,1),it.m(l,Ls)):it&&(Ae(),I(it,1,1,()=>{it=null}),Ee()),N[3].q.m==4?st?(st.p(N,x),x[0]&8&&P(st,1)):(st=gf(N),st.c(),P(st,1),st.m(l,Os)):st&&(Ae(),I(st,1,1,()=>{st=null}),Ee()),x[0]&8&&(qs=N[3].p.r.startsWith("10YNO")||N[3].p.r=="10Y1001A1001A48H"),qs?ot?(ot.p(N,x),x[0]&8&&P(ot,1)):(ot=kf(N),ot.c(),P(ot,1),ot.m(l,Us)):ot&&(Ae(),I(ot,1,1,()=>{ot=null}),Ee()),x[0]&136){ti=N[7];let Ot;for(Ot=0;Ot20||N[0].chip=="esp8266"?ut?(ut.p(N,x),x[0]&1&&P(ut,1)):(ut=$f(N),ut.c(),P(ut,1),ut.m(l,Hs)):ut&&(Ae(),I(ut,1,1,()=>{ut=null}),Ee()),x[0]&8&&(Jt.checked=N[3].d.s),N[3].d.s?Tt?Tt.p(N,x):(Tt=Nf(N),Tt.c(),Tt.m(At,null)):Tt&&(Tt.d(1),Tt=null);const ft={};x[0]&2&&(ft.active=N[1]),ln.$set(ft);const Ir={};x[0]&4&&(Ir.active=N[2]),nn.$set(Ir);const Fr={};x[0]&16&&(Fr.active=N[4]),sn.$set(Fr);const Rr={};x[0]&32&&(Rr.active=N[5]),on.$set(Rr)},i(N){Lt||(P(a.$$.fragment,N),P(E.$$.fragment,N),P(It.$$.fragment,N),P(Tn.$$.fragment,N),P(In.$$.fragment,N),P(Ln.$$.fragment,N),P(qn.$$.fragment,N),P(nt),P(it),P(st),P(ot),P(Xn.$$.fragment,N),P(ut),P(Jn.$$.fragment,N),P(ln.$$.fragment,N),P(nn.$$.fragment,N),P(sn.$$.fragment,N),P(on.$$.fragment,N),Lt=!0)},o(N){I(a.$$.fragment,N),I(E.$$.fragment,N),I(It.$$.fragment,N),I(Tn.$$.fragment,N),I(In.$$.fragment,N),I(Ln.$$.fragment,N),I(qn.$$.fragment,N),I(nt),I(it),I(st),I(ot),I(Xn.$$.fragment,N),I(ut),I(Jn.$$.fragment,N),I(ln.$$.fragment,N),I(nn.$$.fragment,N),I(sn.$$.fragment,N),I(on.$$.fragment,N),Lt=!1},d(N){N&&k(e),X(a),X(E),cl(gi,N),bt&&bt.d(),gt&>.d(),X(It),cl(ki,N),kt&&kt.d(),wt&&wt.d(),yt&&yt.d(),X(Tn),X(In),X(Ln),$t&&$t.d(),X(qn),Ct&&Ct.d(),nt&&nt.d(),it&&it.d(),st&&st.d(),ot&&ot.d(),X(Xn),cl(pt,N),ut&&ut.d(),X(Jn),Tt&&Tt.d(),N&&k(Ws),X(ln,N),N&&k(Gs),X(nn,N),N&&k(Bs),X(sn,N),N&&k(zs),X(on,N),Ys=!1,Be(Er)}}}async function d0(){await(await fetch("/reboot",{method:"POST"})).json()}function v0(t,e,l){let{sysinfo:n={}}=e,i=[{name:"Import gauge",key:"i"},{name:"Export gauge",key:"e"},{name:"Voltage",key:"v"},{name:"Amperage",key:"a"},{name:"Reactive",key:"r"},{name:"Realtime",key:"c"},{name:"Peaks",key:"t"},{name:"Price",key:"p"},{name:"Day plot",key:"d"},{name:"Month plot",key:"m"},{name:"Temperature plot",key:"s"}],o=!0,r=!1,a={g:{t:"",h:"",s:0,u:"",p:""},m:{b:2400,p:11,i:!1,d:0,f:0,r:0,e:{e:!1,k:"",a:""},m:{e:!1,w:!1,v:!1,a:!1,c:!1}},w:{s:"",p:"",w:0,z:255,a:!0,b:!0},n:{m:"",i:"",s:"",g:"",d1:"",d2:"",d:!1,n1:"",n2:"",h:!1},q:{h:"",p:1883,u:"",a:"",b:"",s:{e:!1,c:!1,r:!0,k:!1}},o:{e:"",c:"",u1:"",u2:"",u3:""},t:{t:[0,0,0,0,0,0,0,0,0,0],h:1},p:{e:!1,t:"",r:"",c:"",m:1,f:null},d:{s:!1,t:!1,l:5},u:{i:0,e:0,v:0,a:0,r:0,c:0,t:0,p:0,d:0,m:0,s:0},i:{h:{p:null,u:!0},a:null,l:{p:null,i:!1},r:{r:null,g:null,b:null,i:!1},t:{d:null,a:null},v:{p:null,d:{v:null,g:null},o:null,m:null,b:null}},h:{t:"",h:"",n:""}};$i.subscribe(ze=>{ze.version&&(l(3,a=ze),l(1,o=!1))}),Hp();let c=!1,f=!1;async function p(){if(confirm("Are you sure you want to factory reset the device?")){l(4,c=!0);const ze=new URLSearchParams;ze.append("perform","true");let vl=await(await fetch("/reset",{method:"POST",body:ze})).json();l(4,c=!1),l(5,f=vl.success)}}async function _(ze){l(2,r=!0);const ke=new FormData(ze.target),vl=new URLSearchParams;for(let It of ke){const[Ui,Gl]=It;vl.append(Ui,Gl)}let Al=await(await fetch("/save",{method:"POST",body:vl})).json();Ht.update(It=>(It.booting=Al.reboot,It.ui=a.u,It)),l(2,r=!1),oi("/")}const b=function(){confirm("Are you sure you want to reboot the device?")&&(Ht.update(ze=>(ze.booting=!0,ze)),d0())};async function d(){confirm("Are you sure you want to delete CA?")&&(await(await fetch("/mqtt-ca",{method:"POST"})).text(),$i.update(ke=>(ke.q.s.c=!1,ke)))}async function v(){confirm("Are you sure you want to delete cert?")&&(await(await fetch("/mqtt-cert",{method:"POST"})).text(),$i.update(ke=>(ke.q.s.r=!1,ke)))}async function g(){confirm("Are you sure you want to delete key?")&&(await(await fetch("/mqtt-key",{method:"POST"})).text(),$i.update(ke=>(ke.q.s.k=!1,ke)))}const T=function(){a.q.s.e?a.q.p==1883&&l(3,a.q.p=8883,a):a.q.p==8883&&l(3,a.q.p=1883,a)};let C=44;function $(){a.g.h=this.value,l(3,a)}function M(){a.g.t=_t(this),l(3,a)}function F(){a.p.r=_t(this),l(3,a)}function S(){a.p.c=_t(this),l(3,a)}function D(){a.p.f=fe(this.value),l(3,a)}function A(){a.p.m=fe(this.value),l(3,a)}function E(){a.p.e=this.checked,l(3,a)}function Y(){a.p.t=this.value,l(3,a)}function R(){a.g.s=_t(this),l(3,a)}function U(){a.g.u=this.value,l(3,a)}function H(){a.g.p=this.value,l(3,a)}function z(){a.m.i=this.checked,l(3,a)}function q(){a.m.b=_t(this),l(3,a)}function L(){a.m.p=_t(this),l(3,a)}function B(){a.m.s=fe(this.value),l(3,a)}function O(){a.m.d=_t(this),l(3,a)}function j(){a.m.f=fe(this.value),l(3,a)}function G(){a.m.r=fe(this.value),l(3,a)}function te(){a.m.e.e=this.checked,l(3,a)}function le(){a.m.e.k=this.value,l(3,a)}function pe(){a.m.e.a=this.value,l(3,a)}function ie(){a.m.m.e=this.checked,l(3,a)}function Pe(){a.m.m.w=fe(this.value),l(3,a)}function je(){a.m.m.v=fe(this.value),l(3,a)}function De(){a.m.m.a=fe(this.value),l(3,a)}function We(){a.m.m.c=fe(this.value),l(3,a)}function be(){a.w.s=this.value,l(3,a)}function ye(){a.w.p=this.value,l(3,a)}function Re(){a.w.z=_t(this),l(3,a)}function ge(){a.w.w=fe(this.value),l(3,a)}function ae(){a.w.a=this.checked,l(3,a)}function $e(){a.w.b=this.checked,l(3,a)}function J(){a.n.m=_t(this),l(3,a)}function se(){a.n.i=this.value,l(3,a)}function Fe(){a.n.s=_t(this),l(3,a)}function Le(){a.n.g=this.value,l(3,a)}function _e(){a.n.d1=this.value,l(3,a)}function Ce(){a.n.d2=this.value,l(3,a)}function Ne(){a.n.d=this.checked,l(3,a)}function de(){a.n.h=this.checked,l(3,a)}function Te(){a.n.n1=this.value,l(3,a)}function ee(){a.q.s.e=this.checked,l(3,a)}function oe(){a.q.h=this.value,l(3,a)}function Ue(){a.q.p=fe(this.value),l(3,a)}function ue(){a.q.u=this.value,l(3,a)}function ve(){a.q.a=this.value,l(3,a)}function dt(){a.q.c=this.value,l(3,a)}function Wl(){a.q.m=_t(this),l(3,a)}function tl(){a.q.b=this.value,l(3,a)}function ct(){a.o.e=this.value,l(3,a)}function Ml(){a.o.c=this.value,l(3,a)}function pl(){a.o.u1=this.value,l(3,a)}function jt(){a.o.u2=this.value,l(3,a)}function vt(){a.o.u3=this.value,l(3,a)}function Qe(){a.h.t=this.value,l(3,a)}function Xe(){a.h.h=this.value,l(3,a)}function Ze(){a.h.n=this.value,l(3,a)}function He(ze){a.t.t[ze]=fe(this.value),l(3,a)}function Je(){a.t.h=fe(this.value),l(3,a)}function Ge(ze){a.u[ze.key]=_t(this),l(3,a)}function xe(){a.i.h.u=this.checked,l(3,a)}function et(){a.i.h.p=_t(this),l(3,a)}function re(){a.i.a=fe(this.value),l(3,a)}function he(){a.i.l.i=this.checked,l(3,a)}function Ai(){a.i.l.p=fe(this.value),l(3,a)}function _l(){a.i.r.i=this.checked,l(3,a)}function _n(){a.i.r.r=fe(this.value),l(3,a)}function St(){a.i.r.g=fe(this.value),l(3,a)}function Ei(){a.i.r.b=fe(this.value),l(3,a)}function Ii(){a.i.t.d=fe(this.value),l(3,a)}function Fi(){a.i.t.a=fe(this.value),l(3,a)}function dl(){a.i.v.p=fe(this.value),l(3,a)}function Ri(){a.i.v.d.v=fe(this.value),l(3,a)}function Li(){a.i.v.d.g=fe(this.value),l(3,a)}function Oi(){a.i.v.o=fe(this.value),l(3,a)}function Mt(){a.i.v.m=fe(this.value),l(3,a)}function Pl(){a.i.v.b=fe(this.value),l(3,a)}function Nl(){a.d.s=this.checked,l(3,a)}function Dl(){a.d.t=this.checked,l(3,a)}function qi(){a.d.l=_t(this),l(3,a)}return t.$$set=ze=>{"sysinfo"in ze&&l(0,n=ze.sysinfo)},t.$$.update=()=>{t.$$.dirty[0]&1&&l(6,C=n.chip=="esp8266"?16:n.chip=="esp32s2"?44:39)},[n,o,r,a,c,f,C,i,p,_,b,d,v,g,T,$,M,F,S,D,A,E,Y,R,U,H,z,q,L,B,O,j,G,te,le,pe,ie,Pe,je,De,We,be,ye,Re,ge,ae,$e,J,se,Fe,Le,_e,Ce,Ne,de,Te,ee,oe,Ue,ue,ve,dt,Wl,tl,ct,Ml,pl,jt,vt,Qe,Xe,Ze,He,Je,Ge,xe,et,re,he,Ai,_l,_n,St,Ei,Ii,Fi,dl,Ri,Li,Oi,Mt,Pl,Nl,Dl,qi]}class h0 extends Me{constructor(e){super(),Se(this,e,v0,_0,we,{sysinfo:0},null,[-1,-1,-1,-1])}}function Af(t,e,l){const n=t.slice();return n[20]=e[l],n}function b0(t){let e=ce(t[1].chip,t[1].board)+"",l;return{c(){l=y(e)},m(n,i){w(n,l,i)},p(n,i){i&2&&e!==(e=ce(n[1].chip,n[1].board)+"")&&W(l,e)},d(n){n&&k(l)}}}function Ef(t){let e,l,n=t[1].apmac+"",i,o,r,a,c,f,p,_,b,d=xr(t[1])+"",v,g,T=t[1].boot_reason+"",C,$,M=t[1].ex_cause+"",F,S,D;const A=[k0,g0],E=[];function Y(R,U){return R[0].u>0?0:1}return c=Y(t),f=E[c]=A[c](t),{c(){e=m("div"),l=y("AP MAC: "),i=y(n),o=h(),r=m("div"),a=y(`Last boot: - `),f.c(),p=h(),_=m("div"),b=y("Reason: "),v=y(d),g=y(" ("),C=y(T),$=y("/"),F=y(M),S=y(")"),u(e,"class","my-2"),u(r,"class","my-2"),u(_,"class","my-2")},m(R,U){w(R,e,U),s(e,l),s(e,i),w(R,o,U),w(R,r,U),s(r,a),E[c].m(r,null),w(R,p,U),w(R,_,U),s(_,b),s(_,v),s(_,g),s(_,C),s(_,$),s(_,F),s(_,S),D=!0},p(R,U){(!D||U&2)&&n!==(n=R[1].apmac+"")&&W(i,n);let H=c;c=Y(R),c===H?E[c].p(R,U):(Ae(),I(E[H],1,1,()=>{E[H]=null}),Ee(),f=E[c],f?f.p(R,U):(f=E[c]=A[c](R),f.c()),P(f,1),f.m(r,null)),(!D||U&2)&&d!==(d=xr(R[1])+"")&&W(v,d),(!D||U&2)&&T!==(T=R[1].boot_reason+"")&&W(C,T),(!D||U&2)&&M!==(M=R[1].ex_cause+"")&&W(F,M)},i(R){D||(P(f),D=!0)},o(R){I(f),D=!1},d(R){R&&k(e),R&&k(o),R&&k(r),E[c].d(),R&&k(p),R&&k(_)}}}function g0(t){let e;return{c(){e=y("-")},m(l,n){w(l,e,n)},p:ne,i:ne,o:ne,d(l){l&&k(e)}}}function k0(t){let e,l;return e=new Gc({props:{timestamp:new Date(new Date().getTime()-t[0].u*1e3),fullTimeColor:""}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.timestamp=new Date(new Date().getTime()-n[0].u*1e3)),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function w0(t){let e;return{c(){e=m("span"),e.textContent="Update consents",u(e,"class","btn-pri-sm")},m(l,n){w(l,e,n)},p:ne,d(l){l&&k(e)}}}function If(t){let e,l,n,i,o,r=Ts(t[1].meter.mfg)+"",a,c,f,p,_=t[1].meter.model+"",b,d,v,g,T=t[1].meter.id+"",C;return{c(){e=m("div"),l=m("strong"),l.textContent="Meter",n=h(),i=m("div"),o=y("Manufacturer: "),a=y(r),c=h(),f=m("div"),p=y("Model: "),b=y(_),d=h(),v=m("div"),g=y("ID: "),C=y(T),u(l,"class","text-sm"),u(i,"class","my-2"),u(f,"class","my-2"),u(v,"class","my-2"),u(e,"class","cnt")},m($,M){w($,e,M),s(e,l),s(e,n),s(e,i),s(i,o),s(i,a),s(e,c),s(e,f),s(f,p),s(f,b),s(e,d),s(e,v),s(v,g),s(v,C)},p($,M){M&2&&r!==(r=Ts($[1].meter.mfg)+"")&&W(a,r),M&2&&_!==(_=$[1].meter.model+"")&&W(b,_),M&2&&T!==(T=$[1].meter.id+"")&&W(C,T)},d($){$&&k(e)}}}function Ff(t){let e,l,n,i,o,r=t[1].net.ip+"",a,c,f,p,_=t[1].net.mask+"",b,d,v,g,T=t[1].net.gw+"",C,$,M,F,S=t[1].net.dns1+"",D,A,E=t[1].net.dns2&&Rf(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Network",n=h(),i=m("div"),o=y("IP: "),a=y(r),c=h(),f=m("div"),p=y("Mask: "),b=y(_),d=h(),v=m("div"),g=y("Gateway: "),C=y(T),$=h(),M=m("div"),F=y("DNS: "),D=y(S),A=h(),E&&E.c(),u(l,"class","text-sm"),u(i,"class","my-2"),u(f,"class","my-2"),u(v,"class","my-2"),u(M,"class","my-2"),u(e,"class","cnt")},m(Y,R){w(Y,e,R),s(e,l),s(e,n),s(e,i),s(i,o),s(i,a),s(e,c),s(e,f),s(f,p),s(f,b),s(e,d),s(e,v),s(v,g),s(v,C),s(e,$),s(e,M),s(M,F),s(M,D),s(M,A),E&&E.m(M,null)},p(Y,R){R&2&&r!==(r=Y[1].net.ip+"")&&W(a,r),R&2&&_!==(_=Y[1].net.mask+"")&&W(b,_),R&2&&T!==(T=Y[1].net.gw+"")&&W(C,T),R&2&&S!==(S=Y[1].net.dns1+"")&&W(D,S),Y[1].net.dns2?E?E.p(Y,R):(E=Rf(Y),E.c(),E.m(M,null)):E&&(E.d(1),E=null)},d(Y){Y&&k(e),E&&E.d()}}}function Rf(t){let e,l=t[1].net.dns2+"",n;return{c(){e=y("/ "),n=y(l)},m(i,o){w(i,e,o),w(i,n,o)},p(i,o){o&2&&l!==(l=i[1].net.dns2+"")&&W(n,l)},d(i){i&&k(e),i&&k(n)}}}function Lf(t){let e,l,n,i=t[1].upgrade.t+"",o,r,a=t[1].version+"",c,f,p=t[1].upgrade.x+"",_,b,d=t[1].upgrade.e+"",v,g;return{c(){e=m("div"),l=m("div"),n=y("Previous upgrade attempt ("),o=y(i),r=y(") does not match current version ("),c=y(a),f=y(") ["),_=y(p),b=y("/"),v=y(d),g=y("]"),u(l,"class","bd-yellow"),u(e,"class","my-2")},m(T,C){w(T,e,C),s(e,l),s(l,n),s(l,o),s(l,r),s(l,c),s(l,f),s(l,_),s(l,b),s(l,v),s(l,g)},p(T,C){C&2&&i!==(i=T[1].upgrade.t+"")&&W(o,i),C&2&&a!==(a=T[1].version+"")&&W(c,a),C&2&&p!==(p=T[1].upgrade.x+"")&&W(_,p),C&2&&d!==(d=T[1].upgrade.e+"")&&W(v,d)},d(T){T&&k(e)}}}function Of(t){let e,l,n,i=t[2].tag_name+"",o,r,a,c,f,p,_=(t[1].security==0||t[0].a)&&t[1].fwconsent===1&&t[2]&&t[2].tag_name!=t[1].version&&qf(t),b=t[1].fwconsent===2&&Uf();return{c(){e=m("div"),l=y(`Latest version: - `),n=m("a"),o=y(i),a=h(),_&&_.c(),c=h(),b&&b.c(),f=Ke(),u(n,"href",r=t[2].html_url),u(n,"class","ml-2 text-blue-600 hover:text-blue-800"),u(n,"target","_blank"),u(n,"rel","noreferrer"),u(e,"class","my-2 flex")},m(d,v){w(d,e,v),s(e,l),s(e,n),s(n,o),s(e,a),_&&_.m(e,null),w(d,c,v),b&&b.m(d,v),w(d,f,v),p=!0},p(d,v){(!p||v&4)&&i!==(i=d[2].tag_name+"")&&W(o,i),(!p||v&4&&r!==(r=d[2].html_url))&&u(n,"href",r),(d[1].security==0||d[0].a)&&d[1].fwconsent===1&&d[2]&&d[2].tag_name!=d[1].version?_?(_.p(d,v),v&7&&P(_,1)):(_=qf(d),_.c(),P(_,1),_.m(e,null)):_&&(Ae(),I(_,1,1,()=>{_=null}),Ee()),d[1].fwconsent===2?b||(b=Uf(),b.c(),b.m(f.parentNode,f)):b&&(b.d(1),b=null)},i(d){p||(P(_),p=!0)},o(d){I(_),p=!1},d(d){d&&k(e),_&&_.d(),d&&k(c),b&&b.d(d),d&&k(f)}}}function qf(t){let e,l,n,i,o,r;return n=new Bc({}),{c(){e=m("div"),l=m("button"),Z(n.$$.fragment),u(e,"class","flex-none ml-2 text-green-500"),u(e,"title","Install this version")},m(a,c){w(a,e,c),s(e,l),Q(n,l,null),i=!0,o||(r=K(l,"click",t[10]),o=!0)},p:ne,i(a){i||(P(n.$$.fragment,a),i=!0)},o(a){I(n.$$.fragment,a),i=!1},d(a){a&&k(e),X(n),o=!1,r()}}}function Uf(t){let e;return{c(){e=m("div"),e.innerHTML='
You have disabled one-click firmware upgrade, link to self-upgrade is disabled
',u(e,"class","my-2")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function Hf(t){let e,l=Ss(ce(t[1].chip,t[1].board))+"",n;return{c(){e=m("div"),n=y(l),u(e,"class","bd-red")},m(i,o){w(i,e,o),s(e,n)},p(i,o){o&2&&l!==(l=Ss(ce(i[1].chip,i[1].board))+"")&&W(n,l)},d(i){i&&k(e)}}}function jf(t){let e,l,n,i,o,r;function a(p,_){return p[4].length==0?$0:y0}let c=a(t),f=c(t);return{c(){e=m("div"),l=m("form"),n=m("input"),i=h(),f.c(),lc(n,"display","none"),u(n,"name","file"),u(n,"type","file"),u(n,"accept",".bin"),u(l,"action","/firmware"),u(l,"enctype","multipart/form-data"),u(l,"method","post"),u(l,"autocomplete","off"),u(e,"class","my-2 flex")},m(p,_){w(p,e,_),s(e,l),s(l,n),t[12](n),s(l,i),f.m(l,null),o||(r=[K(n,"change",t[13]),K(l,"submit",t[15])],o=!0)},p(p,_){c===(c=a(p))&&f?f.p(p,_):(f.d(1),f=c(p),f&&(f.c(),f.m(l,null)))},d(p){p&&k(e),t[12](null),f.d(),o=!1,Be(r)}}}function y0(t){let e=t[4][0].name+"",l,n,i;return{c(){l=y(e),n=h(),i=m("button"),i.textContent="Upload",u(i,"type","submit"),u(i,"class","btn-pri-sm float-right")},m(o,r){w(o,l,r),w(o,n,r),w(o,i,r)},p(o,r){r&16&&e!==(e=o[4][0].name+"")&&W(l,e)},d(o){o&&k(l),o&&k(n),o&&k(i)}}}function $0(t){let e,l,n;return{c(){e=m("button"),e.textContent="Select firmware file for upgrade",u(e,"type","button"),u(e,"class","btn-pri-sm float-right")},m(i,o){w(i,e,o),l||(n=K(e,"click",t[14]),l=!0)},p:ne,d(i){i&&k(e),l=!1,n()}}}function Wf(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g=t[9],T=[];for(let S=0;S Include Secrets
(SSID, PSK, passwords and tokens)',c=h(),C&&C.c(),f=h(),p=m("form"),_=m("input"),b=h(),F.c(),u(l,"class","text-sm"),u(a,"class","my-1 mx-3 col-span-2"),u(o,"class","grid grid-cols-2"),u(i,"method","get"),u(i,"action","/configfile.cfg"),u(i,"autocomplete","off"),lc(_,"display","none"),u(_,"name","file"),u(_,"type","file"),u(_,"accept",".cfg"),u(p,"action","/configfile"),u(p,"enctype","multipart/form-data"),u(p,"method","post"),u(p,"autocomplete","off"),u(e,"class","cnt")},m(S,D){w(S,e,D),s(e,l),s(e,n),s(e,i),s(i,o);for(let A=0;A{se=null}),Ee());const ue={};oe&8388608&&(ue.$$scope={dirty:oe,ctx:ee}),Y.$set(ue),ee[1].meter?Fe?Fe.p(ee,oe):(Fe=If(ee),Fe.c(),Fe.m(e,z)):Fe&&(Fe.d(1),Fe=null),ee[1].net?Le?Le.p(ee,oe):(Le=Ff(ee),Le.c(),Le.m(e,q)):Le&&(Le.d(1),Le=null),(!ae||oe&2)&&te!==(te=ee[1].version+"")&&W(le,te),ee[1].upgrade.t&&ee[1].upgrade.t!=ee[1].version?_e?_e.p(ee,oe):(_e=Lf(ee),_e.c(),_e.m(L,ie)):_e&&(_e.d(1),_e=null),ee[2]?Ce?(Ce.p(ee,oe),oe&4&&P(Ce,1)):(Ce=Of(ee),Ce.c(),P(Ce,1),Ce.m(L,Pe)):Ce&&(Ae(),I(Ce,1,1,()=>{Ce=null}),Ee()),oe&3&&(je=(ee[1].security==0||ee[0].a)&&ui(ee[1].board)),je?Ne?Ne.p(ee,oe):(Ne=Hf(ee),Ne.c(),Ne.m(L,De)):Ne&&(Ne.d(1),Ne=null),ee[1].security==0||ee[0].a?de?de.p(ee,oe):(de=jf(ee),de.c(),de.m(L,null)):de&&(de.d(1),de=null),ee[1].security==0||ee[0].a?Te?Te.p(ee,oe):(Te=Wf(ee),Te.c(),Te.m(e,null)):Te&&(Te.d(1),Te=null);const ve={};oe&32&&(ve.active=ee[5]),ye.$set(ve);const dt={};oe&256&&(dt.active=ee[8]),ge.$set(dt)},i(ee){ae||(P(T.$$.fragment,ee),P(se),P(Y.$$.fragment,ee),P(Ce),P(ye.$$.fragment,ee),P(ge.$$.fragment,ee),ae=!0)},o(ee){I(T.$$.fragment,ee),I(se),I(Y.$$.fragment,ee),I(Ce),I(ye.$$.fragment,ee),I(ge.$$.fragment,ee),ae=!1},d(ee){ee&&k(e),X(T),se&&se.d(),X(Y),Fe&&Fe.d(),Le&&Le.d(),_e&&_e.d(),Ce&&Ce.d(),Ne&&Ne.d(),de&&de.d(),Te&&Te.d(),ee&&k(be),X(ye,ee),ee&&k(Re),X(ge,ee),$e=!1,J()}}}async function M0(){await(await fetch("/reboot",{method:"POST"})).json()}function P0(t,e,l){let{data:n}=e,{sysinfo:i}=e,o=[{name:"WiFi",key:"iw"},{name:"MQTT",key:"im"},{name:"Web",key:"ie"},{name:"Meter",key:"it"},{name:"Thresholds",key:"ih"},{name:"GPIO",key:"ig"},{name:"NTP",key:"in"},{name:"Price API",key:"is"}],r={};So.subscribe(A=>{l(2,r=Wc(i.version,A)),r||l(2,r=A[0])});function a(){confirm("Do you want to upgrade this device to "+r.tag_name+"?")&&(i.board!=2&&i.board!=4&&i.board!=7||confirm(Ss(ce(i.chip,i.board))))&&(Ht.update(A=>(A.upgrading=!0,A)),jc(r.tag_name))}const c=function(){confirm("Are you sure you want to reboot the device?")&&(Ht.update(A=>(A.booting=!0,A)),M0())};let f,p=[],_=!1,b,d=[],v=!1;yo();function g(A){$s[A?"unshift":"push"](()=>{f=A,l(3,f)})}function T(){p=this.files,l(4,p)}const C=()=>{f.click()},$=()=>l(5,_=!0);function M(A){$s[A?"unshift":"push"](()=>{b=A,l(6,b)})}function F(){d=this.files,l(7,d)}const S=()=>{b.click()},D=()=>l(8,v=!0);return t.$$set=A=>{"data"in A&&l(0,n=A.data),"sysinfo"in A&&l(1,i=A.sysinfo)},[n,i,r,f,p,_,b,d,v,o,a,c,g,T,C,$,M,F,S,D]}class N0 extends Me{constructor(e){super(),Se(this,e,P0,S0,we,{data:0,sysinfo:1})}}function zf(t){let e,l,n=ce(t[0],7)+"",i,o,r=ce(t[0],5)+"",a,c,f=ce(t[0],4)+"",p,_,b=ce(t[0],3)+"",d,v,g,T,C=ce(t[0],2)+"",$,M,F=ce(t[0],1)+"",S,D,A=ce(t[0],0)+"",E,Y,R,U,H=ce(t[0],101)+"",z,q,L=ce(t[0],100)+"",B;return{c(){e=m("optgroup"),l=m("option"),i=y(n),o=m("option"),a=y(r),c=m("option"),p=y(f),_=m("option"),d=y(b),v=h(),g=m("optgroup"),T=m("option"),$=y(C),M=m("option"),S=y(F),D=m("option"),E=y(A),Y=h(),R=m("optgroup"),U=m("option"),z=y(H),q=m("option"),B=y(L),l.__value=7,l.value=l.__value,o.__value=5,o.value=o.__value,c.__value=4,c.value=c.__value,_.__value=3,_.value=_.__value,u(e,"label","amsleser.no"),T.__value=2,T.value=T.__value,M.__value=1,M.value=M.__value,D.__value=0,D.value=D.__value,u(g,"label","Custom hardware"),U.__value=101,U.value=U.__value,q.__value=100,q.value=q.__value,u(R,"label","Generic hardware")},m(O,j){w(O,e,j),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),s(e,_),s(_,d),w(O,v,j),w(O,g,j),s(g,T),s(T,$),s(g,M),s(M,S),s(g,D),s(D,E),w(O,Y,j),w(O,R,j),s(R,U),s(U,z),s(R,q),s(q,B)},p(O,j){j&1&&n!==(n=ce(O[0],7)+"")&&W(i,n),j&1&&r!==(r=ce(O[0],5)+"")&&W(a,r),j&1&&f!==(f=ce(O[0],4)+"")&&W(p,f),j&1&&b!==(b=ce(O[0],3)+"")&&W(d,b),j&1&&C!==(C=ce(O[0],2)+"")&&W($,C),j&1&&F!==(F=ce(O[0],1)+"")&&W(S,F),j&1&&A!==(A=ce(O[0],0)+"")&&W(E,A),j&1&&H!==(H=ce(O[0],101)+"")&&W(z,H),j&1&&L!==(L=ce(O[0],100)+"")&&W(B,L)},d(O){O&&k(e),O&&k(v),O&&k(g),O&&k(Y),O&&k(R)}}}function Yf(t){let e,l,n=ce(t[0],201)+"",i,o,r=ce(t[0],202)+"",a,c,f=ce(t[0],203)+"",p,_,b=ce(t[0],200)+"",d;return{c(){e=m("optgroup"),l=m("option"),i=y(n),o=m("option"),a=y(r),c=m("option"),p=y(f),_=m("option"),d=y(b),l.__value=201,l.value=l.__value,o.__value=202,o.value=o.__value,c.__value=203,c.value=c.__value,_.__value=200,_.value=_.__value,u(e,"label","Generic hardware")},m(v,g){w(v,e,g),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),s(e,_),s(_,d)},p(v,g){g&1&&n!==(n=ce(v[0],201)+"")&&W(i,n),g&1&&r!==(r=ce(v[0],202)+"")&&W(a,r),g&1&&f!==(f=ce(v[0],203)+"")&&W(p,f),g&1&&b!==(b=ce(v[0],200)+"")&&W(d,b)},d(v){v&&k(e)}}}function Kf(t){let e,l,n=ce(t[0],7)+"",i,o,r=ce(t[0],6)+"",a,c,f=ce(t[0],5)+"",p,_,b,d,v=ce(t[0],51)+"",g,T,C=ce(t[0],50)+"",$;return{c(){e=m("optgroup"),l=m("option"),i=y(n),o=m("option"),a=y(r),c=m("option"),p=y(f),_=h(),b=m("optgroup"),d=m("option"),g=y(v),T=m("option"),$=y(C),l.__value=7,l.value=l.__value,o.__value=6,o.value=o.__value,c.__value=5,c.value=c.__value,u(e,"label","amsleser.no"),d.__value=51,d.value=d.__value,T.__value=50,T.value=T.__value,u(b,"label","Generic hardware")},m(M,F){w(M,e,F),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),w(M,_,F),w(M,b,F),s(b,d),s(d,g),s(b,T),s(T,$)},p(M,F){F&1&&n!==(n=ce(M[0],7)+"")&&W(i,n),F&1&&r!==(r=ce(M[0],6)+"")&&W(a,r),F&1&&f!==(f=ce(M[0],5)+"")&&W(p,f),F&1&&v!==(v=ce(M[0],51)+"")&&W(g,v),F&1&&C!==(C=ce(M[0],50)+"")&&W($,C)},d(M){M&&k(e),M&&k(_),M&&k(b)}}}function Vf(t){let e,l,n=ce(t[0],8)+"",i,o,r,a,c=ce(t[0],71)+"",f,p,_=ce(t[0],70)+"",b;return{c(){e=m("optgroup"),l=m("option"),i=y(n),o=h(),r=m("optgroup"),a=m("option"),f=y(c),p=m("option"),b=y(_),l.__value=8,l.value=l.__value,u(e,"label","Custom hardware"),a.__value=71,a.value=a.__value,p.__value=70,p.value=p.__value,u(r,"label","Generic hardware")},m(d,v){w(d,e,v),s(e,l),s(l,i),w(d,o,v),w(d,r,v),s(r,a),s(a,f),s(r,p),s(p,b)},p(d,v){v&1&&n!==(n=ce(d[0],8)+"")&&W(i,n),v&1&&c!==(c=ce(d[0],71)+"")&&W(f,c),v&1&&_!==(_=ce(d[0],70)+"")&&W(b,_)},d(d){d&&k(e),d&&k(o),d&&k(r)}}}function Qf(t){let e,l,n=ce(t[0],200)+"",i;return{c(){e=m("optgroup"),l=m("option"),i=y(n),l.__value=200,l.value=l.__value,u(e,"label","Generic hardware")},m(o,r){w(o,e,r),s(e,l),s(l,i)},p(o,r){r&1&&n!==(n=ce(o[0],200)+"")&&W(i,n)},d(o){o&&k(e)}}}function D0(t){let e,l,n,i,o,r,a,c=t[0]=="esp8266"&&zf(t),f=t[0]=="esp32"&&Yf(t),p=t[0]=="esp32s2"&&Kf(t),_=t[0]=="esp32c3"&&Vf(t),b=t[0]=="esp32solo"&&Qf(t);return{c(){e=m("option"),l=h(),c&&c.c(),n=h(),f&&f.c(),i=h(),p&&p.c(),o=h(),_&&_.c(),r=h(),b&&b.c(),a=Ke(),e.__value=-1,e.value=e.__value},m(d,v){w(d,e,v),w(d,l,v),c&&c.m(d,v),w(d,n,v),f&&f.m(d,v),w(d,i,v),p&&p.m(d,v),w(d,o,v),_&&_.m(d,v),w(d,r,v),b&&b.m(d,v),w(d,a,v)},p(d,[v]){d[0]=="esp8266"?c?c.p(d,v):(c=zf(d),c.c(),c.m(n.parentNode,n)):c&&(c.d(1),c=null),d[0]=="esp32"?f?f.p(d,v):(f=Yf(d),f.c(),f.m(i.parentNode,i)):f&&(f.d(1),f=null),d[0]=="esp32s2"?p?p.p(d,v):(p=Kf(d),p.c(),p.m(o.parentNode,o)):p&&(p.d(1),p=null),d[0]=="esp32c3"?_?_.p(d,v):(_=Vf(d),_.c(),_.m(r.parentNode,r)):_&&(_.d(1),_=null),d[0]=="esp32solo"?b?b.p(d,v):(b=Qf(d),b.c(),b.m(a.parentNode,a)):b&&(b.d(1),b=null)},i:ne,o:ne,d(d){d&&k(e),d&&k(l),c&&c.d(d),d&&k(n),f&&f.d(d),d&&k(i),p&&p.d(d),d&&k(o),_&&_.d(d),d&&k(r),b&&b.d(d),d&&k(a)}}}function A0(t,e,l){let{chip:n}=e;return t.$$set=i=>{"chip"in i&&l(0,n=i.chip)},[n]}class E0 extends Me{constructor(e){super(),Se(this,e,A0,D0,we,{chip:0})}}function Xf(t){let e;return{c(){e=m("div"),e.textContent="WARNING: Changing this configuration will affect basic configuration of your device. Only make changes here if instructed by vendor",u(e,"class","bd-red")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function Zf(t){let e,l,n,i,o,r,a;return r=new Yc({props:{chip:t[0].chip}}),{c(){e=m("div"),l=y("HAN GPIO"),n=m("br"),i=h(),o=m("select"),Z(r.$$.fragment),u(o,"name","vh"),u(o,"class","in-s"),u(e,"class","my-3")},m(c,f){w(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),Q(r,o,null),a=!0},p(c,f){const p={};f&1&&(p.chip=c[0].chip),r.$set(p)},i(c){a||(P(r.$$.fragment,c),a=!0)},o(c){I(r.$$.fragment,c),a=!1},d(c){c&&k(e),X(r)}}}function I0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q=t[0].usrcfg&&Xf();v=new E0({props:{chip:t[0].chip}});let L=t[0].board&&t[0].board>20&&Zf(t);return R=new Et({props:{active:t[1],message:"Saving device configuration"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("input"),o=h(),r=m("strong"),r.textContent="Initial configuration",a=h(),q&&q.c(),c=h(),f=m("div"),p=y("Board type"),_=m("br"),b=h(),d=m("select"),Z(v.$$.fragment),g=h(),L&&L.c(),T=h(),C=m("div"),$=m("label"),M=m("input"),F=y(" Clear all other configuration"),S=h(),D=m("div"),D.innerHTML='',A=h(),E=m("span"),E.textContent=" ",Y=h(),Z(R.$$.fragment),u(i,"type","hidden"),u(i,"name","v"),i.value="true",u(r,"class","text-sm"),u(d,"name","vb"),u(d,"class","in-s"),t[0].board===void 0&&tt(()=>t[4].call(d)),u(f,"class","my-3"),u(M,"type","checkbox"),u(M,"name","vr"),M.__value="true",M.value=M.__value,u(M,"class","rounded mb-1"),u(C,"class","my-3"),u(D,"class","my-3"),u(E,"class","clear-both"),u(n,"autocomplete","off"),u(l,"class","cnt"),u(e,"class","grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2")},m(B,O){w(B,e,O),s(e,l),s(l,n),s(n,i),s(n,o),s(n,r),s(n,a),q&&q.m(n,null),s(n,c),s(n,f),s(f,p),s(f,_),s(f,b),s(f,d),Q(v,d,null),qe(d,t[0].board,!0),s(n,g),L&&L.m(n,null),s(n,T),s(n,C),s(C,$),s($,M),M.checked=t[2],s($,F),s(n,S),s(n,D),s(n,A),s(n,E),w(B,Y,O),Q(R,B,O),U=!0,H||(z=[K(d,"change",t[4]),K(M,"change",t[5]),K(n,"submit",Ms(t[3]))],H=!0)},p(B,[O]){B[0].usrcfg?q||(q=Xf(),q.c(),q.m(n,c)):q&&(q.d(1),q=null);const j={};O&1&&(j.chip=B[0].chip),v.$set(j),O&1&&qe(d,B[0].board),B[0].board&&B[0].board>20?L?(L.p(B,O),O&1&&P(L,1)):(L=Zf(B),L.c(),P(L,1),L.m(n,T)):L&&(Ae(),I(L,1,1,()=>{L=null}),Ee()),O&4&&(M.checked=B[2]);const G={};O&2&&(G.active=B[1]),R.$set(G)},i(B){U||(P(v.$$.fragment,B),P(L),P(R.$$.fragment,B),U=!0)},o(B){I(v.$$.fragment,B),I(L),I(R.$$.fragment,B),U=!1},d(B){B&&k(e),q&&q.d(),X(v),L&&L.d(),B&&k(Y),X(R,B),H=!1,Be(z)}}}function F0(t,e,l){let{sysinfo:n={}}=e,i=!1;async function o(f){l(1,i=!0);const p=new FormData(f.target),_=new URLSearchParams;for(let v of p){const[g,T]=v;_.append(g,T)}let d=await(await fetch("/save",{method:"POST",body:_})).json();l(1,i=!1),Ht.update(v=>(v.vndcfg=d.success,v.booting=d.reboot,v)),oi(n.usrcfg?"/":"/setup")}let r=!1;function a(){n.board=_t(this),l(0,n)}function c(){r=this.checked,l(2,r),l(0,n)}return t.$$set=f=>{"sysinfo"in f&&l(0,n=f.sysinfo)},t.$$.update=()=>{t.$$.dirty&1&&l(2,r=!n.usrcfg)},[n,i,r,o,a,c]}class R0 extends Me{constructor(e){super(),Se(this,e,F0,I0,we,{sysinfo:0})}}function Jf(t){let e,l,n,i,o,r,a,c;return a=new Kc({}),{c(){e=m("br"),l=h(),n=m("div"),i=m("input"),o=h(),r=m("select"),Z(a.$$.fragment),u(i,"name","si"),u(i,"type","text"),u(i,"class","in-f w-full"),i.required=t[1],u(r,"name","su"),u(r,"class","in-l"),r.required=t[1],u(n,"class","flex")},m(f,p){w(f,e,p),w(f,l,p),w(f,n,p),s(n,i),s(n,o),s(n,r),Q(a,r,null),c=!0},p(f,p){(!c||p&2)&&(i.required=f[1]),(!c||p&2)&&(r.required=f[1])},i(f){c||(P(a.$$.fragment,f),c=!0)},o(f){I(a.$$.fragment,f),c=!1},d(f){f&&k(e),f&&k(l),f&&k(n),X(a)}}}function xf(t){let e;return{c(){e=m("div"),e.innerHTML=`
Gateway
+Occurred in: ${i}`:"",u=ko(t),a=fc(e)?e(u):e;return`<${u}> ${a}${o}`}const Mc=t=>(...e)=>t(A0(...e)),Sc=Mc(t=>{throw new Error(t)}),ws=Mc(console.warn),Ta=4,E0=3,P0=2,D0=1,I0=1;function O0(t,e){const l=t.default?0:vl(t.fullPath).reduce((n,i)=>{let o=n;return o+=Ta,k0(i)?o+=I0:w0(i)?o+=P0:bc(i)?o-=Ta+D0:o+=E0,o},0);return{route:t,score:l,index:e}}function R0(t){return t.map(O0).sort((e,l)=>e.scorel.score?-1:e.index-l.index)}function Tc(t,e){let l,n;const[i]=e.split("?"),o=vl(i),u=o[0]==="",a=R0(t);for(let c=0,f=a.length;c({...p,params:h,uri:$});if(p.default){n=d(e);continue}const v=vl(p.fullPath),g=Math.max(o.length,v.length);let E=0;for(;E{f===".."?c.pop():f!=="."&&c.push(f)}),Gs(`/${c.join("/")}`,n)}function $a(t,e){const{pathname:l,hash:n="",search:i="",state:o}=t,u=vl(e,!0),a=vl(l,!0);for(;u.length;)u[0]!==a[0]&&Sc(mn,`Invalid state: All locations must begin with the basepath "${e}", found "${l}"`),u.shift(),a.shift();return{pathname:Ni(...a),hash:n,search:i,state:o}}const Na=t=>t.length===1?"":t,wo=t=>{const e=t.indexOf("?"),l=t.indexOf("#"),n=e!==-1,i=l!==-1,o=i?Na(ki(t,l)):"",u=i?ki(t,0,l):t,a=n?Na(ki(u,e)):"";return{pathname:(n?ki(u,0,e):u)||"/",search:a,hash:o}},F0=t=>{const{pathname:e,search:l,hash:n}=t;return e+l+n};function q0(t,e,l){return Ni(l,L0(t,e))}function B0(t,e){const l=bo(y0(t)),n=vl(l,!0),i=vl(e,!0).slice(0,n.length),o=$c({fullPath:l},Ni(...i));return o&&o.uri}const Vs="POP",U0="PUSH",j0="REPLACE";function Ks(t){return{...t.location,pathname:encodeURI(decodeURI(t.location.pathname)),state:t.history.state,_key:t.history.state&&t.history.state._key||"initial"}}function H0(t){let e=[],l=Ks(t),n=Vs;const i=(o=e)=>o.forEach(u=>u({location:l,action:n}));return{get location(){return l},listen(o){e.push(o);const u=()=>{l=Ks(t),n=Vs,i([o])};i([o]);const a=pc(t,"popstate",u);return()=>{a(),e=e.filter(c=>c!==o)}},navigate(o,u){const{state:a={},replace:c=!1}=u||{};if(n=c?j0:U0,cc(o))u&&ws(Cc,"Navigation options (state or replace) are not supported, when passing a number as the first argument to navigate. They are ignored."),n=Vs,t.history.go(o);else{const f={...a,_key:v0()};try{t.history[c?"replaceState":"pushState"](f,"",o)}catch{t.location[c?"replace":"assign"](o)}}l=Ks(t),i()}}}function Ys(t,e){return{...wo(e),state:t}}function W0(t="/"){let e=0,l=[Ys(null,t)];return{get entries(){return l},get location(){return l[e]},addEventListener(){},removeEventListener(){},history:{get state(){return l[e].state},pushState(n,i,o){e++,l=l.slice(0,e),l.push(Ys(n,o))},replaceState(n,i,o){l[e]=Ys(n,o)},go(n){const i=e+n;i<0||i>l.length-1||(e=i)}}}}const z0=!!(!Wl&&window.document&&window.document.createElement),G0=!Wl&&window.location.origin==="null",Nc=H0(z0&&!G0?window:W0()),{navigate:si}=Nc;let Tl=null,Ac=!0;function V0(t,e){const l=document.querySelectorAll("[data-svnav-router]");for(let n=0;nTl.level||t.level===Tl.level&&V0(t.routerId,Tl.routerId))&&(Tl=t)}function Y0(){Tl=null}function Q0(){Ac=!1}function Aa(t){if(!t)return!1;const e="tabindex";try{if(!t.hasAttribute(e)){t.setAttribute(e,"-1");let l;l=pc(t,"blur",()=>{t.removeAttribute(e),l()})}return t.focus(),document.activeElement===t}catch{return!1}}function X0(t,e){return Number(t.dataset.svnavRouteEnd)===e}function Z0(t){return/^H[1-6]$/i.test(t.tagName)}function Ea(t,e=document){return e.querySelector(t)}function J0(t){let l=Ea(`[data-svnav-route-start="${t}"]`).nextElementSibling;for(;!X0(l,t);){if(Z0(l))return l;const n=Ea("h1,h2,h3,h4,h5,h6",l);if(n)return n;l=l.nextElementSibling}return null}function x0(t){Promise.resolve(ri(t.focusElement)).then(e=>{const l=e||J0(t.id);l||ws(mn,`Could not find an element to focus. You should always render a header for accessibility reasons, or set a custom focus element via the "useFocus" hook. If you don't want this Route or Router to manage focus, pass "primary={false}" to it.`,t,Ss),!Aa(l)&&Aa(document.documentElement)})}const e1=(t,e,l)=>(n,i)=>c0().then(()=>{if(!Tl||Ac){Q0();return}if(n&&x0(Tl.route),t.announcements&&i){const{path:o,fullPath:u,meta:a,params:c,uri:f}=Tl.route,p=t.createAnnouncement({path:o,fullPath:u,meta:a,params:c,uri:f},ri(l));Promise.resolve(p).then(_=>{e.set(_)})}Y0()}),t1="position:fixed;top:-1px;left:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;";function l1(t){let e,l,n=[{role:"status"},{"aria-atomic":"true"},{"aria-live":"polite"},{"data-svnav-announcer":""},_c(t[6],t1)],i={};for(let o=0;o`Navigated to ${x.uri}`,announcements:!0,...v},$=p,M=bo(p),P=Hl(xs),F=Hl(ui),A=!P,I=i1(),D=d&&!(F&&!F.manageFocus),L=it("");_l(t,L,x=>l(0,a=x));const ie=F?F.disableInlineStyles:g,H=it([]);_l(t,H,x=>l(20,u=x));const K=it(null);_l(t,K,x=>l(18,i=x));let G=!1;const Y=A?0:F.level+1,z=A?it((()=>$a(Wl?wo(_):h.location,M))()):P;_l(t,z,x=>l(17,n=x));const Z=it(n);_l(t,Z,x=>l(19,o=x));const V=e1(E,L,z),j=x=>W=>W.filter(U=>U.id!==x);function ee(x){if(Wl){if(G)return;const W=$c(x,n.pathname);if(W)return G=!0,W}else H.update(W=>{const U=j(x.id)(W);return U.push(x),U})}function ue(x){H.update(j(x))}return!A&&p!==Pa&&ws(mn,'Only top-level Routers can have a "basepath" prop. It is ignored.',{basepath:p}),A&&(sc(()=>h.listen(W=>{const U=$a(W.location,M);Z.set(n),z.set(U)})),Mi(xs,z)),Mi(ui,{activeRoute:K,registerRoute:ee,unregisterRoute:ue,manageFocus:D,level:Y,id:I,history:A?h:F.history,basepath:A?M:F.basepath,disableInlineStyles:ie}),t.$$set=x=>{"basepath"in x&&l(11,p=x.basepath),"url"in x&&l(12,_=x.url),"history"in x&&l(13,h=x.history),"primary"in x&&l(14,d=x.primary),"a11y"in x&&l(15,v=x.a11y),"disableInlineStyles"in x&&l(16,g=x.disableInlineStyles),"$$scope"in x&&l(21,f=x.$$scope)},t.$$.update=()=>{if(t.$$.dirty[0]&2048&&p!==$&&ws(mn,'You cannot change the "basepath" prop. It is ignored.'),t.$$.dirty[0]&1179648){const x=Tc(u,n.pathname);K.set(x)}if(t.$$.dirty[0]&655360&&A){const x=!!n.hash,W=!x&&D,U=!x||n.pathname!==o.pathname;V(W,U)}t.$$.dirty[0]&262144&&D&&i&&i.primary&&K0({level:Y,routerId:I,route:i})},[a,E,A,I,D,L,ie,H,K,z,Z,p,_,h,d,v,g,n,i,o,u,f,c]}class o1 extends De{constructor(e){super(),Pe(this,e,s1,n1,$e,{basepath:11,url:12,history:13,primary:14,a11y:15,disableInlineStyles:16},null,[-1,-1])}}const Ec=o1;function Ai(t,e,l=ui,n=mn){Hl(l)||Sc(t,o=>`You cannot use ${o} outside of a ${ko(n)}.`,e)}const r1=t=>{const{subscribe:e}=Hl(t);return{subscribe:e}};function Pc(){return Ai(kc),r1(xs)}function Dc(){const{history:t}=Hl(ui);return t}function Ic(){const t=Hl(vc);return t?h0(t,e=>e.base):it("/")}function Oc(){Ai(yc);const t=Ic(),{basepath:e}=Hl(ui);return n=>q0(n,ri(t),e)}function a1(){Ai(wc);const t=Oc(),{navigate:e}=Dc();return(n,i)=>{const o=cc(n)?n:t(n);return e(o,i)}}const u1=t=>({params:t&16,location:t&8}),Da=t=>({params:Wl?ri(t[10]):t[4],location:t[3],navigate:t[11]});function Ia(t){let e,l;return e=new Ec({props:{primary:t[1],$$slots:{default:[m1]},$$scope:{ctx:t}}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&2&&(o.primary=n[1]),i&528409&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function f1(t){let e;const l=t[18].default,n=po(l,t,t[19],Da);return{c(){n&&n.c()},m(i,o){n&&n.m(i,o),e=!0},p(i,o){n&&n.p&&(!e||o&524312)&&vo(n,l,i,i[19],e?_o(l,i[19],o,u1):ho(i[19]),Da)},i(i){e||(O(n,i),e=!0)},o(i){B(n,i),e=!1},d(i){n&&n.d(i)}}}function c1(t){let e,l,n;const i=[{location:t[3]},{navigate:t[11]},Wl?ri(t[10]):t[4],t[12]];var o=t[0];function u(a){let c={};for(let f=0;f{oe(p,1)}),Oe()}o?(e=ya(o,u()),re(e.$$.fragment),O(e.$$.fragment,1),se(e,l.parentNode,l)):e=null}else o&&e.$set(f)},i(a){n||(e&&O(e.$$.fragment,a),n=!0)},o(a){e&&B(e.$$.fragment,a),n=!1},d(a){a&&w(l),e&&oe(e,a)}}}function m1(t){let e,l,n,i;const o=[c1,f1],u=[];function a(c,f){return c[0]!==null?0:1}return e=a(t),l=u[e]=o[e](t),{c(){l.c(),n=Ve()},m(c,f){u[e].m(c,f),C(c,n,f),i=!0},p(c,f){let p=e;e=a(c),e===p?u[e].p(c,f):(Ie(),B(u[p],1,1,()=>{u[p]=null}),Oe(),l=u[e],l?l.p(c,f):(l=u[e]=o[e](c),l.c()),O(l,1),l.m(n.parentNode,n))},i(c){i||(O(l),i=!0)},o(c){B(l),i=!1},d(c){u[e].d(c),c&&w(n)}}}function p1(t){let e,l,n,i,o,u=[Js(t[7]),{"data-svnav-route-start":t[5]}],a={};for(let _=0;_{c=null}),Oe())},i(_){o||(O(c),o=!0)},o(_){B(c),o=!1},d(_){_&&w(e),_&&w(l),c&&c.d(_),_&&w(n),_&&w(i)}}}const _1=mc();function d1(t,e,l){let n;const i=["path","component","meta","primary"];let o=gs(e,i),u,a,c,f,{$$slots:p={},$$scope:_}=e,{path:h=""}=e,{component:d=null}=e,{meta:v={}}=e,{primary:g=!0}=e;Ai(Ss,e);const E=_1(),{registerRoute:$,unregisterRoute:M,activeRoute:P,disableInlineStyles:F}=Hl(ui);_l(t,P,G=>l(16,u=G));const A=Ic();_l(t,A,G=>l(17,c=G));const I=Pc();_l(t,I,G=>l(3,a=G));const D=it(null);let L;const ie=it(),H=it({});_l(t,H,G=>l(4,f=G)),Mi(vc,ie),Mi(b0,H),Mi(g0,D);const K=a1();return Wl||u0(()=>M(E)),t.$$set=G=>{l(24,e=sl(sl({},e),bs(G))),l(12,o=gs(e,i)),"path"in G&&l(13,h=G.path),"component"in G&&l(0,d=G.component),"meta"in G&&l(14,v=G.meta),"primary"in G&&l(1,g=G.primary),"$$scope"in G&&l(19,_=G.$$scope)},t.$$.update=()=>{if(t.$$.dirty&155658){const G=h==="",Y=Ni(c,h),Q={id:E,path:h,meta:v,default:G,fullPath:G?"":Y,base:G?c:B0(Y,a.pathname),primary:g,focusElement:D};ie.set(Q),l(15,L=$(Q))}if(t.$$.dirty&98304&&l(2,n=!!(L||u&&u.id===E)),t.$$.dirty&98308&&n){const{params:G}=L||u;H.set(G)}},e=bs(e),[d,g,n,a,f,E,P,F,A,I,H,K,o,h,v,L,u,c,p,_]}class v1 extends De{constructor(e){super(),Pe(this,e,d1,p1,$e,{path:13,component:0,meta:14,primary:1})}}const Sl=v1;function h1(t){let e,l,n,i;const o=t[13].default,u=po(o,t,t[12],null);let a=[{href:t[0]},t[2],t[1]],c={};for(let f=0;fl(11,_=D));const P=f0(),F=Oc(),{navigate:A}=Dc();function I(D){P("click",D),d0(D)&&(D.preventDefault(),A(n,{state:E,replace:u||g}))}return t.$$set=D=>{l(19,e=sl(sl({},e),bs(D))),l(18,p=gs(e,f)),"to"in D&&l(5,v=D.to),"replace"in D&&l(6,g=D.replace),"state"in D&&l(7,E=D.state),"getProps"in D&&l(8,$=D.getProps),"$$scope"in D&&l(12,d=D.$$scope)},t.$$.update=()=>{t.$$.dirty&2080&&l(0,n=F(v,_)),t.$$.dirty&2049&&l(10,i=eo(_.pathname,n)),t.$$.dirty&2049&&l(9,o=n===_.pathname),t.$$.dirty&2049&&(u=wo(n)===F0(_)),t.$$.dirty&512&&l(2,a=o?{"aria-current":"page"}:{}),l(1,c=(()=>{if(fc($)){const D=$({location:_,href:n,isPartiallyCurrent:i,isCurrent:o});return{...p,...D}}return p})())},e=bs(e),[n,c,a,M,I,v,g,E,$,o,i,_,d,h]}class g1 extends De{constructor(e){super(),Pe(this,e,b1,h1,$e,{to:5,replace:6,state:7,getProps:8})}}const ol=g1;let to=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function jl(t){return t===1?"green":t===2?"yellow":t===3?"red":"gray"}function k1(t){return t>218&&t<242?"#32d900":t>212&&t<248?"#b1d900":t>208&&t<252?"#ffb800":"#d90000"}function Rc(t){return t>90?"#d90000":t>85?"#e32100":t>80?"#ffb800":t>75?"#dcd800":"#32d900"}function w1(t){return t>75?"#32d900":t>50?"#77d900":t>25?"#94d900":"#dcd800"}function ys(t){switch(t){case 1:return"Aidon";case 2:return"Kaifa";case 3:return"Kamstrup";case 8:return"Iskra";case 9:return"Landis+Gyr";case 10:return"Sagemcom";default:return"Unknown"}}function Fe(t){for(t=t.toString();t.length<2;)t="0"+t;return t}function ve(t,e){switch(e){case 5:switch(t){case"esp8266":return"Pow-K (GPIO12)";case"esp32s2":return"Pow-K+"}case 7:switch(t){case"esp8266":return"Pow-U (GPIO12)";case"esp32s2":return"Pow-U+"}case 6:return"Pow-P1";case 51:return"Wemos S2 mini";case 50:return"Generic ESP32-S2";case 201:return"Wemos LOLIN D32";case 202:return"Adafruit HUZZAH32";case 203:return"DevKitC";case 241:return"LilyGO T-ETH-POE";case 242:return"M5 PoESP32";case 243:return"WT32-ETH01";case 200:return"Generic ESP32";case 2:return"HAN Reader 2.0 by Max Spencer";case 0:return"Custom hardware by Roar Fredriksen";case 1:return"Kamstrup module by Egil Opsahl";case 8:return"µHAN mosquito by dbeinder";case 3:return"Pow-K (UART0)";case 4:return"Pow-U (UART0)";case 101:return"Wemos D1 mini";case 100:return"Generic ESP8266";case 70:return"Generic ESP32-C3";case 71:return"ESP32-C3-DevKitM-1"}}function Oa(t){switch(t){case-1:return"Parse error";case-2:return"Incomplete data received";case-3:return"Payload boundry flag missing";case-4:return"Header checksum error";case-5:return"Footer checksum error";case-9:return"Unknown data received, check meter config";case-41:return"Frame length not equal";case-51:return"Authentication failed";case-52:return"Decryption failed";case-53:return"Encryption key invalid";case 90:return"No HAN data received for at least 30s";case 91:return"Serial break";case 92:return"Serial buffer full";case 93:return"Serial FIFO overflow";case 94:return"Serial frame error";case 95:return"Serial parity error";case 96:return"RX error";case 98:return"Exception in code, debugging necessary";case 99:return"Autodetection failed"}return t<0?"Unspecified error "+t:""}function Ra(t){switch(t){case-3:return"Connection failed";case-4:return"Network timeout";case-10:return"Connection denied";case-11:return"Failed to subscribe";case-13:return"Connection lost"}return t<0?"Unspecified error "+t:""}function La(t){switch(t){case 400:return"Unrecognized data in request";case 401:case 403:return"Unauthorized, check API key";case 404:return"Price unavailable, not found";case 425:return"Server says its too early";case 429:return"Exceeded API rate limit";case 500:return"Internal server error";case-1:return"Connection error";case-2:return"Incomplete data received";case-3:return"Invalid data, tag missing";case-51:return"Authentication failed";case-52:return"Decryption failed";case-53:return"Encryption key invalid"}return t<0?"Unspecified error "+t:""}function oi(t){switch(t){case 2:case 4:case 7:return!0}return!1}function Qe(t,e){return t==1||t==2&&e}function Ut(t){return"https://github.com/UtilitechAS/amsreader-firmware/wiki/"+t}function be(t,e){return isNaN(t)?"-":(isNaN(e)&&(e=t<10?1:0),t.toFixed(e))}function dl(t,e){return t.setTime(t.getTime()+e*36e5),t}function Fa(t){if(t.chip=="esp8266")switch(t.boot_reason){case 0:return"Normal";case 1:return"WDT reset";case 2:return"Exception reset";case 3:return"Soft WDT reset";case 4:return"Software restart";case 5:return"Deep sleep";case 6:return"External reset";default:return"Unknown (8266)"}else switch(t.boot_reason){case 1:return"Vbat power on reset";case 3:return"Software reset";case 4:return"WDT reset";case 5:return"Deep sleep";case 6:return"SLC reset";case 7:return"Timer Group0 WDT reset";case 8:return"Timer Group1 WDT reset";case 9:return"RTC WDT reset";case 10:return"Instrusion test reset CPU";case 11:return"Time Group reset CPU";case 12:return"Software reset CPU";case 13:return"RTC WTD reset CPU";case 14:return"PRO CPU";case 15:return"Brownout";case 16:return"RTC reset";default:return"Unknown"}}function qa(t){return t=="EOE"?"ENTSO-E":t=="HKS"?"hvakosterstrommen.no":t=="EDS"?"Energy Data Service":t=="MIX"?"Mixed sources":"Unknown ("+t+")"}async function $l(t,e={}){const{timeout:l=8e3}=e,n=new AbortController,i=setTimeout(()=>n.abort(),l),o=await fetch(t,{...e,signal:n.signal});return clearTimeout(i),o}let pl={version:"",chip:"",mac:null,apmac:null,vndcfg:null,usrcfg:null,fwconsent:null,booting:!1,upgrading:!1,ui:{},security:0,boot_reason:0,upgrade:{x:-1,e:0,f:null,t:null},trying:null};const Yt=it(pl);async function yo(){pl=await(await $l("/sysinfo.json?t="+Math.floor(Date.now()/1e3))).json(),Yt.set(pl)}let ds=0,Ba=-127,Ua=null,y1={};const Lc=dc(y1,t=>{let e;async function l(){$l("/data.json").then(n=>n.json()).then(n=>{t(n),Ba!=n.t&&(Ba=n.t,setTimeout(jc,2e3)),Ua==null&&n.pe&&n.p!=null&&(Ua=n.p,qc()),pl.upgrading?window.location.reload():(!pl||!pl.chip||pl.booting||ds>1&&!oi(pl.board))&&(yo(),an&&clearTimeout(an),an=setTimeout(Mo,2e3),un&&clearTimeout(un),un=setTimeout(So,3e3));let i=5e3;if(oi(pl.board)&&n.v>2.5){let o=3.3-Math.min(3.3,n.v);o>0&&(i=Math.max(o,.1)*10*5e3)}i>5e3&&console.log("Scheduling next data fetch in "+i+"ms"),e&&clearTimeout(e),e=setTimeout(l,i),ds=0}).catch(n=>{ds++,ds>3?(t({em:3,hm:0,wm:0,mm:0}),e=setTimeout(l,15e3)):e=setTimeout(l,oi(pl.board)?1e4:5e3)})}return l(),function(){clearTimeout(e)}});let lo={},wi;const Co=it(lo);async function Fc(){let t=!1;Co.update(e=>{for(var l=0;l<36;l++){if(e[Fe(l)]==null){t=l<12;break}e[Fe(l)]=e[Fe(l+1)]}return e}),t?qc():wi=setTimeout(Fc,(60-new Date().getMinutes())*6e4)}async function qc(){wi&&(clearTimeout(wi),wi=0),lo=await(await $l("/energyprice.json")).json(),Co.set(lo),wi=setTimeout(Fc,(60-new Date().getMinutes())*6e4)}let no={},an;async function Mo(){an&&(clearTimeout(an),an=0),no=await(await $l("/dayplot.json")).json(),Bc.set(no),an=setTimeout(Mo,(60-new Date().getMinutes())*6e4+20)}const Bc=it(no,t=>(Mo(),function(){}));let io={},un;async function So(){un&&(clearTimeout(un),un=0),io=await(await $l("/monthplot.json")).json(),Uc.set(io),un=setTimeout(So,(24-new Date().getHours())*36e5+40)}const Uc=it(io,t=>(So(),function(){}));let so={};async function jc(){so=await(await $l("/temperature.json")).json(),Hc.set(so)}const Hc=it(so,t=>(jc(),function(){}));let oo={},vs;async function Wc(){vs&&(clearTimeout(vs),vs=0),oo=await(await $l("/tariff.json")).json(),zc.set(oo),vs=setTimeout(Wc,(60-new Date().getMinutes())*6e4+30)}const zc=it(oo,t=>function(){});let ro=[];const To=it(ro);async function C1(){ro=await(await $l("https://api.github.com/repos/UtilitechAS/amsreader-firmware/releases")).json(),To.set(ro)}let ao={};async function M1(){ao=await(await $l("/realtime.json")).json(),Gc.set(ao)}const Gc=it(ao,t=>(M1(),function(){}));function Cs(t){return"WARNING: "+t+" must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit."}async function Vc(t){await(await fetch("/upgrade?expected_version="+t,{method:"POST"})).json()}function Kc(t,e){if(/^v\d{1,2}\.\d{1,2}\.\d{1,2}$/.test(t)){let l=t.substring(1).split("."),n=parseInt(l[0]),i=parseInt(l[1]),o=parseInt(l[2]),u=[...e];u.reverse();let a,c,f;for(let p=0;po&&(a=_):g==i+1&&(c=_);else if(v==n+1)if(f){let $=f.tag_name.substring(1).split(".");parseInt($[0]);let M=parseInt($[1]);parseInt($[2]),g==M&&(f=_)}else f=_}return c||f||a||!1}else return e[0]}const S1="/github.svg";function ja(t){let e,l;function n(u,a){return u[1]>1?D1:u[1]>0?P1:u[2]>1?E1:u[2]>0?A1:u[3]>1?N1:u[3]>0?$1:T1}let i=n(t),o=i(t);return{c(){e=T(`Up + `),o.c(),l=Ve()},m(u,a){C(u,e,a),o.m(u,a),C(u,l,a)},p(u,a){i===(i=n(u))&&o?o.p(u,a):(o.d(1),o=i(u),o&&(o.c(),o.m(l.parentNode,l)))},d(u){u&&w(e),o.d(u),u&&w(l)}}}function T1(t){let e,l;return{c(){e=T(t[0]),l=T(" seconds")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&1&&X(e,n[0])},d(n){n&&w(e),n&&w(l)}}}function $1(t){let e,l;return{c(){e=T(t[3]),l=T(" minute")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&8&&X(e,n[3])},d(n){n&&w(e),n&&w(l)}}}function N1(t){let e,l;return{c(){e=T(t[3]),l=T(" minutes")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&8&&X(e,n[3])},d(n){n&&w(e),n&&w(l)}}}function A1(t){let e,l;return{c(){e=T(t[2]),l=T(" hour")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&4&&X(e,n[2])},d(n){n&&w(e),n&&w(l)}}}function E1(t){let e,l;return{c(){e=T(t[2]),l=T(" hours")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&4&&X(e,n[2])},d(n){n&&w(e),n&&w(l)}}}function P1(t){let e,l;return{c(){e=T(t[1]),l=T(" day")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&2&&X(e,n[1])},d(n){n&&w(e),n&&w(l)}}}function D1(t){let e,l;return{c(){e=T(t[1]),l=T(" days")},m(n,i){C(n,e,i),C(n,l,i)},p(n,i){i&2&&X(e,n[1])},d(n){n&&w(e),n&&w(l)}}}function I1(t){let e,l=t[0]&&ja(t);return{c(){l&&l.c(),e=Ve()},m(n,i){l&&l.m(n,i),C(n,e,i)},p(n,[i]){n[0]?l?l.p(n,i):(l=ja(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},i:_e,o:_e,d(n){l&&l.d(n),n&&w(e)}}}function O1(t,e,l){let{epoch:n}=e,i=0,o=0,u=0;return t.$$set=a=>{"epoch"in a&&l(0,n=a.epoch)},t.$$.update=()=>{t.$$.dirty&1&&(l(1,i=Math.floor(n/86400)),l(2,o=Math.floor(n/3600)),l(3,u=Math.floor(n/60)))},[n,i,o,u]}class R1 extends De{constructor(e){super(),Pe(this,e,O1,I1,$e,{epoch:0})}}function L1(t){let e,l,n;return{c(){e=m("span"),l=T(t[2]),r(e,"title",t[1]),r(e,"class",n="bd-"+t[0])},m(i,o){C(i,e,o),s(e,l)},p(i,[o]){o&4&&X(l,i[2]),o&2&&r(e,"title",i[1]),o&1&&n!==(n="bd-"+i[0])&&r(e,"class",n)},i:_e,o:_e,d(i){i&&w(e)}}}function F1(t,e,l){let{color:n}=e,{title:i}=e,{text:o}=e;return t.$$set=u=>{"color"in u&&l(0,n=u.color),"title"in u&&l(1,i=u.title),"text"in u&&l(2,o=u.text)},[n,i,o]}class fn extends De{constructor(e){super(),Pe(this,e,F1,L1,$e,{color:0,title:1,text:2})}}function q1(t){let e,l=`${Fe(t[0].getDate())}.${Fe(t[0].getMonth()+1)}.${t[0].getFullYear()} ${Fe(t[0].getHours())}:${Fe(t[0].getMinutes())}`,n;return{c(){e=m("span"),n=T(l),r(e,"class",t[1])},m(i,o){C(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l=`${Fe(i[0].getDate())}.${Fe(i[0].getMonth()+1)}.${i[0].getFullYear()} ${Fe(i[0].getHours())}:${Fe(i[0].getMinutes())}`)&&X(n,l),o&2&&r(e,"class",i[1])},d(i){i&&w(e)}}}function B1(t){let e=`${Fe(t[0].getDate())}. ${to[t[0].getMonth()]} ${Fe(t[0].getHours())}:${Fe(t[0].getMinutes())}`,l;return{c(){l=T(e)},m(n,i){C(n,l,i)},p(n,i){i&1&&e!==(e=`${Fe(n[0].getDate())}. ${to[n[0].getMonth()]} ${Fe(n[0].getHours())}:${Fe(n[0].getMinutes())}`)&&X(l,e)},d(n){n&&w(l)}}}function U1(t){let e;function l(o,u){return o[2]?B1:q1}let n=l(t),i=n(t);return{c(){i.c(),e=Ve()},m(o,u){i.m(o,u),C(o,e,u)},p(o,[u]){n===(n=l(o))&&i?i.p(o,u):(i.d(1),i=n(o),i&&(i.c(),i.m(e.parentNode,e)))},i:_e,o:_e,d(o){i.d(o),o&&w(e)}}}function j1(t,e,l){let{timestamp:n}=e,{fullTimeColor:i}=e,{offset:o}=e,u;return t.$$set=a=>{"timestamp"in a&&l(0,n=a.timestamp),"fullTimeColor"in a&&l(1,i=a.fullTimeColor),"offset"in a&&l(3,o=a.offset)},t.$$.update=()=>{t.$$.dirty&9&&(l(2,u=Math.abs(new Date().getTime()-n.getTime())<3e5),isNaN(o)||dl(n,o-(24+n.getHours()-n.getUTCHours())%24))},[n,i,u,o]}class Yc extends De{constructor(e){super(),Pe(this,e,j1,U1,$e,{timestamp:0,fullTimeColor:1,offset:3})}}function H1(t){let e,l,n;return{c(){e=Te("svg"),l=Te("path"),n=Te("path"),r(l,"stroke-linecap","round"),r(l,"stroke-linejoin","round"),r(l,"d","M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"),r(n,"stroke-linecap","round"),r(n,"stroke-linejoin","round"),r(n,"d","M15 12a3 3 0 11-6 0 3 3 0 016 0z"),r(e,"xmlns","http://www.w3.org/2000/svg"),r(e,"fill","none"),r(e,"viewBox","0 0 24 24"),r(e,"stroke-width","1.5"),r(e,"stroke","currentColor"),r(e,"class","w-6 h-6")},m(i,o){C(i,e,o),s(e,l),s(e,n)},p:_e,i:_e,o:_e,d(i){i&&w(e)}}}class W1 extends De{constructor(e){super(),Pe(this,e,null,H1,$e,{})}}function z1(t){let e,l;return{c(){e=Te("svg"),l=Te("path"),r(l,"stroke-linecap","round"),r(l,"stroke-linejoin","round"),r(l,"d","M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"),r(e,"xmlns","http://www.w3.org/2000/svg"),r(e,"fill","none"),r(e,"viewBox","0 0 24 24"),r(e,"stroke-width","1.5"),r(e,"stroke","currentColor"),r(e,"class","w-6 h-6")},m(n,i){C(n,e,i),s(e,l)},p:_e,i:_e,o:_e,d(n){n&&w(e)}}}class G1 extends De{constructor(e){super(),Pe(this,e,null,z1,$e,{})}}function V1(t){let e,l;return{c(){e=Te("svg"),l=Te("path"),r(l,"stroke-linecap","round"),r(l,"stroke-linejoin","round"),r(l,"d","M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"),r(e,"xmlns","http://www.w3.org/2000/svg"),r(e,"fill","none"),r(e,"viewBox","0 0 24 24"),r(e,"stroke-width","1.5"),r(e,"stroke","currentColor"),r(e,"class","w-6 h-6")},m(n,i){C(n,e,i),s(e,l)},p:_e,i:_e,o:_e,d(n){n&&w(e)}}}class Bt extends De{constructor(e){super(),Pe(this,e,null,V1,$e,{})}}function K1(t){let e,l;return{c(){e=Te("svg"),l=Te("path"),r(l,"stroke-linecap","round"),r(l,"stroke-linejoin","round"),r(l,"d","M9 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15M9 12l3 3m0 0l3-3m-3 3V2.25"),r(e,"xmlns","http://www.w3.org/2000/svg"),r(e,"fill","none"),r(e,"viewBox","0 0 24 24"),r(e,"stroke-width","1.5"),r(e,"stroke","currentColor"),r(e,"class","w-6 h-6")},m(n,i){C(n,e,i),s(e,l)},p:_e,i:_e,o:_e,d(n){n&&w(e)}}}class Qc extends De{constructor(e){super(),Pe(this,e,null,K1,$e,{})}}function Y1(t){let e,l,n=t[1].version+"",i;return{c(){e=T("AMS reader "),l=m("span"),i=T(n)},m(o,u){C(o,e,u),C(o,l,u),s(l,i)},p(o,u){u&2&&n!==(n=o[1].version+"")&&X(i,n)},d(o){o&&w(e),o&&w(l)}}}function Ha(t){let e,l=(t[0].t>-50?t[0].t.toFixed(1):"-")+"",n,i;return{c(){e=m("div"),n=T(l),i=T("°C"),r(e,"class","flex-none my-auto")},m(o,u){C(o,e,u),s(e,n),s(e,i)},p(o,u){u&1&&l!==(l=(o[0].t>-50?o[0].t.toFixed(1):"-")+"")&&X(n,l)},d(o){o&&w(e)}}}function Wa(t){let e,l="HAN: "+Oa(t[0].he),n;return{c(){e=m("div"),n=T(l),r(e,"class","bd-red")},m(i,o){C(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="HAN: "+Oa(i[0].he))&&X(n,l)},d(i){i&&w(e)}}}function za(t){let e,l="MQTT: "+Ra(t[0].me),n;return{c(){e=m("div"),n=T(l),r(e,"class","bd-red")},m(i,o){C(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="MQTT: "+Ra(i[0].me))&&X(n,l)},d(i){i&&w(e)}}}function Ga(t){let e,l="PriceAPI: "+La(t[0].ee),n;return{c(){e=m("div"),n=T(l),r(e,"class","bd-red")},m(i,o){C(i,e,o),s(e,n)},p(i,o){o&1&&l!==(l="PriceAPI: "+La(i[0].ee))&&X(n,l)},d(i){i&&w(e)}}}function Va(t){let e,l,n,i,o,u;return l=new ol({props:{to:"/configuration",$$slots:{default:[Q1]},$$scope:{ctx:t}}}),o=new ol({props:{to:"/status",$$slots:{default:[X1]},$$scope:{ctx:t}}}),{c(){e=m("div"),re(l.$$.fragment),n=b(),i=m("div"),re(o.$$.fragment),r(e,"class","flex-none px-1 mt-1"),r(e,"title","Configuration"),r(i,"class","flex-none px-1 mt-1"),r(i,"title","Device information")},m(a,c){C(a,e,c),se(l,e,null),C(a,n,c),C(a,i,c),se(o,i,null),u=!0},i(a){u||(O(l.$$.fragment,a),O(o.$$.fragment,a),u=!0)},o(a){B(l.$$.fragment,a),B(o.$$.fragment,a),u=!1},d(a){a&&w(e),oe(l),a&&w(n),a&&w(i),oe(o)}}}function Q1(t){let e,l;return e=new W1({}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function X1(t){let e,l;return e=new G1({}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function Ka(t){let e,l,n,i,o;const u=[J1,Z1],a=[];function c(f,p){return f[1].security==0||f[0].a?0:1}return l=c(t),n=a[l]=u[l](t),{c(){e=m("div"),n.c(),r(e,"class","flex-none mr-3 text-yellow-500"),r(e,"title",i="New version: "+t[2].tag_name)},m(f,p){C(f,e,p),a[l].m(e,null),o=!0},p(f,p){let _=l;l=c(f),l===_?a[l].p(f,p):(Ie(),B(a[_],1,1,()=>{a[_]=null}),Oe(),n=a[l],n?n.p(f,p):(n=a[l]=u[l](f),n.c()),O(n,1),n.m(e,null)),(!o||p&4&&i!==(i="New version: "+f[2].tag_name))&&r(e,"title",i)},i(f){o||(O(n),o=!0)},o(f){B(n),o=!1},d(f){f&&w(e),a[l].d()}}}function Z1(t){let e,l,n=t[2].tag_name+"",i;return{c(){e=m("span"),l=T("New version: "),i=T(n)},m(o,u){C(o,e,u),s(e,l),s(e,i)},p(o,u){u&4&&n!==(n=o[2].tag_name+"")&&X(i,n)},i:_e,o:_e,d(o){o&&w(e)}}}function J1(t){let e,l,n,i=t[2].tag_name+"",o,u,a,c,f,p;return a=new Qc({}),{c(){e=m("button"),l=m("span"),n=T("New version: "),o=T(i),u=b(),re(a.$$.fragment),r(l,"class","mt-1"),r(e,"class","flex")},m(_,h){C(_,e,h),s(e,l),s(l,n),s(l,o),s(e,u),se(a,e,null),c=!0,f||(p=le(e,"click",t[3]),f=!0)},p(_,h){(!c||h&4)&&i!==(i=_[2].tag_name+"")&&X(o,i)},i(_){c||(O(a.$$.fragment,_),c=!0)},o(_){B(a.$$.fragment,_),c=!1},d(_){_&&w(e),oe(a),f=!1,p()}}}function x1(t){let e,l,n,i,o,u,a,c,f,p,_,h,d=(t[0].m?(t[0].m/1e3).toFixed(1):"-")+"",v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue,x,W,U,ke,He,Be,We;i=new ol({props:{to:"/",$$slots:{default:[Y1]},$$scope:{ctx:t}}}),c=new R1({props:{epoch:t[0].u}});let Ne=t[0].t>-50&&Ha(t);M=new fn({props:{title:"ESP",text:t[1].booting?"Booting":t[0].v>2?t[0].v.toFixed(2)+"V":"ESP",color:jl(t[1].booting?2:t[0].em)}}),F=new fn({props:{title:"HAN",text:"HAN",color:jl(t[1].booting?9:t[0].hm)}}),I=new fn({props:{title:"WiFi",text:t[0].r?t[0].r.toFixed(0)+"dBm":"WiFi",color:jl(t[1].booting?9:t[0].wm)}}),L=new fn({props:{title:"MQTT",text:"MQTT",color:jl(t[1].booting?9:t[0].mm)}});let ge=(t[0].he<0||t[0].he>0)&&Wa(t),Re=t[0].me<0&&za(t),Me=(t[0].ee>0||t[0].ee<0)&&Ga(t);ue=new Yc({props:{timestamp:t[0].c?new Date(t[0].c*1e3):new Date(0),offset:t[1].clock_offset,fullTimeColor:"text-red-500"}});let S=t[1].vndcfg&&t[1].usrcfg&&Va(t);He=new Bt({});let k=t[1].fwconsent===1&&t[2]&&Ka(t);return{c(){e=m("nav"),l=m("div"),n=m("div"),re(i.$$.fragment),o=b(),u=m("div"),a=m("div"),re(c.$$.fragment),f=b(),Ne&&Ne.c(),p=b(),_=m("div"),h=T("Free mem: "),v=T(d),g=T("kb"),E=b(),$=m("div"),re(M.$$.fragment),P=b(),re(F.$$.fragment),A=b(),re(I.$$.fragment),D=b(),re(L.$$.fragment),ie=b(),ge&&ge.c(),H=b(),Re&&Re.c(),K=b(),Me&&Me.c(),G=b(),Y=m("div"),Q=m("div"),z=m("a"),Z=m("img"),j=b(),ee=m("div"),re(ue.$$.fragment),x=b(),S&&S.c(),W=b(),U=m("div"),ke=m("a"),re(He.$$.fragment),Be=b(),k&&k.c(),r(n,"class","flex text-lg text-gray-100 p-2"),r(a,"class","flex-none my-auto"),r(_,"class","flex-none my-auto"),r(u,"class","flex-none my-auto p-2 flex space-x-4"),r($,"class","flex-auto flex-wrap my-auto justify-center p-2"),r(Z,"class","gh-logo"),Xs(Z.src,V=S1)||r(Z,"src",V),r(Z,"alt","GitHub repo"),r(z,"class","float-right"),r(z,"href","https://github.com/UtilitechAS/amsreader-firmware"),r(z,"target","_blank"),r(z,"rel","noreferrer"),r(z,"aria-label","GitHub"),r(Q,"class","flex-none"),r(ee,"class","flex-none my-auto px-2"),r(ke,"href",Ut("")),r(ke,"target","_blank"),r(ke,"rel","noreferrer"),r(U,"class","flex-none px-1 mt-1"),r(U,"title","Documentation"),r(Y,"class","flex-auto p-2 flex flex-row-reverse flex-wrap"),r(l,"class","flex flex-wrap space-x-4 text-sm text-gray-300"),r(e,"class","bg-violet-600 p-1 rounded-md mx-2")},m(y,N){C(y,e,N),s(e,l),s(l,n),se(i,n,null),s(l,o),s(l,u),s(u,a),se(c,a,null),s(u,f),Ne&&Ne.m(u,null),s(u,p),s(u,_),s(_,h),s(_,v),s(_,g),s(l,E),s(l,$),se(M,$,null),s($,P),se(F,$,null),s($,A),se(I,$,null),s($,D),se(L,$,null),s(l,ie),ge&&ge.m(l,null),s(l,H),Re&&Re.m(l,null),s(l,K),Me&&Me.m(l,null),s(l,G),s(l,Y),s(Y,Q),s(Q,z),s(z,Z),s(Y,j),s(Y,ee),se(ue,ee,null),s(Y,x),S&&S.m(Y,null),s(Y,W),s(Y,U),s(U,ke),se(He,ke,null),s(Y,Be),k&&k.m(Y,null),We=!0},p(y,[N]){const R={};N&18&&(R.$$scope={dirty:N,ctx:y}),i.$set(R);const J={};N&1&&(J.epoch=y[0].u),c.$set(J),y[0].t>-50?Ne?Ne.p(y,N):(Ne=Ha(y),Ne.c(),Ne.m(u,p)):Ne&&(Ne.d(1),Ne=null),(!We||N&1)&&d!==(d=(y[0].m?(y[0].m/1e3).toFixed(1):"-")+"")&&X(v,d);const te={};N&3&&(te.text=y[1].booting?"Booting":y[0].v>2?y[0].v.toFixed(2)+"V":"ESP"),N&3&&(te.color=jl(y[1].booting?2:y[0].em)),M.$set(te);const fe={};N&3&&(fe.color=jl(y[1].booting?9:y[0].hm)),F.$set(fe);const de={};N&1&&(de.text=y[0].r?y[0].r.toFixed(0)+"dBm":"WiFi"),N&3&&(de.color=jl(y[1].booting?9:y[0].wm)),I.$set(de);const we={};N&3&&(we.color=jl(y[1].booting?9:y[0].mm)),L.$set(we),y[0].he<0||y[0].he>0?ge?ge.p(y,N):(ge=Wa(y),ge.c(),ge.m(l,H)):ge&&(ge.d(1),ge=null),y[0].me<0?Re?Re.p(y,N):(Re=za(y),Re.c(),Re.m(l,K)):Re&&(Re.d(1),Re=null),y[0].ee>0||y[0].ee<0?Me?Me.p(y,N):(Me=Ga(y),Me.c(),Me.m(l,G)):Me&&(Me.d(1),Me=null);const Ae={};N&1&&(Ae.timestamp=y[0].c?new Date(y[0].c*1e3):new Date(0)),N&2&&(Ae.offset=y[1].clock_offset),ue.$set(Ae),y[1].vndcfg&&y[1].usrcfg?S?N&2&&O(S,1):(S=Va(y),S.c(),O(S,1),S.m(Y,W)):S&&(Ie(),B(S,1,1,()=>{S=null}),Oe()),y[1].fwconsent===1&&y[2]?k?(k.p(y,N),N&6&&O(k,1)):(k=Ka(y),k.c(),O(k,1),k.m(Y,null)):k&&(Ie(),B(k,1,1,()=>{k=null}),Oe())},i(y){We||(O(i.$$.fragment,y),O(c.$$.fragment,y),O(M.$$.fragment,y),O(F.$$.fragment,y),O(I.$$.fragment,y),O(L.$$.fragment,y),O(ue.$$.fragment,y),O(S),O(He.$$.fragment,y),O(k),We=!0)},o(y){B(i.$$.fragment,y),B(c.$$.fragment,y),B(M.$$.fragment,y),B(F.$$.fragment,y),B(I.$$.fragment,y),B(L.$$.fragment,y),B(ue.$$.fragment,y),B(S),B(He.$$.fragment,y),B(k),We=!1},d(y){y&&w(e),oe(i),oe(c),Ne&&Ne.d(),oe(M),oe(F),oe(I),oe(L),ge&&ge.d(),Re&&Re.d(),Me&&Me.d(),oe(ue),S&&S.d(),oe(He),k&&k.d()}}}function em(t,e,l){let{data:n={}}=e,i={},o={};function u(){confirm("Do you want to upgrade this device to "+o.tag_name+"?")&&(!oi(i.board)||confirm(Cs(ve(i.chip,i.board))))&&(Yt.update(a=>(a.upgrading=!0,a)),Vc(o.tag_name))}return Yt.subscribe(a=>{l(1,i=a),a.fwconsent===1&&C1()}),To.subscribe(a=>{l(2,o=Kc(i.version,a))}),t.$$set=a=>{"data"in a&&l(0,n=a.data)},[n,i,o,u]}class tm extends De{constructor(e){super(),Pe(this,e,em,x1,$e,{data:0})}}function lm(t){let e,l,n,i;return{c(){e=Te("svg"),l=Te("path"),n=Te("path"),r(l,"d",Qs(150,150,115,210,510)),r(l,"stroke","rgba(128, 128, 128, 0.15)"),r(l,"fill","none"),r(l,"stroke-width","55"),r(n,"d",i=Qs(150,150,115,210,210+300*t[0]/100)),r(n,"stroke",t[1]),r(n,"fill","none"),r(n,"stroke-width","55"),r(e,"viewBox","0 0 300 300"),r(e,"xmlns","http://www.w3.org/2000/svg"),r(e,"height","100%")},m(o,u){C(o,e,u),s(e,l),s(e,n)},p(o,[u]){u&1&&i!==(i=Qs(150,150,115,210,210+300*o[0]/100))&&r(n,"d",i),u&2&&r(n,"stroke",o[1])},i:_e,o:_e,d(o){o&&w(e)}}}function Ya(t,e,l,n){var i=(n-90)*Math.PI/180;return{x:t+l*Math.cos(i),y:e+l*Math.sin(i)}}function Qs(t,e,l,n,i){var o=Ya(t,e,l,i),u=Ya(t,e,l,n),a=i-n<=180?"0":"1",c=["M",o.x,o.y,"A",l,l,0,a,0,u.x,u.y].join(" ");return c}function nm(t,e,l){let{pct:n=0}=e,{color:i="red"}=e;return t.$$set=o=>{"pct"in o&&l(0,n=o.pct),"color"in o&&l(1,i=o.color)},[n,i]}class im extends De{constructor(e){super(),Pe(this,e,nm,lm,$e,{pct:0,color:1})}}function Qa(t){let e,l,n,i,o,u,a,c;return{c(){e=m("br"),l=b(),n=m("span"),i=T(t[3]),o=b(),u=m("span"),a=T(t[4]),c=T("/kWh"),r(n,"class","pl-sub"),r(u,"class","pl-snt")},m(f,p){C(f,e,p),C(f,l,p),C(f,n,p),s(n,i),C(f,o,p),C(f,u,p),s(u,a),s(u,c)},p(f,p){p&8&&X(i,f[3]),p&16&&X(a,f[4])},d(f){f&&w(e),f&&w(l),f&&w(n),f&&w(o),f&&w(u)}}}function sm(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E;l=new im({props:{pct:t[6],color:t[5](t[6])}});let $=t[3]&&Qa(t);return{c(){e=m("div"),re(l.$$.fragment),n=b(),i=m("span"),o=m("span"),u=T(t[2]),a=b(),c=m("br"),f=b(),p=m("span"),_=T(t[0]),h=b(),d=m("span"),v=T(t[1]),g=b(),$&&$.c(),r(o,"class","pl-lab"),r(p,"class","pl-val"),r(d,"class","pl-unt"),r(i,"class","pl-ov"),r(e,"class","pl-root")},m(M,P){C(M,e,P),se(l,e,null),s(e,n),s(e,i),s(i,o),s(o,u),s(i,a),s(i,c),s(i,f),s(i,p),s(p,_),s(i,h),s(i,d),s(d,v),s(i,g),$&&$.m(i,null),E=!0},p(M,[P]){const F={};P&64&&(F.pct=M[6]),P&96&&(F.color=M[5](M[6])),l.$set(F),(!E||P&4)&&X(u,M[2]),(!E||P&1)&&X(_,M[0]),(!E||P&2)&&X(v,M[1]),M[3]?$?$.p(M,P):($=Qa(M),$.c(),$.m(i,null)):$&&($.d(1),$=null)},i(M){E||(O(l.$$.fragment,M),E=!0)},o(M){B(l.$$.fragment,M),E=!1},d(M){M&&w(e),oe(l),$&&$.d()}}}function om(t,e,l){let{val:n}=e,{max:i}=e,{unit:o}=e,{label:u}=e,{sub:a=""}=e,{subunit:c=""}=e,{colorFn:f}=e,p=0;return t.$$set=_=>{"val"in _&&l(0,n=_.val),"max"in _&&l(7,i=_.max),"unit"in _&&l(1,o=_.unit),"label"in _&&l(2,u=_.label),"sub"in _&&l(3,a=_.sub),"subunit"in _&&l(4,c=_.subunit),"colorFn"in _&&l(5,f=_.colorFn)},t.$$.update=()=>{t.$$.dirty&129&&l(6,p=Math.min(n,i)/i*100)},[n,o,u,a,c,f,p,i]}class Xc extends De{constructor(e){super(),Pe(this,e,om,sm,$e,{val:0,max:7,unit:1,label:2,sub:3,subunit:4,colorFn:5})}}function Xa(t,e,l){const n=t.slice();return n[9]=e[l],n[11]=l,n}function Za(t,e,l){const n=t.slice();return n[9]=e[l],n[11]=l,n}function Ja(t,e,l){const n=t.slice();return n[13]=e[l],n}function xa(t){let e,l,n,i,o,u=t[0].title&&eu(t),a=t[0].y.ticks,c=[];for(let d=0;d20||t[11]%2==0)&&iu(t);return{c(){e=Te("g"),n&&n.c(),r(e,"class","tick"),r(e,"transform",l="translate("+t[5](t[11])+","+t[4]+")")},m(i,o){C(i,e,o),n&&n.m(e,null)},p(i,o){i[3]>20||i[11]%2==0?n?n.p(i,o):(n=iu(i),n.c(),n.m(e,null)):n&&(n.d(1),n=null),o&48&&l!==(l="translate("+i[5](i[11])+","+i[4]+")")&&r(e,"transform",l)},d(i){i&&w(e),n&&n.d()}}}function iu(t){let e,l=t[9].label+"",n,i;return{c(){e=Te("text"),n=T(l),r(e,"x",i=t[3]/2),r(e,"y","-4")},m(o,u){C(o,e,u),s(e,n)},p(o,u){u&1&&l!==(l=o[9].label+"")&&X(n,l),u&8&&i!==(i=o[3]/2)&&r(e,"x",i)},d(o){o&&w(e)}}}function su(t){let e=!isNaN(t[5](t[11])),l,n=e&&nu(t);return{c(){n&&n.c(),l=Ve()},m(i,o){n&&n.m(i,o),C(i,l,o)},p(i,o){o&32&&(e=!isNaN(i[5](i[11]))),e?n?n.p(i,o):(n=nu(i),n.c(),n.m(l.parentNode,l)):n&&(n.d(1),n=null)},d(i){n&&n.d(i),i&&w(l)}}}function ou(t){let e,l,n=t[9].value!==void 0&&ru(t),i=t[9].value2>1e-4&&fu(t);return{c(){e=Te("g"),n&&n.c(),l=Te("g"),i&&i.c()},m(o,u){C(o,e,u),n&&n.m(e,null),C(o,l,u),i&&i.m(l,null)},p(o,u){o[9].value!==void 0?n?n.p(o,u):(n=ru(o),n.c(),n.m(e,null)):n&&(n.d(1),n=null),o[9].value2>1e-4?i?i.p(o,u):(i=fu(o),i.c(),i.m(l,null)):i&&(i.d(1),i=null)},d(o){o&&w(e),n&&n.d(),o&&w(l),i&&i.d()}}}function ru(t){let e,l,n,i,o,u,a,c=t[3]>15&&au(t);return{c(){e=Te("rect"),c&&c.c(),a=Ve(),r(e,"x",l=t[5](t[11])+2),r(e,"y",n=t[6](t[9].value)),r(e,"width",i=t[3]-4),r(e,"height",o=t[6](t[0].y.min)-t[6](Math.min(t[0].y.min,0)+t[9].value)),r(e,"fill",u=t[9].color)},m(f,p){C(f,e,p),c&&c.m(f,p),C(f,a,p)},p(f,p){p&32&&l!==(l=f[5](f[11])+2)&&r(e,"x",l),p&65&&n!==(n=f[6](f[9].value))&&r(e,"y",n),p&8&&i!==(i=f[3]-4)&&r(e,"width",i),p&65&&o!==(o=f[6](f[0].y.min)-f[6](Math.min(f[0].y.min,0)+f[9].value))&&r(e,"height",o),p&1&&u!==(u=f[9].color)&&r(e,"fill",u),f[3]>15?c?c.p(f,p):(c=au(f),c.c(),c.m(a.parentNode,a)):c&&(c.d(1),c=null)},d(f){f&&w(e),c&&c.d(f),f&&w(a)}}}function au(t){let e,l=t[9].label+"",n,i,o,u,a,c,f=t[9].title&&uu(t);return{c(){e=Te("text"),n=T(l),f&&f.c(),c=Ve(),r(e,"width",i=t[3]-4),r(e,"dominant-baseline","middle"),r(e,"text-anchor",o=t[3]t[6](0)-t[7]?t[9].color:"white"),r(e,"transform",a="translate("+(t[5](t[11])+t[3]/2)+" "+(t[6](t[9].value)>t[6](0)-t[7]?t[6](t[9].value)-t[7]:t[6](t[9].value)+10)+") rotate("+(t[3]p[6](0)-p[7]?p[9].color:"white")&&r(e,"fill",u),_&233&&a!==(a="translate("+(p[5](p[11])+p[3]/2)+" "+(p[6](p[9].value)>p[6](0)-p[7]?p[6](p[9].value)-p[7]:p[6](p[9].value)+10)+") rotate("+(p[3]15&&cu(t);return{c(){e=Te("rect"),c&&c.c(),a=Ve(),r(e,"x",l=t[5](t[11])+2),r(e,"y",n=t[6](0)),r(e,"width",i=t[3]-4),r(e,"height",o=t[6](t[0].y.min)-t[6](t[0].y.min+t[9].value2)),r(e,"fill",u=t[9].color2?t[9].color2:t[9].color)},m(f,p){C(f,e,p),c&&c.m(f,p),C(f,a,p)},p(f,p){p&32&&l!==(l=f[5](f[11])+2)&&r(e,"x",l),p&64&&n!==(n=f[6](0))&&r(e,"y",n),p&8&&i!==(i=f[3]-4)&&r(e,"width",i),p&65&&o!==(o=f[6](f[0].y.min)-f[6](f[0].y.min+f[9].value2))&&r(e,"height",o),p&1&&u!==(u=f[9].color2?f[9].color2:f[9].color)&&r(e,"fill",u),f[3]>15?c?c.p(f,p):(c=cu(f),c.c(),c.m(a.parentNode,a)):c&&(c.d(1),c=null)},d(f){f&&w(e),c&&c.d(f),f&&w(a)}}}function cu(t){let e,l=t[9].label2+"",n,i,o,u,a,c=t[9].title2&&mu(t);return{c(){e=Te("text"),n=T(l),c&&c.c(),a=Ve(),r(e,"width",i=t[3]-4),r(e,"dominant-baseline","middle"),r(e,"text-anchor","middle"),r(e,"fill",o=t[6](-t[9].value2)t[8].call(e))},m(i,o){C(i,e,o),n&&n.m(e,null),l=ic(e,t[8].bind(e))},p(i,[o]){i[0].x.ticks&&i[0].points&&i[4]?n?n.p(i,o):(n=xa(i),n.c(),n.m(e,null)):n&&(n.d(1),n=null)},i:_e,o:_e,d(i){i&&w(e),n&&n.d(),l()}}}let cn=30;function am(t,e,l){let{config:n}=e,i,o,u,a,c,f,p;function _(){i=this.clientWidth,o=this.clientHeight,l(1,i),l(2,o)}return t.$$set=h=>{"config"in h&&l(0,n=h.config)},t.$$.update=()=>{if(t.$$.dirty&31){l(4,f=o-(n.title?20:0));let h=i-(n.padding.left+n.padding.right);l(3,u=h/n.points.length),l(7,p=un.y.max?g=n.padding.bottom:vf||g<0?0:g})}},[n,i,o,u,f,a,c,p,_]}class pn extends De{constructor(e){super(),Pe(this,e,am,rm,$e,{config:0})}}function um(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function fm(t,e,l){let{u1:n}=e,{u2:i}=e,{u3:o}=e,{ds:u}=e,a={};function c(f){return{label:be(f)+"V",title:f.toFixed(1)+" V",value:isNaN(f)?0:f,color:k1(f||0)}}return t.$$set=f=>{"u1"in f&&l(1,n=f.u1),"u2"in f&&l(2,i=f.u2),"u3"in f&&l(3,o=f.u3),"ds"in f&&l(4,u=f.ds)},t.$$.update=()=>{if(t.$$.dirty&30){let f=[],p=[];n>0&&(f.push({label:u===1?"L1-L2":"L1"}),p.push(c(n))),i>0&&(f.push({label:u===1?"L1-L3":"L2"}),p.push(c(i))),o>0&&(f.push({label:u===1?"L2-L3":"L3"}),p.push(c(o))),l(0,a={padding:{top:20,right:15,bottom:20,left:35},y:{min:200,max:260,ticks:[{value:207,label:"-10%"},{value:230,label:"230v"},{value:253,label:"+10%"}]},x:{ticks:f},points:p})}},[a,n,i,o,u]}class cm extends De{constructor(e){super(),Pe(this,e,fm,um,$e,{u1:1,u2:2,u3:3,ds:4})}}function mm(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function pm(t,e,l){let{u1:n}=e,{u2:i}=e,{u3:o}=e,{i1:u}=e,{i2:a}=e,{i3:c}=e,{max:f}=e,p={};function _(h){return{label:be(h)+"A",title:h.toFixed(1)+" A",value:isNaN(h)?0:h,color:Rc(h?h/f*100:0)}}return t.$$set=h=>{"u1"in h&&l(1,n=h.u1),"u2"in h&&l(2,i=h.u2),"u3"in h&&l(3,o=h.u3),"i1"in h&&l(4,u=h.i1),"i2"in h&&l(5,a=h.i2),"i3"in h&&l(6,c=h.i3),"max"in h&&l(7,f=h.max)},t.$$.update=()=>{if(t.$$.dirty&254){let h=[],d=[];n>0&&(h.push({label:"L1"}),d.push(_(u))),i>0&&(h.push({label:"L2"}),d.push(_(a))),o>0&&(h.push({label:"L3"}),d.push(_(c))),l(0,p={padding:{top:20,right:15,bottom:20,left:35},y:{min:0,max:f,ticks:[{value:0,label:"0%"},{value:f/4,label:"25%"},{value:f/2,label:"50%"},{value:f/4*3,label:"75%"},{value:f,label:"100%"}]},x:{ticks:h},points:d})}},[p,n,i,o,u,a,c,f]}class _m extends De{constructor(e){super(),Pe(this,e,pm,mm,$e,{u1:1,u2:2,u3:3,i1:4,i2:5,i3:6,max:7})}}function dm(t){let e,l,n,i,o,u,a,c=(typeof t[0]<"u"?t[0].toFixed(0):"-")+"",f,p,_,h,d,v,g=(typeof t[1]<"u"?t[1].toFixed(0):"-")+"",E,$,M,P,F,A,I,D=(typeof t[2]<"u"?t[2].toFixed(1):"-")+"",L,ie,H,K,G,Y,Q=(typeof t[3]<"u"?t[3].toFixed(1):"-")+"",z,Z;return{c(){e=m("div"),l=m("strong"),l.textContent="Reactive",n=b(),i=m("div"),o=m("div"),o.textContent="Instant in",u=b(),a=m("div"),f=T(c),p=T(" VAr"),_=b(),h=m("div"),h.textContent="Instant out",d=b(),v=m("div"),E=T(g),$=T(" VAr"),M=b(),P=m("div"),F=m("div"),F.textContent="Total in",A=b(),I=m("div"),L=T(D),ie=T(" kVArh"),H=b(),K=m("div"),K.textContent="Total out",G=b(),Y=m("div"),z=T(Q),Z=T(" kVArh"),r(a,"class","text-right"),r(v,"class","text-right"),r(i,"class","grid grid-cols-2 mt-4"),r(I,"class","text-right"),r(Y,"class","text-right"),r(P,"class","grid grid-cols-2 mt-4"),r(e,"class","mx-2 text-sm")},m(V,j){C(V,e,j),s(e,l),s(e,n),s(e,i),s(i,o),s(i,u),s(i,a),s(a,f),s(a,p),s(i,_),s(i,h),s(i,d),s(i,v),s(v,E),s(v,$),s(e,M),s(e,P),s(P,F),s(P,A),s(P,I),s(I,L),s(I,ie),s(P,H),s(P,K),s(P,G),s(P,Y),s(Y,z),s(Y,Z)},p(V,[j]){j&1&&c!==(c=(typeof V[0]<"u"?V[0].toFixed(0):"-")+"")&&X(f,c),j&2&&g!==(g=(typeof V[1]<"u"?V[1].toFixed(0):"-")+"")&&X(E,g),j&4&&D!==(D=(typeof V[2]<"u"?V[2].toFixed(1):"-")+"")&&X(L,D),j&8&&Q!==(Q=(typeof V[3]<"u"?V[3].toFixed(1):"-")+"")&&X(z,Q)},i:_e,o:_e,d(V){V&&w(e)}}}function vm(t,e,l){let{importInstant:n}=e,{exportInstant:i}=e,{importTotal:o}=e,{exportTotal:u}=e;return t.$$set=a=>{"importInstant"in a&&l(0,n=a.importInstant),"exportInstant"in a&&l(1,i=a.exportInstant),"importTotal"in a&&l(2,o=a.importTotal),"exportTotal"in a&&l(3,u=a.exportTotal)},[n,i,o,u]}class hm extends De{constructor(e){super(),Pe(this,e,vm,dm,$e,{importInstant:0,exportInstant:1,importTotal:2,exportTotal:3})}}function _u(t){let e;function l(o,u){return o[3]?gm:bm}let n=l(t),i=n(t);return{c(){i.c(),e=Ve()},m(o,u){i.m(o,u),C(o,e,u)},p(o,u){n===(n=l(o))&&i?i.p(o,u):(i.d(1),i=n(o),i&&(i.c(),i.m(e.parentNode,e)))},d(o){i.d(o),o&&w(e)}}}function bm(t){let e,l,n,i,o,u,a=be(t[1].h.u,2)+"",c,f,p,_,h,d,v=be(t[1].d.u,1)+"",g,E,$,M,P,F,A=be(t[1].m.u)+"",I,D,L,ie,H,K,G=be(t[0].last_month.u)+"",Y,Q,z,Z,V=t[4]&&du(t);return{c(){e=m("strong"),e.textContent="Consumption",l=b(),n=m("div"),i=m("div"),i.textContent="Hour",o=b(),u=m("div"),c=T(a),f=T(" kWh"),p=b(),_=m("div"),_.textContent="Day",h=b(),d=m("div"),g=T(v),E=T(" kWh"),$=b(),M=m("div"),M.textContent="Month",P=b(),F=m("div"),I=T(A),D=T(" kWh"),L=b(),ie=m("div"),ie.textContent="Last month",H=b(),K=m("div"),Y=T(G),Q=T(" kWh"),z=b(),V&&V.c(),Z=Ve(),r(u,"class","text-right"),r(d,"class","text-right"),r(F,"class","text-right"),r(K,"class","text-right"),r(n,"class","grid grid-cols-2 mb-3")},m(j,ee){C(j,e,ee),C(j,l,ee),C(j,n,ee),s(n,i),s(n,o),s(n,u),s(u,c),s(u,f),s(n,p),s(n,_),s(n,h),s(n,d),s(d,g),s(d,E),s(n,$),s(n,M),s(n,P),s(n,F),s(F,I),s(F,D),s(n,L),s(n,ie),s(n,H),s(n,K),s(K,Y),s(K,Q),C(j,z,ee),V&&V.m(j,ee),C(j,Z,ee)},p(j,ee){ee&2&&a!==(a=be(j[1].h.u,2)+"")&&X(c,a),ee&2&&v!==(v=be(j[1].d.u,1)+"")&&X(g,v),ee&2&&A!==(A=be(j[1].m.u)+"")&&X(I,A),ee&1&&G!==(G=be(j[0].last_month.u)+"")&&X(Y,G),j[4]?V?V.p(j,ee):(V=du(j),V.c(),V.m(Z.parentNode,Z)):V&&(V.d(1),V=null)},d(j){j&&w(e),j&&w(l),j&&w(n),j&&w(z),V&&V.d(j),j&&w(Z)}}}function gm(t){let e,l,n,i,o,u,a=be(t[1].h.u,2)+"",c,f,p,_,h,d,v,g=be(t[1].d.u,1)+"",E,$,M,P,F,A,I,D=be(t[1].m.u)+"",L,ie,H,K,G,Y,Q,z=be(t[0].last_month.u)+"",Z,V,j,ee,ue,x,W,U,ke,He,Be,We=be(t[1].h.p,2)+"",Ne,ge,Re,Me,S,k,y,N=be(t[1].d.p,1)+"",R,J,te,fe,de,we,Ae,ae=be(t[1].m.p)+"",Ce,Je,At,st,ht,lt,Et,Ye=be(t[0].last_month.p)+"",Qt,Ht,bt,ze,xe=t[4]&&vu(t),Xe=t[4]&&hu(t),Ue=t[4]&&bu(t),qe=t[4]&&gu(t),et=t[4]&&ku(t),Ee=t[4]&&wu(t),Le=t[4]&&yu(t),pe=t[4]&&Cu(t);return{c(){e=m("strong"),e.textContent="Import",l=b(),n=m("div"),i=m("div"),i.textContent="Hour",o=b(),u=m("div"),c=T(a),f=T(" kWh"),p=b(),xe&&xe.c(),_=b(),h=m("div"),h.textContent="Day",d=b(),v=m("div"),E=T(g),$=T(" kWh"),M=b(),Xe&&Xe.c(),P=b(),F=m("div"),F.textContent="Month",A=b(),I=m("div"),L=T(D),ie=T(" kWh"),H=b(),Ue&&Ue.c(),K=b(),G=m("div"),G.textContent="Last mo.",Y=b(),Q=m("div"),Z=T(z),V=T(" kWh"),j=b(),qe&&qe.c(),ue=b(),x=m("strong"),x.textContent="Export",W=b(),U=m("div"),ke=m("div"),ke.textContent="Hour",He=b(),Be=m("div"),Ne=T(We),ge=T(" kWh"),Re=b(),et&&et.c(),Me=b(),S=m("div"),S.textContent="Day",k=b(),y=m("div"),R=T(N),J=T(" kWh"),te=b(),Ee&&Ee.c(),fe=b(),de=m("div"),de.textContent="Month",we=b(),Ae=m("div"),Ce=T(ae),Je=T(" kWh"),At=b(),Le&&Le.c(),st=b(),ht=m("div"),ht.textContent="Last mo.",lt=b(),Et=m("div"),Qt=T(Ye),Ht=T(" kWh"),bt=b(),pe&&pe.c(),r(u,"class","text-right"),r(v,"class","text-right"),r(I,"class","text-right"),r(Q,"class","text-right"),r(n,"class",ee="grid grid-cols-"+t[5]+" mb-3"),r(Be,"class","text-right"),r(y,"class","text-right"),r(Ae,"class","text-right"),r(Et,"class","text-right"),r(U,"class",ze="grid grid-cols-"+t[5])},m(ce,ye){C(ce,e,ye),C(ce,l,ye),C(ce,n,ye),s(n,i),s(n,o),s(n,u),s(u,c),s(u,f),s(n,p),xe&&xe.m(n,null),s(n,_),s(n,h),s(n,d),s(n,v),s(v,E),s(v,$),s(n,M),Xe&&Xe.m(n,null),s(n,P),s(n,F),s(n,A),s(n,I),s(I,L),s(I,ie),s(n,H),Ue&&Ue.m(n,null),s(n,K),s(n,G),s(n,Y),s(n,Q),s(Q,Z),s(Q,V),s(n,j),qe&&qe.m(n,null),C(ce,ue,ye),C(ce,x,ye),C(ce,W,ye),C(ce,U,ye),s(U,ke),s(U,He),s(U,Be),s(Be,Ne),s(Be,ge),s(U,Re),et&&et.m(U,null),s(U,Me),s(U,S),s(U,k),s(U,y),s(y,R),s(y,J),s(U,te),Ee&&Ee.m(U,null),s(U,fe),s(U,de),s(U,we),s(U,Ae),s(Ae,Ce),s(Ae,Je),s(U,At),Le&&Le.m(U,null),s(U,st),s(U,ht),s(U,lt),s(U,Et),s(Et,Qt),s(Et,Ht),s(U,bt),pe&&pe.m(U,null)},p(ce,ye){ye&2&&a!==(a=be(ce[1].h.u,2)+"")&&X(c,a),ce[4]?xe?xe.p(ce,ye):(xe=vu(ce),xe.c(),xe.m(n,_)):xe&&(xe.d(1),xe=null),ye&2&&g!==(g=be(ce[1].d.u,1)+"")&&X(E,g),ce[4]?Xe?Xe.p(ce,ye):(Xe=hu(ce),Xe.c(),Xe.m(n,P)):Xe&&(Xe.d(1),Xe=null),ye&2&&D!==(D=be(ce[1].m.u)+"")&&X(L,D),ce[4]?Ue?Ue.p(ce,ye):(Ue=bu(ce),Ue.c(),Ue.m(n,K)):Ue&&(Ue.d(1),Ue=null),ye&1&&z!==(z=be(ce[0].last_month.u)+"")&&X(Z,z),ce[4]?qe?qe.p(ce,ye):(qe=gu(ce),qe.c(),qe.m(n,null)):qe&&(qe.d(1),qe=null),ye&32&&ee!==(ee="grid grid-cols-"+ce[5]+" mb-3")&&r(n,"class",ee),ye&2&&We!==(We=be(ce[1].h.p,2)+"")&&X(Ne,We),ce[4]?et?et.p(ce,ye):(et=ku(ce),et.c(),et.m(U,Me)):et&&(et.d(1),et=null),ye&2&&N!==(N=be(ce[1].d.p,1)+"")&&X(R,N),ce[4]?Ee?Ee.p(ce,ye):(Ee=wu(ce),Ee.c(),Ee.m(U,fe)):Ee&&(Ee.d(1),Ee=null),ye&2&&ae!==(ae=be(ce[1].m.p)+"")&&X(Ce,ae),ce[4]?Le?Le.p(ce,ye):(Le=yu(ce),Le.c(),Le.m(U,st)):Le&&(Le.d(1),Le=null),ye&1&&Ye!==(Ye=be(ce[0].last_month.p)+"")&&X(Qt,Ye),ce[4]?pe?pe.p(ce,ye):(pe=Cu(ce),pe.c(),pe.m(U,null)):pe&&(pe.d(1),pe=null),ye&32&&ze!==(ze="grid grid-cols-"+ce[5])&&r(U,"class",ze)},d(ce){ce&&w(e),ce&&w(l),ce&&w(n),xe&&xe.d(),Xe&&Xe.d(),Ue&&Ue.d(),qe&&qe.d(),ce&&w(ue),ce&&w(x),ce&&w(W),ce&&w(U),et&&et.d(),Ee&&Ee.d(),Le&&Le.d(),pe&&pe.d()}}}function du(t){let e,l,n,i,o,u,a=be(t[1].h.c,2)+"",c,f,p,_,h,d,v,g=be(t[1].d.c,1)+"",E,$,M,P,F,A,I,D=be(t[1].m.c)+"",L,ie,H,K,G,Y,Q,z=be(t[0].last_month.c)+"",Z,V,j;return{c(){e=m("strong"),e.textContent="Cost",l=b(),n=m("div"),i=m("div"),i.textContent="Hour",o=b(),u=m("div"),c=T(a),f=b(),p=T(t[2]),_=b(),h=m("div"),h.textContent="Day",d=b(),v=m("div"),E=T(g),$=b(),M=T(t[2]),P=b(),F=m("div"),F.textContent="Month",A=b(),I=m("div"),L=T(D),ie=b(),H=T(t[2]),K=b(),G=m("div"),G.textContent="Last month",Y=b(),Q=m("div"),Z=T(z),V=b(),j=T(t[2]),r(u,"class","text-right"),r(v,"class","text-right"),r(I,"class","text-right"),r(Q,"class","text-right"),r(n,"class","grid grid-cols-2")},m(ee,ue){C(ee,e,ue),C(ee,l,ue),C(ee,n,ue),s(n,i),s(n,o),s(n,u),s(u,c),s(u,f),s(u,p),s(n,_),s(n,h),s(n,d),s(n,v),s(v,E),s(v,$),s(v,M),s(n,P),s(n,F),s(n,A),s(n,I),s(I,L),s(I,ie),s(I,H),s(n,K),s(n,G),s(n,Y),s(n,Q),s(Q,Z),s(Q,V),s(Q,j)},p(ee,ue){ue&2&&a!==(a=be(ee[1].h.c,2)+"")&&X(c,a),ue&4&&X(p,ee[2]),ue&2&&g!==(g=be(ee[1].d.c,1)+"")&&X(E,g),ue&4&&X(M,ee[2]),ue&2&&D!==(D=be(ee[1].m.c)+"")&&X(L,D),ue&4&&X(H,ee[2]),ue&1&&z!==(z=be(ee[0].last_month.c)+"")&&X(Z,z),ue&4&&X(j,ee[2])},d(ee){ee&&w(e),ee&&w(l),ee&&w(n)}}}function vu(t){let e,l=be(t[1].h.c,2)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].h.c,2)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function hu(t){let e,l=be(t[1].d.c,1)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].d.c,1)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function bu(t){let e,l=be(t[1].m.c)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].m.c)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function gu(t){let e,l=be(t[0].last_month.c)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&1&&l!==(l=be(u[0].last_month.c)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function ku(t){let e,l=be(t[1].h.i,2)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].h.i,2)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function wu(t){let e,l=be(t[1].d.i,1)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].d.i,1)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function yu(t){let e,l=be(t[1].m.i)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&2&&l!==(l=be(u[1].m.i)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function Cu(t){let e,l=be(t[0].last_month.i)+"",n,i,o;return{c(){e=m("div"),n=T(l),i=b(),o=T(t[2]),r(e,"class","text-right")},m(u,a){C(u,e,a),s(e,n),s(e,i),s(e,o)},p(u,a){a&1&&l!==(l=be(u[0].last_month.i)+"")&&X(n,l),a&4&&X(o,u[2])},d(u){u&&w(e)}}}function km(t){let e,l,n,i,o,u,a=t[1]&&_u(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Real time calculation",n=b(),i=m("br"),o=m("br"),u=b(),a&&a.c(),r(e,"class","mx-2 text-sm")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),s(e,u),a&&a.m(e,null)},p(c,[f]){c[1]?a?a.p(c,f):(a=_u(c),a.c(),a.m(e,null)):a&&(a.d(1),a=null)},i:_e,o:_e,d(c){c&&w(e),a&&a.d()}}}function wm(t,e,l){let{sysinfo:n}=e,{data:i}=e,{currency:o}=e,{hasExport:u}=e,a=!1,c=3;return t.$$set=f=>{"sysinfo"in f&&l(0,n=f.sysinfo),"data"in f&&l(1,i=f.data),"currency"in f&&l(2,o=f.currency),"hasExport"in f&&l(3,u=f.hasExport)},t.$$.update=()=>{t.$$.dirty&18&&(l(4,a=i&&i.h&&(Math.abs(i.h.c)>.01||Math.abs(i.d.c)>.01||Math.abs(i.m.c)>.01||Math.abs(i.h.i)>.01||Math.abs(i.d.i)>.01||Math.abs(i.m.i)>.01)),l(5,c=a?3:2))},[n,i,o,u,a,c]}class ym extends De{constructor(e){super(),Pe(this,e,wm,km,$e,{sysinfo:0,data:1,currency:2,hasExport:3})}}function Cm(t){let e,l,n=qa(t[0].source)+"",i,o,u,a;return u=new pn({props:{config:t[1]}}),{c(){e=m("a"),l=T("Provided by: "),i=T(n),o=b(),re(u.$$.fragment),r(e,"href","https://transparency.entsoe.eu/"),r(e,"target","_blank"),r(e,"class","text-xs float-right z-40")},m(c,f){C(c,e,f),s(e,l),s(e,i),C(c,o,f),se(u,c,f),a=!0},p(c,[f]){(!a||f&1)&&n!==(n=qa(c[0].source)+"")&&X(i,n);const p={};f&2&&(p.config=c[1]),u.$set(p)},i(c){a||(O(u.$$.fragment,c),a=!0)},o(c){B(u.$$.fragment,c),a=!1},d(c){c&&w(e),c&&w(o),oe(u,c)}}}function Mm(t,e,l){let{json:n}=e,{sysinfo:i}=e,o={},u,a;return t.$$set=c=>{"json"in c&&l(0,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&29){let c=n.currency,f=new Date().getUTCHours(),p=0,_=0,h=0,d=[],v=[],g=[];l(4,a=l(3,u=0));let E=new Date;for(dl(E,i.clock_offset-(24+E.getHours()-E.getUTCHours())%24),p=f;p<24&&(_=n[Fe(h++)],_!=null);p++)v.push({label:Fe(E.getHours())}),g.push(_*100),l(4,a=Math.min(a,_*100)),l(3,u=Math.max(u,_*100)),dl(E,1);for(p=0;p<24&&(_=n[Fe(h++)],_!=null);p++)v.push({label:Fe(E.getHours())}),g.push(_*100),l(4,a=Math.min(a,_*100)),l(3,u=Math.max(u,_*100)),dl(E,1);if(a>-100&&u<100){switch(c){case"NOK":case"SEK":case"DKK":c="øre";break;case"EUR":c="cent";break;default:c=c+"/100"}for(l(4,a*=100),l(3,u*=100),p=0;p=0?A.toFixed(I):"",title:A>=0?A.toFixed(2)+" "+c:"",value:_>=0?Math.abs(_):0,label2:A<0?A.toFixed(I):"",title2:A<0?A.toFixed(2)+" "+c:"",value2:_<0?Math.abs(_):0,color:"#7c3aed"})}let M=Math.max(u,Math.abs(a));if(a<0){l(4,a=Math.min(M/4*-1,a));let A=Math.ceil(Math.abs(a)/M*4),I=a/A;for(p=1;p{"json"in c&&l(1,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&30){let c=0,f=[],p=[],_=[];l(4,a=l(3,u=0));let h=dl(new Date,-24),d=new Date().getUTCHours();for(dl(h,i.clock_offset-(24+h.getHours()-h.getUTCHours())%24),c=d;c<24;c++){let $=n["i"+Fe(c)],M=n["e"+Fe(c)];$===void 0&&($=0),M===void 0&&(M=0),p.push({label:Fe(h.getHours())}),_.push({label:$.toFixed(1),title:$.toFixed(2)+" kWh",value:$*10,label2:M.toFixed(1),title2:M.toFixed(2)+" kWh",value2:M*10,color:"#7c3aed",color2:"#37829E"}),l(4,a=Math.max(a,M*10)),l(3,u=Math.max(u,$*10)),dl(h,1)}for(c=0;c{"json"in c&&l(1,n=c.json),"sysinfo"in c&&l(2,i=c.sysinfo)},t.$$.update=()=>{if(t.$$.dirty&30){let c=0,f=[],p=[],_=[];l(4,a=l(3,u=0));let h=new Date,d=new Date;for(dl(h,i.clock_offset-(24+h.getHours()-h.getUTCHours())%24),dl(d,i.clock_offset-(24+d.getHours()-d.getUTCHours())%24),d.setDate(0),c=h.getDate();c<=d.getDate();c++){let $=n["i"+Fe(c)],M=n["e"+Fe(c)];$===void 0&&($=0),M===void 0&&(M=0),p.push({label:Fe(c)}),_.push({label:$.toFixed($<10?1:0),title:$.toFixed(2)+" kWh",value:$,label2:M.toFixed(M<10?1:0),title2:M.toFixed(2)+" kWh",value2:M,color:"#7c3aed",color2:"#37829E"}),l(4,a=Math.max(a,M)),l(3,u=Math.max(u,$))}for(c=1;c{"json"in a&&l(1,n=a.json)},t.$$.update=()=>{if(t.$$.dirty&14){let a=0,c=0,f=[],p=[],_=[];n.s&&n.s.forEach((v,g)=>{var E=v.n?v.n:v.a;c=v.v,c==-127&&(c=0),p.push({label:E.slice(-4)}),_.push({label:c.toFixed(1),value:c,color:"#7c3aed"}),l(3,u=Math.min(u,c)),l(2,o=Math.max(o,c))}),l(2,o=Math.ceil(o)),l(3,u=Math.floor(u));let h=o;u<0&&(h+=Math.abs(u));let d=h/4;for(a=0;a<5;a++)c=u+d*a,f.push({value:c,label:c.toFixed(1)});l(0,i={title:"Temperature sensors (°C)",height:226,width:1520,padding:{top:20,right:15,bottom:20,left:35},y:{min:u,max:o,ticks:f},x:{ticks:p},points:_})}},[i,n,o,u]}class Om extends De{constructor(e){super(),Pe(this,e,Im,Dm,$e,{json:1})}}function Rm(t){let e,l;return e=new pn({props:{config:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,[i]){const o={};i&1&&(o.config=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}let Lm=0;function Fm(t,e,l){let n={},i=0,o;return zc.subscribe(u=>{l(2,o=u)}),Wc(),t.$$.update=()=>{if(t.$$.dirty&6){let u=0,a=[],c=[],f=[];if(a.push({value:0,label:0}),o&&o.p)for(u=0;u0?Fe(p.d)+"."+to[new Date().getMonth()]:"-"}),l(1,i=Math.max(i,p.v))}if(o&&o.t){for(u=0;u=i)break;a.push({value:p,label:p})}a.push({label:o.m.toFixed(1),align:"right",color:"green",value:o.m})}o&&o.c&&(a.push({label:o.c.toFixed(0),color:"orange",value:o.c}),l(1,i=Math.max(i,o.c))),l(1,i=Math.ceil(i)),l(0,n={title:"Tariff peaks",padding:{top:20,right:35,bottom:20,left:35},y:{min:Lm,max:i,ticks:a},x:{ticks:c},points:f})}},[n,i,o]}class qm extends De{constructor(e){super(),Pe(this,e,Fm,Rm,$e,{})}}function Mu(t,e,l){const n=t.slice();return n[18]=e[l],n[20]=l,n}function Su(t,e,l){const n=t.slice();return n[21]=e[l],n}function Tu(t){let e,l,n,i,o,u=t[7],a=[];for(let p=0;pt[14].call(e))},m(f,p){C(f,e,p),s(e,l),s(l,n),s(l,i),s(l,o),s(e,u),c&&c.m(e,null),a=ic(e,t[14].bind(e))},p(f,[p]){p&1024&&X(i,f[10]),f[7]?c?c.p(f,p):(c=Tu(f),c.c(),c.m(e,null)):c&&(c.d(1),c=null)},i:_e,o:_e,d(f){f&&w(e),c&&c.d(),a()}}}let Um=12;function jm(t,e,l){let n;Gc.subscribe(A=>{l(11,n=A)});let i,o=0;function u(){n.data.unshift(0),l(11,n.data=n.data.slice(0,n.size),n),o+=10,i=setTimeout(u,1e4)}Lc.subscribe(A=>{o>0?n.data&&A.u-o>=10&&(i&&clearTimeout(i),n.data.unshift(A.i-A.e),l(11,n.data=n.data.slice(0,n.size),n),o+=10,i=setTimeout(u,1e4)):o=A.u});let a,c,f,p,_,h,d,v,g,E,$,M,P;function F(){f=this.clientWidth,p=this.clientHeight,l(0,f),l(1,p)}return t.$$.update=()=>{if(t.$$.dirty&14847&&(l(2,_=parseInt(p)-50),l(3,h=f-35),l(9,M=h/n.size),l(13,c=0),l(12,a=0),n.data)){for(let I in n.data){let D=n.data[I];l(12,a=Math.max(Math.ceil(D/1e3)*1e3,a)),l(13,c=Math.min(Math.ceil(D/1e3)*1e3,c))}l(10,P=a>2500?"kW":"W"),l(7,E=[]);for(let I=c;I2500?(I/1e3).toFixed(1):I});l(8,$=[]);for(let I=c;I0||t[0].e>0}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o&2&&(u.sysinfo=i[1]),o&1&&(u.data=i[0].ea),o&1&&(u.currency=i[0].pc),o&1&&(u.hasExport=i[0].om>0||i[0].e>0),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function qu(t){let e,l,n;return l=new qm({}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt h-64")},m(i,o){C(i,e,o),se(l,e,null),n=!0},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function Bu(t){let e,l,n;return l=new Hm({}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt gwf")},m(i,o){C(i,e,o),se(l,e,null),n=!0},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function Uu(t){let e,l,n;return l=new Sm({props:{json:t[2],sysinfo:t[1]}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt gwf")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o&4&&(u.json=i[2]),o&2&&(u.sysinfo=i[1]),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function ju(t){let e,l,n;return l=new Nm({props:{json:t[3],sysinfo:t[1]}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt gwf")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o&8&&(u.json=i[3]),o&2&&(u.sysinfo=i[1]),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function Hu(t){let e,l,n;return l=new Pm({props:{json:t[4],sysinfo:t[1]}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt gwf")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o&16&&(u.json=i[4]),o&2&&(u.sysinfo=i[1]),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function Wu(t){let e,l,n;return l=new Om({props:{json:t[5]}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","cnt gwf")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o&32&&(u.json=i[5]),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function Wm(t){let e,l=Qe(t[1].ui.i,t[0].i),n,i=Qe(t[1].ui.e,t[0].om||t[0].e>0),o,u=Qe(t[1].ui.v,t[0].u1>100||t[0].u2>100||t[0].u3>100),a,c=Qe(t[1].ui.a,t[0].i1>.01||t[0].i2>.01||t[0].i3>.01),f,p=Qe(t[1].ui.r,t[0].ri>0||t[0].re>0||t[0].ric>0||t[0].rec>0),_,h=Qe(t[1].ui.c,t[0].ea),d,v=Qe(t[1].ui.t,t[0].pr&&(t[0].pr.startsWith("10YNO")||t[0].pr=="10Y1001A1001A48H")),g,E=Qe(t[1].ui.l),$,M=Qe(t[1].ui.p,t[0].pe&&!Number.isNaN(t[0].p)),P,F=Qe(t[1].ui.d,t[3]),A,I=Qe(t[1].ui.m,t[4]),D,L=Qe(t[1].ui.s,t[0].t&&t[0].t!=-127&&t[5].c>1),ie,H=l&&Du(t),K=i&&Iu(t),G=u&&Ou(t),Y=c&&Ru(t),Q=p&&Lu(t),z=h&&Fu(t),Z=v&&qu(),V=E&&Bu(),j=M&&Uu(t),ee=F&&ju(t),ue=I&&Hu(t),x=L&&Wu(t);return{c(){e=m("div"),H&&H.c(),n=b(),K&&K.c(),o=b(),G&&G.c(),a=b(),Y&&Y.c(),f=b(),Q&&Q.c(),_=b(),z&&z.c(),d=b(),Z&&Z.c(),g=b(),V&&V.c(),$=b(),j&&j.c(),P=b(),ee&&ee.c(),A=b(),ue&&ue.c(),D=b(),x&&x.c(),r(e,"class","grid 2xl:grid-cols-6 xl:grid-cols-5 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2")},m(W,U){C(W,e,U),H&&H.m(e,null),s(e,n),K&&K.m(e,null),s(e,o),G&&G.m(e,null),s(e,a),Y&&Y.m(e,null),s(e,f),Q&&Q.m(e,null),s(e,_),z&&z.m(e,null),s(e,d),Z&&Z.m(e,null),s(e,g),V&&V.m(e,null),s(e,$),j&&j.m(e,null),s(e,P),ee&&ee.m(e,null),s(e,A),ue&&ue.m(e,null),s(e,D),x&&x.m(e,null),ie=!0},p(W,[U]){U&3&&(l=Qe(W[1].ui.i,W[0].i)),l?H?(H.p(W,U),U&3&&O(H,1)):(H=Du(W),H.c(),O(H,1),H.m(e,n)):H&&(Ie(),B(H,1,1,()=>{H=null}),Oe()),U&3&&(i=Qe(W[1].ui.e,W[0].om||W[0].e>0)),i?K?(K.p(W,U),U&3&&O(K,1)):(K=Iu(W),K.c(),O(K,1),K.m(e,o)):K&&(Ie(),B(K,1,1,()=>{K=null}),Oe()),U&3&&(u=Qe(W[1].ui.v,W[0].u1>100||W[0].u2>100||W[0].u3>100)),u?G?(G.p(W,U),U&3&&O(G,1)):(G=Ou(W),G.c(),O(G,1),G.m(e,a)):G&&(Ie(),B(G,1,1,()=>{G=null}),Oe()),U&3&&(c=Qe(W[1].ui.a,W[0].i1>.01||W[0].i2>.01||W[0].i3>.01)),c?Y?(Y.p(W,U),U&3&&O(Y,1)):(Y=Ru(W),Y.c(),O(Y,1),Y.m(e,f)):Y&&(Ie(),B(Y,1,1,()=>{Y=null}),Oe()),U&3&&(p=Qe(W[1].ui.r,W[0].ri>0||W[0].re>0||W[0].ric>0||W[0].rec>0)),p?Q?(Q.p(W,U),U&3&&O(Q,1)):(Q=Lu(W),Q.c(),O(Q,1),Q.m(e,_)):Q&&(Ie(),B(Q,1,1,()=>{Q=null}),Oe()),U&3&&(h=Qe(W[1].ui.c,W[0].ea)),h?z?(z.p(W,U),U&3&&O(z,1)):(z=Fu(W),z.c(),O(z,1),z.m(e,d)):z&&(Ie(),B(z,1,1,()=>{z=null}),Oe()),U&3&&(v=Qe(W[1].ui.t,W[0].pr&&(W[0].pr.startsWith("10YNO")||W[0].pr=="10Y1001A1001A48H"))),v?Z?U&3&&O(Z,1):(Z=qu(),Z.c(),O(Z,1),Z.m(e,g)):Z&&(Ie(),B(Z,1,1,()=>{Z=null}),Oe()),U&2&&(E=Qe(W[1].ui.l)),E?V?U&2&&O(V,1):(V=Bu(),V.c(),O(V,1),V.m(e,$)):V&&(Ie(),B(V,1,1,()=>{V=null}),Oe()),U&3&&(M=Qe(W[1].ui.p,W[0].pe&&!Number.isNaN(W[0].p))),M?j?(j.p(W,U),U&3&&O(j,1)):(j=Uu(W),j.c(),O(j,1),j.m(e,P)):j&&(Ie(),B(j,1,1,()=>{j=null}),Oe()),U&10&&(F=Qe(W[1].ui.d,W[3])),F?ee?(ee.p(W,U),U&10&&O(ee,1)):(ee=ju(W),ee.c(),O(ee,1),ee.m(e,A)):ee&&(Ie(),B(ee,1,1,()=>{ee=null}),Oe()),U&18&&(I=Qe(W[1].ui.m,W[4])),I?ue?(ue.p(W,U),U&18&&O(ue,1)):(ue=Hu(W),ue.c(),O(ue,1),ue.m(e,D)):ue&&(Ie(),B(ue,1,1,()=>{ue=null}),Oe()),U&35&&(L=Qe(W[1].ui.s,W[0].t&&W[0].t!=-127&&W[5].c>1)),L?x?(x.p(W,U),U&35&&O(x,1)):(x=Wu(W),x.c(),O(x,1),x.m(e,null)):x&&(Ie(),B(x,1,1,()=>{x=null}),Oe())},i(W){ie||(O(H),O(K),O(G),O(Y),O(Q),O(z),O(Z),O(V),O(j),O(ee),O(ue),O(x),ie=!0)},o(W){B(H),B(K),B(G),B(Y),B(Q),B(z),B(Z),B(V),B(j),B(ee),B(ue),B(x),ie=!1},d(W){W&&w(e),H&&H.d(),K&&K.d(),G&&G.d(),Y&&Y.d(),Q&&Q.d(),z&&z.d(),Z&&Z.d(),V&&V.d(),j&&j.d(),ee&&ee.d(),ue&&ue.d(),x&&x.d()}}}function zm(t,e,l){let{data:n={}}=e,{sysinfo:i={}}=e,o={},u={},a={},c={};return Co.subscribe(f=>{l(2,o=f)}),Bc.subscribe(f=>{l(3,u=f)}),Uc.subscribe(f=>{l(4,a=f)}),Hc.subscribe(f=>{l(5,c=f)}),t.$$set=f=>{"data"in f&&l(0,n=f.data),"sysinfo"in f&&l(1,i=f.sysinfo)},[n,i,o,u,a,c]}class Gm extends De{constructor(e){super(),Pe(this,e,zm,Wm,$e,{data:0,sysinfo:1})}}let uo={};const yi=it(uo);async function Vm(){uo=await(await fetch("/configuration.json")).json(),yi.set(uo)}function zu(t,e,l){const n=t.slice();return n[2]=e[l],n[4]=l,n}function Km(t){let e;return{c(){e=m("option"),e.textContent="UART0",e.__value=3,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Ym(t){let e;return{c(){e=m("option"),e.textContent="UART0",e.__value=20,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Gu(t){let e;return{c(){e=m("option"),e.textContent="UART2",e.__value=113,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Vu(t){let e,l,n;return{c(){e=m("option"),e.textContent="UART1",l=b(),n=m("option"),n.textContent="UART2",e.__value=9,e.value=e.__value,n.__value=16,n.value=n.__value},m(i,o){C(i,e,o),C(i,l,o),C(i,n,o)},d(i){i&&w(e),i&&w(l),i&&w(n)}}}function Ku(t){let e;return{c(){e=m("option"),e.textContent="UART1",e.__value=18,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Yu(t){let e,l,n;return{c(){e=m("option"),l=T("GPIO"),n=T(t[4]),e.__value=t[4],e.value=e.__value},m(i,o){C(i,e,o),s(e,l),s(e,n)},d(i){i&&w(e)}}}function Qu(t){let e,l=t[4]>3&&!(t[0]=="esp32"&&(t[4]==9||t[4]==16))&&!(t[0]=="esp32s2"&&t[4]==18)&&!(t[0]=="esp8266"&&(t[4]==3||t[4]==113))&&Yu(t);return{c(){l&&l.c(),e=Ve()},m(n,i){l&&l.m(n,i),C(n,e,i)},p(n,i){n[4]>3&&!(n[0]=="esp32"&&(n[4]==9||n[4]==16))&&!(n[0]=="esp32s2"&&n[4]==18)&&!(n[0]=="esp8266"&&(n[4]==3||n[4]==113))?l||(l=Yu(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},d(n){l&&l.d(n),n&&w(e)}}}function Qm(t){let e,l,n,i,o;function u(v,g){return v[0]=="esp32c3"?Ym:Km}let a=u(t),c=a(t),f=t[0]=="esp8266"&&Gu(),p=(t[0]=="esp32"||t[0]=="esp32solo")&&Vu(),_=t[0]=="esp32s2"&&Ku(),h={length:t[1]+1},d=[];for(let v=0;v{"chip"in o&&l(0,n=o.chip)},t.$$.update=()=>{if(t.$$.dirty&1)switch(n){case"esp8266":l(1,i=16);break;case"esp32s2":l(1,i=44);break;case"esp32c3":l(1,i=19);break}},[n,i]}class fo extends De{constructor(e){super(),Pe(this,e,Xm,Qm,$e,{chip:0})}}function Xu(t){let e,l,n=t[1]&&Zu(t);return{c(){e=m("div"),l=m("div"),n&&n.c(),r(l,"class","fixed inset-0 bg-gray-500 dark:bg-gray-900 bg-opacity-50 flex items-center justify-center"),r(e,"class","z-50"),r(e,"aria-modal","true")},m(i,o){C(i,e,o),s(e,l),n&&n.m(l,null)},p(i,o){i[1]?n?n.p(i,o):(n=Zu(i),n.c(),n.m(l,null)):n&&(n.d(1),n=null)},d(i){i&&w(e),n&&n.d()}}}function Zu(t){let e,l;return{c(){e=m("div"),l=T(t[1]),r(e,"class","bg-white dark:bg-gray-600 m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700 dark:text-white w-96")},m(n,i){C(n,e,i),s(e,l)},p(n,i){i&2&&X(l,n[1])},d(n){n&&w(e)}}}function Zm(t){let e,l=t[0]&&Xu(t);return{c(){l&&l.c(),e=Ve()},m(n,i){l&&l.m(n,i),C(n,e,i)},p(n,[i]){n[0]?l?l.p(n,i):(l=Xu(n),l.c(),l.m(e.parentNode,e)):l&&(l.d(1),l=null)},i:_e,o:_e,d(n){l&&l.d(n),n&&w(e)}}}function Jm(t,e,l){let{active:n}=e,{message:i}=e;return t.$$set=o=>{"active"in o&&l(0,n=o.active),"message"in o&&l(1,i=o.message)},[n,i]}class jt extends De{constructor(e){super(),Pe(this,e,Jm,Zm,$e,{active:0,message:1})}}function Ju(t,e,l){const n=t.slice();return n[1]=e[l],n}function xu(t){let e,l,n=t[1]+"",i;return{c(){e=m("option"),l=T("Europe/"),i=T(n),e.__value="Europe/"+t[1],e.value=e.__value},m(o,u){C(o,e,u),s(e,l),s(e,i)},p:_e,d(o){o&&w(e)}}}function xm(t){let e,l,n,i=t[0],o=[];for(let u=0;u>1&1,N=0;N0;k--)N[k]=N[k]?N[k-1]^A.EXPONENT[L._modN(A.LOG[N[k]]+S)]:N[k-1];N[0]=A.EXPONENT[L._modN(A.LOG[N[0]]+S)]}for(S=0;S<=y;S++)N[S]=A.LOG[N[S]]},_checkBadness:function(){var S,k,y,N,R,J=0,te=this._badness,fe=this.buffer,de=this.width;for(R=0;Rde*de;)ae-=de*de,Ae++;for(J+=Ae*L.N4,N=0;N=te-2&&(S=te-2,R>9&&S--);var fe=S;if(R>9){for(J[fe+2]=0,J[fe+3]=0;fe--;)k=J[fe],J[fe+3]|=255&k<<4,J[fe+2]=k>>4;J[2]|=255&S<<4,J[1]=S>>4,J[0]=64|S>>12}else{for(J[fe+1]=0,J[fe+2]=0;fe--;)k=J[fe],J[fe+2]|=255&k<<4,J[fe+1]=k>>4;J[1]|=255&S<<4,J[0]=64|S>>4}for(fe=S+3-(R<10);fe=5&&(y+=L.N1+N[k]-5);for(k=3;kS||N[k-3]*3>=N[k]*4||N[k+3]*3>=N[k]*4)&&(y+=L.N3);return y},_finish:function(){this._stringBuffer=this.buffer.slice();var S,k,y=0,N=3e4;for(k=0;k<8&&(this._applyMask(k),S=this._checkBadness(),S>=1)N&1&&(R[J-1-k+J*8]=1,k<6?R[8+J*k]=1:R[8+J*(k+1)]=1);for(k=0;k<7;k++,N>>=1)N&1&&(R[8+J*(J-7+k)]=1,k?R[6-k+J*8]=1:R[7+J*8]=1)},_interleaveBlocks:function(){var S,k,y=this._dataBlock,N=this._ecc,R=this._eccBlock,J=0,te=this._calculateMaxLength(),fe=this._neccBlock1,de=this._neccBlock2,we=this._stringBuffer;for(S=0;S1)for(S=$.BLOCK[N],y=R-7;;){for(k=R-7;k>S-3&&(this._addAlignment(k,y),!(k6)for(S=D.BLOCK[J-7],k=17,y=0;y<6;y++)for(N=0;N<3;N++,k--)1&(k>11?J>>k-12:S>>k)?(R[5-y+te*(2-N+te-11)]=1,R[2-N+te-11+te*(5-y)]=1):(this._setMask(5-y,2-N+te-11),this._setMask(2-N+te-11,5-y))},_isMasked:function(S,k){var y=L._getMaskBit(S,k);return this._mask[y]===1},_pack:function(){var S,k,y,N=1,R=1,J=this.width,te=J-1,fe=J-1,de=(this._dataBlock+this._eccBlock)*(this._neccBlock1+this._neccBlock2)+this._neccBlock2;for(k=0;kk&&(y=S,S=k,k=y),y=k,y+=k*k,y>>=1,y+=S,y},_modN:function(S){for(;S>=255;)S-=255,S=(S>>8)+(S&255);return S},N1:3,N2:3,N3:40,N4:10}),ie=L,H=d.extend({draw:function(){this.element.src=this.qrious.toDataURL()},reset:function(){this.element.src=""},resize:function(){var S=this.element;S.width=S.height=this.qrious.size}}),K=H,G=_.extend(function(S,k,y,N){this.name=S,this.modifiable=!!k,this.defaultValue=y,this._valueTransformer=N},{transform:function(S){var k=this._valueTransformer;return typeof k=="function"?k(S,this):S}}),Y=G,Q=_.extend(null,{abs:function(S){return S!=null?Math.abs(S):null},hasOwn:function(S,k){return Object.prototype.hasOwnProperty.call(S,k)},noop:function(){},toUpperCase:function(S){return S!=null?S.toUpperCase():null}}),z=Q,Z=_.extend(function(S){this.options={},S.forEach(function(k){this.options[k.name]=k},this)},{exists:function(S){return this.options[S]!=null},get:function(S,k){return Z._get(this.options[S],k)},getAll:function(S){var k,y=this.options,N={};for(k in y)z.hasOwn(y,k)&&(N[k]=Z._get(y[k],S));return N},init:function(S,k,y){typeof y!="function"&&(y=z.noop);var N,R;for(N in this.options)z.hasOwn(this.options,N)&&(R=this.options[N],Z._set(R,R.defaultValue,k),Z._createAccessor(R,k,y));this._setAll(S,k,!0)},set:function(S,k,y){return this._set(S,k,y)},setAll:function(S,k){return this._setAll(S,k)},_set:function(S,k,y,N){var R=this.options[S];if(!R)throw new Error("Invalid option: "+S);if(!R.modifiable&&!N)throw new Error("Option cannot be modified: "+S);return Z._set(R,k,y)},_setAll:function(S,k,y){if(!S)return!1;var N,R=!1;for(N in S)z.hasOwn(S,N)&&this._set(N,S[N],k,y)&&(R=!0);return R}},{_createAccessor:function(S,k,y){var N={get:function(){return Z._get(S,k)}};S.modifiable&&(N.set=function(R){Z._set(S,R,k)&&y(R,S)}),Object.defineProperty(k,S.name,N)},_get:function(S,k){return k["_"+S.name]},_set:function(S,k,y){var N="_"+S.name,R=y[N],J=S.transform(k??S.defaultValue);return y[N]=J,J!==R}}),V=Z,j=_.extend(function(){this._services={}},{getService:function(S){var k=this._services[S];if(!k)throw new Error("Service is not being managed with name: "+S);return k},setService:function(S,k){if(this._services[S])throw new Error("Service is already managed with name: "+S);k&&(this._services[S]=k)}}),ee=j,ue=new V([new Y("background",!0,"white"),new Y("backgroundAlpha",!0,1,z.abs),new Y("element"),new Y("foreground",!0,"black"),new Y("foregroundAlpha",!0,1,z.abs),new Y("level",!0,"L",z.toUpperCase),new Y("mime",!0,"image/png"),new Y("padding",!0,null,z.abs),new Y("size",!0,100,z.abs),new Y("value",!0,"")]),x=new ee,W=_.extend(function(S){ue.init(S,this,this.update.bind(this));var k=ue.get("element",this),y=x.getService("element"),N=k&&y.isCanvas(k)?k:y.createCanvas(),R=k&&y.isImage(k)?k:y.createImage();this._canvasRenderer=new g(this,N,!0),this._imageRenderer=new K(this,R,R===k),this.update()},{get:function(){return ue.getAll(this)},set:function(S){ue.setAll(S,this)&&this.update()},toDataURL:function(S){return this.canvas.toDataURL(S||this.mime)},update:function(){var S=new ie({level:this.level,value:this.value});this._canvasRenderer.render(S),this._imageRenderer.render(S)}},{use:function(S){x.setService(S.getName(),S)}});Object.defineProperties(W.prototype,{canvas:{get:function(){return this._canvasRenderer.getElement()}},image:{get:function(){return this._imageRenderer.getElement()}}});var U=W,ke=U,He=_.extend({getName:function(){}}),Be=He,We=Be.extend({createCanvas:function(){},createImage:function(){},getName:function(){return"element"},isCanvas:function(S){},isImage:function(S){}}),Ne=We,ge=Ne.extend({createCanvas:function(){return document.createElement("canvas")},createImage:function(){return document.createElement("img")},isCanvas:function(S){return S instanceof HTMLCanvasElement},isImage:function(S){return S instanceof HTMLImageElement}}),Re=ge;ke.use(new Re);var Me=ke;return Me})})(Jc);var op=Jc.exports;const rp=sp(op);function ap(t){let e,l;return{c(){e=m("img"),Xs(e.src,l=t[2])||r(e,"src",l),r(e,"alt",t[0]),r(e,"class",t[1])},m(n,i){C(n,e,i)},p(n,[i]){i&4&&!Xs(e.src,l=n[2])&&r(e,"src",l),i&1&&r(e,"alt",n[0]),i&2&&r(e,"class",n[1])},i:_e,o:_e,d(n){n&&w(e)}}}function up(t,e,l){const n=new rp;let{errorCorrection:i="L"}=e,{background:o="#fff"}=e,{color:u="#000"}=e,{size:a="200"}=e,{value:c=""}=e,{padding:f=0}=e,{className:p="qrcode"}=e,_="";function h(){n.set({background:o,foreground:u,level:i,padding:f,size:a,value:c}),l(2,_=n.toDataURL("image/jpeg"))}return sc(()=>{h()}),t.$$set=d=>{"errorCorrection"in d&&l(3,i=d.errorCorrection),"background"in d&&l(4,o=d.background),"color"in d&&l(5,u=d.color),"size"in d&&l(6,a=d.size),"value"in d&&l(0,c=d.value),"padding"in d&&l(7,f=d.padding),"className"in d&&l(1,p=d.className)},t.$$.update=()=>{t.$$.dirty&1&&c&&h()},[c,p,_,i,o,u,a,f]}class fp extends De{constructor(e){super(),Pe(this,e,up,ap,$e,{errorCorrection:3,background:4,color:5,size:6,value:0,padding:7,className:1})}}function ef(t,e,l){const n=t.slice();return n[103]=e[l],n[104]=e,n[105]=l,n}function tf(t,e,l){const n=t.slice();return n[106]=e[l],n[107]=e,n[108]=l,n}function cp(t,e,l){const n=t.slice();return n[109]=e[l],n}function mp(t,e,l){const n=t.slice();return n[112]=e[l],n}function pp(t){let e,l;return{c(){e=m("option"),l=T(t[112]),e.__value=t[112],e.value=e.__value},m(n,i){C(n,e,i),s(e,l)},p:_e,d(n){n&&w(e)}}}function lf(t){let e,l,n,i;return{c(){e=m("br"),l=m("input"),r(l,"name","pt"),r(l,"type","text"),r(l,"class","in-s"),r(l,"placeholder","ENTSO-E API key, optional, read docs")},m(o,u){C(o,e,u),C(o,l,u),ne(l,t[3].p.t),n||(i=le(l,"input",t[22]),n=!0)},p(o,u){u[0]&8&&l.value!==o[3].p.t&&ne(l,o[3].p.t)},d(o){o&&w(e),o&&w(l),n=!1,i()}}}function nf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d;return{c(){e=m("div"),l=T("Username"),n=m("br"),i=b(),o=m("input"),u=b(),a=m("div"),c=T("Password"),f=m("br"),p=b(),_=m("input"),r(o,"name","gu"),r(o,"type","text"),r(o,"class","in-s"),r(e,"class","my-1"),r(_,"name","gp"),r(_,"type","password"),r(_,"class","in-s"),r(a,"class","my-1")},m(v,g){C(v,e,g),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].g.u),C(v,u,g),C(v,a,g),s(a,c),s(a,f),s(a,p),s(a,_),ne(_,t[3].g.p),h||(d=[le(o,"input",t[24]),le(_,"input",t[25])],h=!0)},p(v,g){g[0]&8&&o.value!==v[3].g.u&&ne(o,v[3].g.u),g[0]&8&&_.value!==v[3].g.p&&ne(_,v[3].g.p)},d(v){v&&w(e),v&&w(u),v&&w(a),h=!1,Ge(d)}}}function _p(t){let e,l=t[109]*100+"",n;return{c(){e=m("option"),n=T(l),e.__value=t[109]*100,e.value=e.__value},m(i,o){C(i,e,o),s(e,n)},p:_e,d(i){i&&w(e)}}}function sf(t){let e,l,n,i;return{c(){e=m("br"),l=m("input"),r(l,"name","mek"),r(l,"type","text"),r(l,"class","in-s")},m(o,u){C(o,e,u),C(o,l,u),ne(l,t[3].m.e.k),n||(i=le(l,"input",t[35]),n=!0)},p(o,u){u[0]&8&&l.value!==o[3].m.e.k&&ne(l,o[3].m.e.k)},d(o){o&&w(e),o&&w(l),n=!1,i()}}}function of(t){let e,l,n,i,o,u,a;return{c(){e=m("div"),l=T("Authentication key"),n=m("br"),i=b(),o=m("input"),r(o,"name","mea"),r(o,"type","text"),r(o,"class","in-s"),r(e,"class","my-1")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].m.e.a),u||(a=le(o,"input",t[36]),u=!0)},p(c,f){f[0]&8&&o.value!==c[3].m.e.a&&ne(o,c[3].m.e.a)},d(c){c&&w(e),u=!1,a()}}}function rf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H;return{c(){e=m("div"),l=m("div"),n=T("Watt"),i=m("br"),o=b(),u=m("input"),a=b(),c=m("div"),f=T("Volt"),p=m("br"),_=b(),h=m("input"),d=b(),v=m("div"),g=T("Amp"),E=m("br"),$=b(),M=m("input"),P=b(),F=m("div"),A=T("kWh"),I=m("br"),D=b(),L=m("input"),r(u,"name","mmw"),r(u,"type","number"),r(u,"min","0.00"),r(u,"max","1000"),r(u,"step","0.001"),r(u,"class","in-f tr w-full"),r(l,"class","w-1/4"),r(h,"name","mmv"),r(h,"type","number"),r(h,"min","0.00"),r(h,"max","1000"),r(h,"step","0.001"),r(h,"class","in-m tr w-full"),r(c,"class","w-1/4"),r(M,"name","mma"),r(M,"type","number"),r(M,"min","0.00"),r(M,"max","1000"),r(M,"step","0.001"),r(M,"class","in-m tr w-full"),r(v,"class","w-1/4"),r(L,"name","mmc"),r(L,"type","number"),r(L,"min","0.00"),r(L,"max","1000"),r(L,"step","0.001"),r(L,"class","in-l tr w-full"),r(F,"class","w-1/4"),r(e,"class","flex my-1")},m(K,G){C(K,e,G),s(e,l),s(l,n),s(l,i),s(l,o),s(l,u),ne(u,t[3].m.m.w),s(e,a),s(e,c),s(c,f),s(c,p),s(c,_),s(c,h),ne(h,t[3].m.m.v),s(e,d),s(e,v),s(v,g),s(v,E),s(v,$),s(v,M),ne(M,t[3].m.m.a),s(e,P),s(e,F),s(F,A),s(F,I),s(F,D),s(F,L),ne(L,t[3].m.m.c),ie||(H=[le(u,"input",t[38]),le(h,"input",t[39]),le(M,"input",t[40]),le(L,"input",t[41])],ie=!0)},p(K,G){G[0]&8&&he(u.value)!==K[3].m.m.w&&ne(u,K[3].m.m.w),G[0]&8&&he(h.value)!==K[3].m.m.v&&ne(h,K[3].m.m.v),G[0]&8&&he(M.value)!==K[3].m.m.a&&ne(M,K[3].m.m.a),G[0]&8&&he(L.value)!==K[3].m.m.c&&ne(L,K[3].m.m.c)},d(K){K&&w(e),ie=!1,Ge(H)}}}function af(t){let e;return{c(){e=m("option"),e.textContent="Ethernet",e.__value=3,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function uf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue,x,W;return{c(){e=m("div"),l=T("SSID"),n=m("br"),i=b(),o=m("input"),u=b(),a=m("div"),c=T("Password"),f=m("br"),p=b(),_=m("input"),h=b(),d=m("div"),v=m("div"),g=T("Power saving"),E=m("br"),$=b(),M=m("select"),P=m("option"),P.textContent="Default",F=m("option"),F.textContent="Off",A=m("option"),A.textContent="Minimum",I=m("option"),I.textContent="Maximum",D=b(),L=m("div"),ie=T("Power"),H=m("br"),K=b(),G=m("div"),Y=m("input"),Q=b(),z=m("span"),z.textContent="dBm",Z=b(),V=m("div"),j=m("label"),ee=m("input"),ue=T(" Allow 802.11b legacy rates"),r(o,"name","ws"),r(o,"type","text"),r(o,"class","in-s"),r(e,"class","my-1"),r(_,"name","wp"),r(_,"type","password"),r(_,"class","in-s"),r(a,"class","my-1"),P.__value=255,P.value=P.__value,F.__value=0,F.value=F.__value,A.__value=1,A.value=A.__value,I.__value=2,I.value=I.__value,r(M,"name","wz"),r(M,"class","in-s"),t[3].w.z===void 0&&Ke(()=>t[45].call(M)),r(v,"class","w-1/2"),r(Y,"name","ww"),r(Y,"type","number"),r(Y,"min","0"),r(Y,"max","20.5"),r(Y,"step","0.5"),r(Y,"class","in-f tr w-full"),r(z,"class","in-post"),r(G,"class","flex"),r(L,"class","ml-2 w-1/2"),r(d,"class","my-1 flex"),r(ee,"type","checkbox"),r(ee,"name","wb"),ee.__value="true",ee.value=ee.__value,r(ee,"class","rounded mb-1"),r(V,"class","my-3")},m(U,ke){C(U,e,ke),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].w.s),C(U,u,ke),C(U,a,ke),s(a,c),s(a,f),s(a,p),s(a,_),ne(_,t[3].w.p),C(U,h,ke),C(U,d,ke),s(d,v),s(v,g),s(v,E),s(v,$),s(v,M),s(M,P),s(M,F),s(M,A),s(M,I),Se(M,t[3].w.z,!0),s(d,D),s(d,L),s(L,ie),s(L,H),s(L,K),s(L,G),s(G,Y),ne(Y,t[3].w.w),s(G,Q),s(G,z),C(U,Z,ke),C(U,V,ke),s(V,j),s(j,ee),ee.checked=t[3].w.b,s(j,ue),x||(W=[le(o,"input",t[43]),le(_,"input",t[44]),le(M,"change",t[45]),le(Y,"input",t[46]),le(ee,"change",t[47])],x=!0)},p(U,ke){ke[0]&8&&o.value!==U[3].w.s&&ne(o,U[3].w.s),ke[0]&8&&_.value!==U[3].w.p&&ne(_,U[3].w.p),ke[0]&8&&Se(M,U[3].w.z),ke[0]&8&&he(Y.value)!==U[3].w.w&&ne(Y,U[3].w.w),ke[0]&8&&(ee.checked=U[3].w.b)},d(U){U&&w(e),U&&w(u),U&&w(a),U&&w(h),U&&w(d),U&&w(Z),U&&w(V),x=!1,Ge(W)}}}function ff(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E;return{c(){e=m("div"),l=T("Gateway"),n=m("br"),i=b(),o=m("input"),u=b(),a=m("div"),c=T("DNS"),f=m("br"),p=b(),_=m("div"),h=m("input"),d=b(),v=m("input"),r(o,"name","ng"),r(o,"type","text"),r(o,"class","in-s"),r(e,"class","my-1"),r(h,"name","nd1"),r(h,"type","text"),r(h,"class","in-f w-full"),r(v,"name","nd2"),r(v,"type","text"),r(v,"class","in-l w-full"),r(_,"class","flex"),r(a,"class","my-1")},m($,M){C($,e,M),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].n.g),C($,u,M),C($,a,M),s(a,c),s(a,f),s(a,p),s(a,_),s(_,h),ne(h,t[3].n.d1),s(_,d),s(_,v),ne(v,t[3].n.d2),g||(E=[le(o,"input",t[51]),le(h,"input",t[52]),le(v,"input",t[53])],g=!0)},p($,M){M[0]&8&&o.value!==$[3].n.g&&ne(o,$[3].n.g),M[0]&8&&h.value!==$[3].n.d1&&ne(h,$[3].n.d1),M[0]&8&&v.value!==$[3].n.d2&&ne(v,$[3].n.d2)},d($){$&&w(e),$&&w(u),$&&w(a),g=!1,Ge(E)}}}function cf(t){let e,l,n,i,o;return{c(){e=m("label"),l=m("input"),n=T(" SSL"),r(l,"type","checkbox"),r(l,"name","qs"),l.__value="true",l.value=l.__value,r(l,"class","rounded mb-1"),r(e,"class","float-right mr-3")},m(u,a){C(u,e,a),s(e,l),l.checked=t[3].q.s.e,s(e,n),i||(o=[le(l,"change",t[57]),le(l,"change",t[14])],i=!0)},p(u,a){a[0]&8&&(l.checked=u[3].q.s.e)},d(u){u&&w(e),i=!1,Ge(o)}}}function mf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d;const v=[vp,dp],g=[];function E(D,L){return D[3].q.s.c?0:1}n=E(t),i=g[n]=v[n](t);const $=[kp,gp],M=[];function P(D,L){return D[3].q.s.r?0:1}a=P(t),c=M[a]=$[a](t);const F=[Mp,Cp],A=[];function I(D,L){return D[3].q.s.k?0:1}return _=I(t),h=A[_]=F[_](t),{c(){e=m("div"),l=m("span"),i.c(),o=b(),u=m("span"),c.c(),f=b(),p=m("span"),h.c(),r(l,"class","flex pr-2"),r(u,"class","flex pr-2"),r(p,"class","flex pr-2"),r(e,"class","my-1 flex")},m(D,L){C(D,e,L),s(e,l),g[n].m(l,null),s(e,o),s(e,u),M[a].m(u,null),s(e,f),s(e,p),A[_].m(p,null),d=!0},p(D,L){let ie=n;n=E(D),n===ie?g[n].p(D,L):(Ie(),B(g[ie],1,1,()=>{g[ie]=null}),Oe(),i=g[n],i?i.p(D,L):(i=g[n]=v[n](D),i.c()),O(i,1),i.m(l,null));let H=a;a=P(D),a===H?M[a].p(D,L):(Ie(),B(M[H],1,1,()=>{M[H]=null}),Oe(),c=M[a],c?c.p(D,L):(c=M[a]=$[a](D),c.c()),O(c,1),c.m(u,null));let K=_;_=I(D),_===K?A[_].p(D,L):(Ie(),B(A[K],1,1,()=>{A[K]=null}),Oe(),h=A[_],h?h.p(D,L):(h=A[_]=F[_](D),h.c()),O(h,1),h.m(p,null))},i(D){d||(O(i),O(c),O(h),d=!0)},o(D){B(i),B(c),B(h),d=!1},d(D){D&&w(e),g[n].d(),M[a].d(),A[_].d()}}}function dp(t){let e,l;return e=new ol({props:{to:"/mqtt-ca",$$slots:{default:[hp]},$$scope:{ctx:t}}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i[3]&4194304&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function vp(t){let e,l,n,i,o,u,a,c;return l=new ol({props:{to:"/mqtt-ca",$$slots:{default:[bp]},$$scope:{ctx:t}}}),o=new $o({}),{c(){e=m("span"),re(l.$$.fragment),n=b(),i=m("span"),re(o.$$.fragment),r(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),r(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){C(f,e,p),se(l,e,null),C(f,n,p),C(f,i,p),se(o,i,null),u=!0,a||(c=[le(i,"click",t[11]),le(i,"keypress",t[11])],a=!0)},p(f,p){const _={};p[3]&4194304&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){u||(O(l.$$.fragment,f),O(o.$$.fragment,f),u=!0)},o(f){B(l.$$.fragment,f),B(o.$$.fragment,f),u=!1},d(f){f&&w(e),oe(l),f&&w(n),f&&w(i),oe(o),a=!1,Ge(c)}}}function hp(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload CA",title:"Click here to upload CA"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function bp(t){let e;return{c(){e=T("CA OK")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function gp(t){let e,l;return e=new ol({props:{to:"/mqtt-cert",$$slots:{default:[wp]},$$scope:{ctx:t}}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i[3]&4194304&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function kp(t){let e,l,n,i,o,u,a,c;return l=new ol({props:{to:"/mqtt-cert",$$slots:{default:[yp]},$$scope:{ctx:t}}}),o=new $o({}),{c(){e=m("span"),re(l.$$.fragment),n=b(),i=m("span"),re(o.$$.fragment),r(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),r(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){C(f,e,p),se(l,e,null),C(f,n,p),C(f,i,p),se(o,i,null),u=!0,a||(c=[le(i,"click",t[12]),le(i,"keypress",t[12])],a=!0)},p(f,p){const _={};p[3]&4194304&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){u||(O(l.$$.fragment,f),O(o.$$.fragment,f),u=!0)},o(f){B(l.$$.fragment,f),B(o.$$.fragment,f),u=!1},d(f){f&&w(e),oe(l),f&&w(n),f&&w(i),oe(o),a=!1,Ge(c)}}}function wp(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload cert",title:"Click here to upload certificate"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function yp(t){let e;return{c(){e=T("Cert OK")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Cp(t){let e,l;return e=new ol({props:{to:"/mqtt-key",$$slots:{default:[Sp]},$$scope:{ctx:t}}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i[3]&4194304&&(o.$$scope={dirty:i,ctx:n}),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function Mp(t){let e,l,n,i,o,u,a,c;return l=new ol({props:{to:"/mqtt-key",$$slots:{default:[Tp]},$$scope:{ctx:t}}}),o=new $o({}),{c(){e=m("span"),re(l.$$.fragment),n=b(),i=m("span"),re(o.$$.fragment),r(e,"class","rounded-l-md bg-green-500 text-green-100 text-xs font-semibold px-2.5 py-1"),r(i,"class","rounded-r-md bg-red-500 text-red-100 text-xs px-2.5 py-1")},m(f,p){C(f,e,p),se(l,e,null),C(f,n,p),C(f,i,p),se(o,i,null),u=!0,a||(c=[le(i,"click",t[13]),le(i,"keypress",t[13])],a=!0)},p(f,p){const _={};p[3]&4194304&&(_.$$scope={dirty:p,ctx:f}),l.$set(_)},i(f){u||(O(l.$$.fragment,f),O(o.$$.fragment,f),u=!0)},o(f){B(l.$$.fragment,f),B(o.$$.fragment,f),u=!1},d(f){f&&w(e),oe(l),f&&w(n),f&&w(i),oe(o),a=!1,Ge(c)}}}function Sp(t){let e,l;return e=new fn({props:{color:"blue",text:"Upload key",title:"Click here to upload key"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function Tp(t){let e;return{c(){e=T("Key OK")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function pf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z;return o=new Bt({}),{c(){e=m("div"),l=m("strong"),l.textContent="Domoticz",n=b(),i=m("a"),re(o.$$.fragment),u=b(),a=m("input"),c=b(),f=m("div"),p=m("div"),_=T("Electricity IDX"),h=m("br"),d=b(),v=m("input"),g=b(),E=m("div"),$=T("Current IDX"),M=m("br"),P=b(),F=m("input"),A=b(),I=m("div"),D=T(`Voltage IDX: L1, L2 & L3 + `),L=m("div"),ie=m("input"),H=b(),K=m("input"),G=b(),Y=m("input"),r(l,"class","text-sm"),r(i,"href",Ut("MQTT-configuration#domoticz")),r(i,"target","_blank"),r(i,"class","float-right"),r(a,"type","hidden"),r(a,"name","o"),a.value="true",r(v,"name","oe"),r(v,"type","text"),r(v,"class","in-f tr w-full"),r(p,"class","w-1/2"),r(F,"name","oc"),r(F,"type","text"),r(F,"class","in-l tr w-full"),r(E,"class","w-1/2"),r(f,"class","my-1 flex"),r(ie,"name","ou1"),r(ie,"type","text"),r(ie,"class","in-f tr w-1/3"),r(K,"name","ou2"),r(K,"type","text"),r(K,"class","in-m tr w-1/3"),r(Y,"name","ou3"),r(Y,"type","text"),r(Y,"class","in-l tr w-1/3"),r(L,"class","flex"),r(I,"class","my-1"),r(e,"class","cnt")},m(V,j){C(V,e,j),s(e,l),s(e,n),s(e,i),se(o,i,null),s(e,u),s(e,a),s(e,c),s(e,f),s(f,p),s(p,_),s(p,h),s(p,d),s(p,v),ne(v,t[3].o.e),s(f,g),s(f,E),s(E,$),s(E,M),s(E,P),s(E,F),ne(F,t[3].o.c),s(e,A),s(e,I),s(I,D),s(I,L),s(L,ie),ne(ie,t[3].o.u1),s(L,H),s(L,K),ne(K,t[3].o.u2),s(L,G),s(L,Y),ne(Y,t[3].o.u3),Q=!0,z||(Z=[le(v,"input",t[65]),le(F,"input",t[66]),le(ie,"input",t[67]),le(K,"input",t[68]),le(Y,"input",t[69])],z=!0)},p(V,j){j[0]&8&&v.value!==V[3].o.e&&ne(v,V[3].o.e),j[0]&8&&F.value!==V[3].o.c&&ne(F,V[3].o.c),j[0]&8&&ie.value!==V[3].o.u1&&ne(ie,V[3].o.u1),j[0]&8&&K.value!==V[3].o.u2&&ne(K,V[3].o.u2),j[0]&8&&Y.value!==V[3].o.u3&&ne(Y,V[3].o.u3)},i(V){Q||(O(o.$$.fragment,V),Q=!0)},o(V){B(o.$$.fragment,V),Q=!1},d(V){V&&w(e),oe(o),z=!1,Ge(Z)}}}function _f(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y;return o=new Bt({}),{c(){e=m("div"),l=m("strong"),l.textContent="Home-Assistant",n=b(),i=m("a"),re(o.$$.fragment),u=b(),a=m("input"),c=b(),f=m("div"),p=T("Discovery topic prefix"),_=m("br"),h=b(),d=m("input"),v=b(),g=m("div"),E=T("Hostname for URL"),$=m("br"),M=b(),P=m("input"),A=b(),I=m("div"),D=T("Name tag"),L=m("br"),ie=b(),H=m("input"),r(l,"class","text-sm"),r(i,"href",Ut("MQTT-configuration#home-assistant")),r(i,"target","_blank"),r(i,"class","float-right"),r(a,"type","hidden"),r(a,"name","h"),a.value="true",r(d,"name","ht"),r(d,"type","text"),r(d,"class","in-s"),r(d,"placeholder","homeassistant"),r(f,"class","my-1"),r(P,"name","hh"),r(P,"type","text"),r(P,"class","in-s"),r(P,"placeholder",F=t[3].g.h+".local"),r(g,"class","my-1"),r(H,"name","hn"),r(H,"type","text"),r(H,"class","in-s"),r(I,"class","my-1"),r(e,"class","cnt")},m(Q,z){C(Q,e,z),s(e,l),s(e,n),s(e,i),se(o,i,null),s(e,u),s(e,a),s(e,c),s(e,f),s(f,p),s(f,_),s(f,h),s(f,d),ne(d,t[3].h.t),s(e,v),s(e,g),s(g,E),s(g,$),s(g,M),s(g,P),ne(P,t[3].h.h),s(e,A),s(e,I),s(I,D),s(I,L),s(I,ie),s(I,H),ne(H,t[3].h.n),K=!0,G||(Y=[le(d,"input",t[70]),le(P,"input",t[71]),le(H,"input",t[72])],G=!0)},p(Q,z){z[0]&8&&d.value!==Q[3].h.t&&ne(d,Q[3].h.t),(!K||z[0]&8&&F!==(F=Q[3].g.h+".local"))&&r(P,"placeholder",F),z[0]&8&&P.value!==Q[3].h.h&&ne(P,Q[3].h.h),z[0]&8&&H.value!==Q[3].h.n&&ne(H,Q[3].h.n)},i(Q){K||(O(o.$$.fragment,Q),K=!0)},o(Q){B(o.$$.fragment,Q),K=!1},d(Q){Q&&w(e),oe(o),G=!1,Ge(Y)}}}function df(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue;o=new Bt({});let x=t[3].c.es&&vf(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Cloud connections",n=b(),i=m("a"),re(o.$$.fragment),u=b(),a=m("input"),c=b(),f=m("div"),p=m("label"),_=m("input"),h=T(" Enable cloud upload"),d=b(),v=m("div"),g=T("Client ID"),E=m("br"),$=b(),M=m("input"),A=b(),I=m("div"),D=T("Client secret"),L=m("br"),ie=b(),H=m("input"),G=b(),Y=m("div"),Q=m("label"),z=m("input"),Z=T(" Energy Speedometer"),V=b(),x&&x.c(),r(l,"class","text-sm"),r(i,"href",Ut("Cloud")),r(i,"target","_blank"),r(i,"class","float-right"),r(a,"type","hidden"),r(a,"name","c"),a.value="true",r(_,"type","checkbox"),r(_,"name","ce"),_.__value="true",_.value=_.__value,r(_,"class","rounded mb-1"),r(f,"class","my-1"),r(M,"name","ci"),r(M,"type","text"),r(M,"class","in-s"),r(M,"pattern",P=t[3].c.e?"[A-Z0-9]{16}":".*"),M.required=F=t[3].c.e,r(v,"class","my-1"),r(H,"name","cs"),r(H,"type","text"),r(H,"class","in-s"),r(H,"pattern",K=t[3].c.e&&t[3].c.s!="***"?"[A-Z0-9]{16}":".*"),r(I,"class","my-1"),r(z,"type","checkbox"),r(z,"class","rounded mb-1"),r(z,"name","ces"),z.__value="true",z.value=z.__value,r(Y,"class","my-1"),r(e,"class","cnt")},m(W,U){C(W,e,U),s(e,l),s(e,n),s(e,i),se(o,i,null),s(e,u),s(e,a),s(e,c),s(e,f),s(f,p),s(p,_),_.checked=t[3].c.e,s(p,h),s(e,d),s(e,v),s(v,g),s(v,E),s(v,$),s(v,M),ne(M,t[3].c.i),s(e,A),s(e,I),s(I,D),s(I,L),s(I,ie),s(I,H),ne(H,t[3].c.s),s(e,G),s(e,Y),s(Y,Q),s(Q,z),z.checked=t[3].c.es,s(Q,Z),s(Y,V),x&&x.m(Y,null),j=!0,ee||(ue=[le(_,"change",t[73]),le(M,"input",t[74]),le(H,"input",t[75]),le(z,"change",t[76])],ee=!0)},p(W,U){U[0]&8&&(_.checked=W[3].c.e),(!j||U[0]&8&&P!==(P=W[3].c.e?"[A-Z0-9]{16}":".*"))&&r(M,"pattern",P),(!j||U[0]&8&&F!==(F=W[3].c.e))&&(M.required=F),U[0]&8&&M.value!==W[3].c.i&&ne(M,W[3].c.i),(!j||U[0]&8&&K!==(K=W[3].c.e&&W[3].c.s!="***"?"[A-Z0-9]{16}":".*"))&&r(H,"pattern",K),U[0]&8&&H.value!==W[3].c.s&&ne(H,W[3].c.s),U[0]&8&&(z.checked=W[3].c.es),W[3].c.es?x?(x.p(W,U),U[0]&8&&O(x,1)):(x=vf(W),x.c(),O(x,1),x.m(Y,null)):x&&(Ie(),B(x,1,1,()=>{x=null}),Oe())},i(W){j||(O(o.$$.fragment,W),O(x),j=!0)},o(W){B(o.$$.fragment,W),B(x),j=!1},d(W){W&&w(e),oe(o),x&&x.d(),ee=!1,Ge(ue)}}}function vf(t){let e,l,n=t[0].mac+"",i,o,u,a,c=(t[0].meter.id?t[0].meter.id:"missing, required")+"",f,p,_,h,d=t[0].mac&&t[0].meter.id&&hf(t);return{c(){e=m("div"),l=T("MAC: "),i=T(n),o=b(),u=m("div"),a=T("Meter ID: "),f=T(c),p=b(),d&&d.c(),_=Ve(),r(e,"class","pl-5"),r(u,"class","pl-5")},m(v,g){C(v,e,g),s(e,l),s(e,i),C(v,o,g),C(v,u,g),s(u,a),s(u,f),C(v,p,g),d&&d.m(v,g),C(v,_,g),h=!0},p(v,g){(!h||g[0]&1)&&n!==(n=v[0].mac+"")&&X(i,n),(!h||g[0]&1)&&c!==(c=(v[0].meter.id?v[0].meter.id:"missing, required")+"")&&X(f,c),v[0].mac&&v[0].meter.id?d?(d.p(v,g),g[0]&1&&O(d,1)):(d=hf(v),d.c(),O(d,1),d.m(_.parentNode,_)):d&&(Ie(),B(d,1,1,()=>{d=null}),Oe())},i(v){h||(O(d),h=!0)},o(v){B(d),h=!1},d(v){v&&w(e),v&&w(o),v&&w(u),v&&w(p),d&&d.d(v),v&&w(_)}}}function hf(t){let e,l,n;return l=new fp({props:{value:'{"mac":"'+t[0].mac+'","meter":"'+t[0].meter.id+'"}'}}),{c(){e=m("div"),re(l.$$.fragment),r(e,"class","pl-2")},m(i,o){C(i,e,o),se(l,e,null),n=!0},p(i,o){const u={};o[0]&1&&(u.value='{"mac":"'+i[0].mac+'","meter":"'+i[0].meter.id+'"}'),l.$set(u)},i(i){n||(O(l.$$.fragment,i),n=!0)},o(i){B(l.$$.fragment,i),n=!1},d(i){i&&w(e),oe(l)}}}function bf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P;o=new Bt({});let F={length:9},A=[];for(let I=0;I20&&yf(t),_=t[3].i.d.d>0&&Sf(t),h=t[0].chip=="esp8266"&&Tf(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Hardware",n=b(),i=m("a"),re(o.$$.fragment),u=b(),p&&p.c(),a=b(),_&&_.c(),c=b(),h&&h.c(),r(l,"class","text-sm"),r(i,"href",Ut("GPIO-configuration")),r(i,"target","_blank"),r(i,"class","float-right"),r(e,"class","cnt")},m(d,v){C(d,e,v),s(e,l),s(e,n),s(e,i),se(o,i,null),s(e,u),p&&p.m(e,null),s(e,a),_&&_.m(e,null),s(e,c),h&&h.m(e,null),f=!0},p(d,v){d[0].board>20?p?(p.p(d,v),v[0]&1&&O(p,1)):(p=yf(d),p.c(),O(p,1),p.m(e,a)):p&&(Ie(),B(p,1,1,()=>{p=null}),Oe()),d[3].i.d.d>0?_?_.p(d,v):(_=Sf(d),_.c(),_.m(e,c)):_&&(_.d(1),_=null),d[0].chip=="esp8266"?h?h.p(d,v):(h=Tf(d),h.c(),h.m(e,null)):h&&(h.d(1),h=null)},i(d){f||(O(o.$$.fragment,d),O(p),f=!0)},o(d){B(o.$$.fragment,d),B(p),f=!1},d(d){d&&w(e),oe(o),p&&p.d(),_&&_.d(),h&&h.d()}}}function yf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue,x,W,U,ke,He,Be,We,Ne,ge,Re,Me,S,k,y,N,R,J,te,fe,de,we,Ae,ae,Ce,Je,At,st,ht,lt,Et,Ye,Qt,Ht,bt,ze,xe,Xe,Ue,qe,et;f=new fo({props:{chip:t[0].chip}}),E=new fo({props:{chip:t[0].chip}});let Ee=t[0].chip!="esp8266"&&Cf(t),Le=t[3].i.v.p>0&&Mf(t);return{c(){e=m("input"),l=b(),n=m("div"),i=m("div"),o=T("HAN RX"),u=m("br"),a=b(),c=m("select"),re(f.$$.fragment),p=b(),_=m("div"),h=T("HAN TX"),d=m("br"),v=b(),g=m("select"),re(E.$$.fragment),$=b(),M=m("div"),P=m("label"),F=m("input"),A=T(" pullup"),I=b(),D=m("div"),L=m("div"),ie=T("AP button"),H=m("br"),K=b(),G=m("input"),Y=b(),Q=m("div"),z=T("LED"),Z=m("br"),V=b(),j=m("div"),ee=m("input"),ue=b(),x=m("div"),W=m("label"),U=m("input"),ke=T(" inverted"),He=b(),Be=m("div"),We=T("RGB"),Ne=m("label"),ge=m("input"),Re=T(" inverted"),Me=m("br"),S=b(),k=m("div"),y=m("input"),N=b(),R=m("input"),J=b(),te=m("input"),fe=b(),de=m("div"),we=m("div"),Ae=T(`LED dis. GPIO + `),ae=m("input"),Ce=b(),Je=m("div"),At=T("Temperature"),st=m("br"),ht=b(),lt=m("input"),Et=b(),Ye=m("div"),Qt=T("Analog temp"),Ht=m("br"),bt=b(),ze=m("input"),xe=b(),Ee&&Ee.c(),Xe=b(),Le&&Le.c(),r(e,"type","hidden"),r(e,"name","i"),e.value="true",r(c,"name","ihp"),r(c,"class","in-f w-full"),t[3].i.h.p===void 0&&Ke(()=>t[80].call(c)),r(i,"class","w-1/3"),r(g,"name","iht"),r(g,"class","in-l w-full"),t[3].i.h.t===void 0&&Ke(()=>t[81].call(g)),r(_,"class","w-1/3"),r(F,"name","ihu"),F.__value="true",F.value=F.__value,r(F,"type","checkbox"),r(F,"class","rounded mb-1"),r(P,"class","ml-2"),r(M,"class","w-1/3"),r(n,"class","flex flex-wrap"),r(G,"name","ia"),r(G,"type","number"),r(G,"min","0"),r(G,"max",t[6]),r(G,"class","in-f tr w-full"),r(L,"class","w-1/3"),r(ee,"name","ilp"),r(ee,"type","number"),r(ee,"min","0"),r(ee,"max",t[6]),r(ee,"class","in-l tr w-full"),r(j,"class","flex"),r(Q,"class","w-1/3"),r(U,"name","ili"),U.__value="true",U.value=U.__value,r(U,"type","checkbox"),r(U,"class","rounded mb-1"),r(W,"class","ml-4"),r(x,"class","w-1/3"),r(ge,"name","iri"),ge.__value="true",ge.value=ge.__value,r(ge,"type","checkbox"),r(ge,"class","rounded mb-1"),r(Ne,"class","ml-4"),r(y,"name","irr"),r(y,"type","number"),r(y,"min","0"),r(y,"max",t[6]),r(y,"class","in-f tr w-1/3"),r(R,"name","irg"),r(R,"type","number"),r(R,"min","0"),r(R,"max",t[6]),r(R,"class","in-m tr w-1/3"),r(te,"name","irb"),r(te,"type","number"),r(te,"min","0"),r(te,"max",t[6]),r(te,"class","in-l tr w-1/3"),r(k,"class","flex"),r(Be,"class","w-full"),r(ae,"name","idd"),r(ae,"type","number"),r(ae,"min","0"),r(ae,"max",t[6]),r(ae,"class","in-s tr"),r(we,"class","my-1 pr-1 w-1/3"),r(de,"class","w-full"),r(lt,"name","itd"),r(lt,"type","number"),r(lt,"min","0"),r(lt,"max",t[6]),r(lt,"class","in-f tr w-full"),r(Je,"class","my-1 w-1/3"),r(ze,"name","ita"),r(ze,"type","number"),r(ze,"min","0"),r(ze,"max",t[6]),r(ze,"class","in-l tr w-full"),r(Ye,"class","my-1 pr-1 w-1/3"),r(D,"class","flex flex-wrap")},m(pe,ce){C(pe,e,ce),C(pe,l,ce),C(pe,n,ce),s(n,i),s(i,o),s(i,u),s(i,a),s(i,c),se(f,c,null),Se(c,t[3].i.h.p,!0),s(n,p),s(n,_),s(_,h),s(_,d),s(_,v),s(_,g),se(E,g,null),Se(g,t[3].i.h.t,!0),s(n,$),s(n,M),s(M,P),s(P,F),F.checked=t[3].i.h.u,s(P,A),C(pe,I,ce),C(pe,D,ce),s(D,L),s(L,ie),s(L,H),s(L,K),s(L,G),ne(G,t[3].i.a),s(D,Y),s(D,Q),s(Q,z),s(Q,Z),s(Q,V),s(Q,j),s(j,ee),ne(ee,t[3].i.l.p),s(D,ue),s(D,x),s(x,W),s(W,U),U.checked=t[3].i.l.i,s(W,ke),s(D,He),s(D,Be),s(Be,We),s(Be,Ne),s(Ne,ge),ge.checked=t[3].i.r.i,s(Ne,Re),s(Be,Me),s(Be,S),s(Be,k),s(k,y),ne(y,t[3].i.r.r),s(k,N),s(k,R),ne(R,t[3].i.r.g),s(k,J),s(k,te),ne(te,t[3].i.r.b),s(D,fe),s(D,de),s(de,we),s(we,Ae),s(we,ae),ne(ae,t[3].i.d.d),s(D,Ce),s(D,Je),s(Je,At),s(Je,st),s(Je,ht),s(Je,lt),ne(lt,t[3].i.t.d),s(D,Et),s(D,Ye),s(Ye,Qt),s(Ye,Ht),s(Ye,bt),s(Ye,ze),ne(ze,t[3].i.t.a),s(D,xe),Ee&&Ee.m(D,null),s(D,Xe),Le&&Le.m(D,null),Ue=!0,qe||(et=[le(c,"change",t[80]),le(g,"change",t[81]),le(F,"change",t[82]),le(G,"input",t[83]),le(ee,"input",t[84]),le(U,"change",t[85]),le(ge,"change",t[86]),le(y,"input",t[87]),le(R,"input",t[88]),le(te,"input",t[89]),le(ae,"input",t[90]),le(lt,"input",t[91]),le(ze,"input",t[92])],qe=!0)},p(pe,ce){const ye={};ce[0]&1&&(ye.chip=pe[0].chip),f.$set(ye),ce[0]&8&&Se(c,pe[3].i.h.p);const zl={};ce[0]&1&&(zl.chip=pe[0].chip),E.$set(zl),ce[0]&8&&Se(g,pe[3].i.h.t),ce[0]&8&&(F.checked=pe[3].i.h.u),(!Ue||ce[0]&64)&&r(G,"max",pe[6]),ce[0]&8&&he(G.value)!==pe[3].i.a&&ne(G,pe[3].i.a),(!Ue||ce[0]&64)&&r(ee,"max",pe[6]),ce[0]&8&&he(ee.value)!==pe[3].i.l.p&&ne(ee,pe[3].i.l.p),ce[0]&8&&(U.checked=pe[3].i.l.i),ce[0]&8&&(ge.checked=pe[3].i.r.i),(!Ue||ce[0]&64)&&r(y,"max",pe[6]),ce[0]&8&&he(y.value)!==pe[3].i.r.r&&ne(y,pe[3].i.r.r),(!Ue||ce[0]&64)&&r(R,"max",pe[6]),ce[0]&8&&he(R.value)!==pe[3].i.r.g&&ne(R,pe[3].i.r.g),(!Ue||ce[0]&64)&&r(te,"max",pe[6]),ce[0]&8&&he(te.value)!==pe[3].i.r.b&&ne(te,pe[3].i.r.b),(!Ue||ce[0]&64)&&r(ae,"max",pe[6]),ce[0]&8&&he(ae.value)!==pe[3].i.d.d&&ne(ae,pe[3].i.d.d),(!Ue||ce[0]&64)&&r(lt,"max",pe[6]),ce[0]&8&&he(lt.value)!==pe[3].i.t.d&&ne(lt,pe[3].i.t.d),(!Ue||ce[0]&64)&&r(ze,"max",pe[6]),ce[0]&8&&he(ze.value)!==pe[3].i.t.a&&ne(ze,pe[3].i.t.a),pe[0].chip!="esp8266"?Ee?Ee.p(pe,ce):(Ee=Cf(pe),Ee.c(),Ee.m(D,Xe)):Ee&&(Ee.d(1),Ee=null),pe[3].i.v.p>0?Le?Le.p(pe,ce):(Le=Mf(pe),Le.c(),Le.m(D,null)):Le&&(Le.d(1),Le=null)},i(pe){Ue||(O(f.$$.fragment,pe),O(E.$$.fragment,pe),Ue=!0)},o(pe){B(f.$$.fragment,pe),B(E.$$.fragment,pe),Ue=!1},d(pe){pe&&w(e),pe&&w(l),pe&&w(n),oe(f),oe(E),pe&&w(I),pe&&w(D),Ee&&Ee.d(),Le&&Le.d(),qe=!1,Ge(et)}}}function Cf(t){let e,l,n,i,o,u,a;return{c(){e=m("div"),l=T("Vcc"),n=m("br"),i=b(),o=m("input"),r(o,"name","ivp"),r(o,"type","number"),r(o,"min","0"),r(o,"max",t[6]),r(o,"class","in-s tr w-full"),r(e,"class","my-1 pl-1 w-1/3")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].i.v.p),u||(a=le(o,"input",t[93]),u=!0)},p(c,f){f[0]&64&&r(o,"max",c[6]),f[0]&8&&he(o.value)!==c[3].i.v.p&&ne(o,c[3].i.v.p)},d(c){c&&w(e),u=!1,a()}}}function Mf(t){let e,l,n,i,o,u,a,c,f,p;return{c(){e=m("div"),l=T("Voltage divider"),n=m("br"),i=b(),o=m("div"),u=m("input"),a=b(),c=m("input"),r(u,"name","ivdv"),r(u,"type","number"),r(u,"min","0"),r(u,"max","65535"),r(u,"class","in-f tr w-full"),r(u,"placeholder","VCC"),r(c,"name","ivdg"),r(c,"type","number"),r(c,"min","0"),r(c,"max","65535"),r(c,"class","in-l tr w-full"),r(c,"placeholder","GND"),r(o,"class","flex"),r(e,"class","my-1")},m(_,h){C(_,e,h),s(e,l),s(e,n),s(e,i),s(e,o),s(o,u),ne(u,t[3].i.v.d.v),s(o,a),s(o,c),ne(c,t[3].i.v.d.g),f||(p=[le(u,"input",t[94]),le(c,"input",t[95])],f=!0)},p(_,h){h[0]&8&&he(u.value)!==_[3].i.v.d.v&&ne(u,_[3].i.v.d.v),h[0]&8&&he(c.value)!==_[3].i.v.d.g&&ne(c,_[3].i.v.d.g)},d(_){_&&w(e),f=!1,Ge(p)}}}function Sf(t){let e,l,n,i,o,u,a;return{c(){e=m("div"),l=T(`LED behaviour + `),n=m("select"),i=m("option"),i.textContent="Enabled",o=m("option"),o.textContent="Disabled",i.__value=0,i.value=i.__value,o.__value=1,o.value=o.__value,r(n,"name","idb"),r(n,"class","in-s"),t[3].i.d.b===void 0&&Ke(()=>t[96].call(n)),r(e,"class","my-1 w-full")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(n,i),s(n,o),Se(n,t[3].i.d.b,!0),u||(a=le(n,"change",t[96]),u=!0)},p(c,f){f[0]&8&&Se(n,c[3].i.d.b)},d(c){c&&w(e),u=!1,a()}}}function Tf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M=(t[0].board==2||t[0].board==100)&&$f(t);return{c(){e=m("input"),l=b(),n=m("div"),i=m("div"),o=T("Vcc offset"),u=m("br"),a=b(),c=m("input"),f=b(),p=m("div"),_=T("Multiplier"),h=m("br"),d=b(),v=m("input"),g=b(),M&&M.c(),r(e,"type","hidden"),r(e,"name","iv"),e.value="true",r(c,"name","ivo"),r(c,"type","number"),r(c,"min","0.0"),r(c,"max","3.5"),r(c,"step","0.01"),r(c,"class","in-f tr w-full"),r(i,"class","w-1/3"),r(v,"name","ivm"),r(v,"type","number"),r(v,"min","0.1"),r(v,"max","10"),r(v,"step","0.01"),r(v,"class","in-l tr w-full"),r(p,"class","w-1/3 pr-1"),r(n,"class","my-1 flex flex-wrap")},m(P,F){C(P,e,F),C(P,l,F),C(P,n,F),s(n,i),s(i,o),s(i,u),s(i,a),s(i,c),ne(c,t[3].i.v.o),s(n,f),s(n,p),s(p,_),s(p,h),s(p,d),s(p,v),ne(v,t[3].i.v.m),s(n,g),M&&M.m(n,null),E||($=[le(c,"input",t[97]),le(v,"input",t[98])],E=!0)},p(P,F){F[0]&8&&he(c.value)!==P[3].i.v.o&&ne(c,P[3].i.v.o),F[0]&8&&he(v.value)!==P[3].i.v.m&&ne(v,P[3].i.v.m),P[0].board==2||P[0].board==100?M?M.p(P,F):(M=$f(P),M.c(),M.m(n,null)):M&&(M.d(1),M=null)},d(P){P&&w(e),P&&w(l),P&&w(n),M&&M.d(),E=!1,Ge($)}}}function $f(t){let e,l,n,i,o,u,a;return{c(){e=m("div"),l=T("Boot limit"),n=m("br"),i=b(),o=m("input"),r(o,"name","ivb"),r(o,"type","number"),r(o,"min","2.5"),r(o,"max","3.5"),r(o,"step","0.1"),r(o,"class","in-s tr w-full"),r(e,"class","w-1/3 pl-1")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),ne(o,t[3].i.v.b),u||(a=le(o,"input",t[99]),u=!0)},p(c,f){f[0]&8&&he(o.value)!==c[3].i.v.b&&ne(o,c[3].i.v.b)},d(c){c&&w(e),u=!1,a()}}}function Nf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$=t[3].d.t&&Af();return{c(){e=m("div"),e.textContent="Debug can cause sudden reboots. Do not leave on!",l=b(),n=m("div"),i=m("label"),o=m("input"),u=T(" Enable telnet"),a=b(),$&&$.c(),c=b(),f=m("div"),p=m("select"),_=m("option"),_.textContent="Verbose",h=m("option"),h.textContent="Debug",d=m("option"),d.textContent="Info",v=m("option"),v.textContent="Warning",r(e,"class","bd-red"),r(o,"type","checkbox"),r(o,"name","dt"),o.__value="true",o.value=o.__value,r(o,"class","rounded mb-1"),r(n,"class","my-1"),_.__value=1,_.value=_.__value,h.__value=2,h.value=h.__value,d.__value=3,d.value=d.__value,v.__value=4,v.value=v.__value,r(p,"name","dl"),r(p,"class","in-s"),t[3].d.l===void 0&&Ke(()=>t[102].call(p)),r(f,"class","my-1")},m(M,P){C(M,e,P),C(M,l,P),C(M,n,P),s(n,i),s(i,o),o.checked=t[3].d.t,s(i,u),C(M,a,P),$&&$.m(M,P),C(M,c,P),C(M,f,P),s(f,p),s(p,_),s(p,h),s(p,d),s(p,v),Se(p,t[3].d.l,!0),g||(E=[le(o,"change",t[101]),le(p,"change",t[102])],g=!0)},p(M,P){P[0]&8&&(o.checked=M[3].d.t),M[3].d.t?$||($=Af(),$.c(),$.m(c.parentNode,c)):$&&($.d(1),$=null),P[0]&8&&Se(p,M[3].d.l)},d(M){M&&w(e),M&&w(l),M&&w(n),M&&w(a),$&&$.d(M),M&&w(c),M&&w(f),g=!1,Ge(E)}}}function Af(t){let e;return{c(){e=m("div"),e.textContent="Telnet is unsafe and should be off when not in use",r(e,"class","bd-red")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function $p(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue,x,W,U,ke,He,Be,We,Ne,ge,Re,Me,S,k,y,N,R,J,te,fe,de,we,Ae,ae,Ce,Je,At,st,ht,lt,Et,Ye,Qt,Ht,bt,ze,xe,Xe,Ue,qe,et,Ee,Le,pe,ce,ye,zl,hl,_n,Pt,Ei,Pi,Di,bl,Ii,Oi,Ri,Dt,Nl,Al,El,Li,Fi,je,dn,qi,Pl,Dl,Bi,Gl,Ze,mt,Vl,Il,Ui,Ol,ji,Wt,vn,hn,Ao,rl,Hi,Eo,Ts,Po,fi,Xt,Do,Io,Rl,al,Ll,Oo,Wi,Ro,dt,Fl,Lo,zi,bn,gn,kn,wn,Gi,Fo,It,Vi,qo,Kl,Bo,Uo,jo,ul,yn,Cn,Ho,Mn,Yl,Wo,zo,Go,Sn,Zt,Vo,Ki,Ko,Ql,Yo,Qo,Xo,Tn,Jt,Zo,Yi,Jo,$s,xo,Xl,Qi,xt,er,tr,lr,Ns,Xi,el,nr,ir,sr,Ot,Zi,or,$n,Nn,rr,ci,ar,Zl,ur,fr,cr,zt,An,En,mr,pr,pt,Ji,_r,Pn,Dn,dr,Jl,vr,hr,br,ql,fl,In,On,gr,Rt,xi,es,kr,Lt,Rn,ts,ls,wr,As,ns,is,tl,yr,Cr,mi,Mr,Bl,Sr,pi,ll,Tr,$r,Nr,ss,gl,Ar,tt,os,Er,Ln,Fn,Pr,_i,Dr,cl,Ir,Es,Or,Rr,qn,kl,Lr,nl,Fr,Ps,xl,qr,Br,Ur,wl,jr,en,Hr,Wr,zr,yl,Gr,Bn,Un,Vr,Kr,Yr,Cl,Qr,jn,Xr,Zr,Jr,gt,Hn,Wn,zn,Gn,Vn,Kn,xr,tn,ea,ta,la,Ml,na,Ds,Is,Os,Rs=t[3].p.r.startsWith("10YNO")||t[3].p.r=="10Y1001A1001A48H",Ls,ml,rs,ia,Yn,Qn,sa,di,oa,vi,ra,Fs,Ft,as,aa,Xn,Zn,ua,hi,fa,us,fs,il,ca,ma,pa,Ul,qs,Jn,_a,cs,xn,da,ms,Bs,ln,Us,nn,js,sn,Hs,on,Gt,Ws,va;a=new Bt({}),L=new tp({});let xc=["NOK","SEK","DKK","EUR"],bi=[];for(let q=0;q<4;q+=1)bi[q]=pp(mp(t,xc,q));let kt=t[3].p.e&&t[0].chip!="esp8266"&&lf(t),wt=t[3].g.s>0&&nf(t);Dl=new Bt({});let e0=[24,48,96,192,384,576,1152],gi=[];for(let q=0;q<7;q+=1)gi[q]=_p(cp(t,e0,q));let yt=t[3].m.e.e&&sf(t),Ct=t[3].m.e.e&&of(t),Mt=t[3].m.m.e&&rf(t);Nn=new Bt({});let qt=t[0].if&&t[0].if.eth&&af(),St=(t[3].n.c==1||t[3].n.c==2)&&uf(t);Dn=new Bt({}),Rn=new Zc({});let Tt=t[3].n.m=="static"&&ff(t);Fn=new Bt({});let $t=t[0].chip!="esp8266"&&cf(t),ot=t[3].q.s.e&&mf(t),rt=t[3].q.m==3&&pf(t),at=t[3].q.m==4&&_f(t),ut=t[3].c.es!=null&&df(t),ft=Rs&&bf(t);Qn=new Bt({});let ei=t[7],vt=[];for(let q=0;q20||t[0].chip=="esp8266"||t[3].i.d.d>0)&&wf(t);Zn=new Bt({});let Nt=t[3].d.s&&Nf(t);return ln=new jt({props:{active:t[1],message:"Loading configuration"}}),nn=new jt({props:{active:t[2],message:"Saving configuration"}}),sn=new jt({props:{active:t[4],message:"Performing factory reset"}}),on=new jt({props:{active:t[5],message:"Device have been factory reset and switched to AP mode"}}),{c(){e=m("form"),l=m("div"),n=m("div"),i=m("strong"),i.textContent="General",o=b(),u=m("a"),re(a.$$.fragment),c=b(),f=m("input"),p=b(),_=m("div"),h=m("div"),d=m("div"),v=T("Hostname"),g=m("br"),E=b(),$=m("input"),M=b(),P=m("div"),F=T("Time zone"),A=m("br"),I=b(),D=m("select"),re(L.$$.fragment),ie=b(),H=m("input"),K=b(),G=m("div"),Y=m("div"),Q=m("div"),z=T("Price region"),Z=m("br"),V=b(),j=m("select"),ee=m("optgroup"),ue=m("option"),ue.textContent="NO1",x=m("option"),x.textContent="NO2",W=m("option"),W.textContent="NO3",U=m("option"),U.textContent="NO4",ke=m("option"),ke.textContent="NO5",He=m("optgroup"),Be=m("option"),Be.textContent="SE1",We=m("option"),We.textContent="SE2",Ne=m("option"),Ne.textContent="SE3",ge=m("option"),ge.textContent="SE4",Re=m("optgroup"),Me=m("option"),Me.textContent="DK1",S=m("option"),S.textContent="DK2",k=m("option"),k.textContent="Austria",y=m("option"),y.textContent="Belgium",N=m("option"),N.textContent="Czech Republic",R=m("option"),R.textContent="Estonia",J=m("option"),J.textContent="Finland",te=m("option"),te.textContent="France",fe=m("option"),fe.textContent="Germany",de=m("option"),de.textContent="Great Britain",we=m("option"),we.textContent="Latvia",Ae=m("option"),Ae.textContent="Lithuania",ae=m("option"),ae.textContent="Netherland",Ce=m("option"),Ce.textContent="Poland",Je=m("option"),Je.textContent="Switzerland",At=b(),st=m("div"),ht=T("Currency"),lt=m("br"),Et=b(),Ye=m("select");for(let q=0;q<4;q+=1)bi[q].c();Qt=b(),Ht=m("div"),bt=m("div"),ze=m("div"),xe=T("Fixed price"),Xe=m("br"),Ue=b(),qe=m("input"),et=b(),Ee=m("div"),Le=T("Multiplier"),pe=m("br"),ce=b(),ye=m("input"),zl=b(),hl=m("div"),_n=m("label"),Pt=m("input"),Ei=T(" Enable price fetch from remote server"),Pi=b(),kt&&kt.c(),Di=b(),bl=m("div"),Ii=T("Security"),Oi=m("br"),Ri=b(),Dt=m("select"),Nl=m("option"),Nl.textContent="None",Al=m("option"),Al.textContent="Only configuration",El=m("option"),El.textContent="Everything",Li=b(),wt&&wt.c(),Fi=b(),je=m("div"),dn=m("strong"),dn.textContent="Meter",qi=b(),Pl=m("a"),re(Dl.$$.fragment),Bi=b(),Gl=m("input"),Ze=b(),mt=m("input"),Vl=b(),Il=m("div"),Ui=T("Communication"),Ol=m("br"),ji=b(),Wt=m("select"),vn=m("option"),vn.textContent="Passive (Push)",hn=m("option"),hn.textContent="Kamstrup (Pull)",Ao=b(),rl=m("div"),Hi=m("span"),Hi.textContent="Buffer size",Eo=b(),Ts=m("span"),Ts.textContent="Serial conf.",Po=b(),fi=m("label"),Xt=m("input"),Do=T(" inverted"),Io=b(),Rl=m("div"),al=m("select"),Ll=m("option"),Oo=T("Autodetect");for(let q=0;q<7;q+=1)gi[q].c();Ro=b(),dt=m("select"),Fl=m("option"),Lo=T("-"),bn=m("option"),bn.textContent="7N1",gn=m("option"),gn.textContent="8N1",kn=m("option"),kn.textContent="7E1",wn=m("option"),wn.textContent="8E1",Fo=b(),It=m("input"),qo=b(),Kl=m("div"),Bo=T("Voltage"),Uo=m("br"),jo=b(),ul=m("select"),yn=m("option"),yn.textContent="400V (TN)",Cn=m("option"),Cn.textContent="230V (IT/TT)",Ho=b(),Mn=m("div"),Yl=m("div"),Wo=T("Main fuse"),zo=m("br"),Go=b(),Sn=m("label"),Zt=m("input"),Vo=b(),Ki=m("span"),Ki.textContent="A",Ko=b(),Ql=m("div"),Yo=T("Production"),Qo=m("br"),Xo=b(),Tn=m("label"),Jt=m("input"),Zo=b(),Yi=m("span"),Yi.textContent="kWp",Jo=b(),$s=m("div"),xo=b(),Xl=m("div"),Qi=m("label"),xt=m("input"),er=T(" Meter is encrypted"),tr=b(),yt&&yt.c(),lr=b(),Ct&&Ct.c(),Ns=b(),Xi=m("label"),el=m("input"),nr=T(" Multipliers"),ir=b(),Mt&&Mt.c(),sr=b(),Ot=m("div"),Zi=m("strong"),Zi.textContent="Connection",or=b(),$n=m("a"),re(Nn.$$.fragment),rr=b(),ci=m("input"),ar=b(),Zl=m("div"),ur=T("Connection"),fr=m("br"),cr=b(),zt=m("select"),An=m("option"),An.textContent="WiFi",En=m("option"),En.textContent="Access point",qt&&qt.c(),mr=b(),St&&St.c(),pr=b(),pt=m("div"),Ji=m("strong"),Ji.textContent="Network",_r=b(),Pn=m("a"),re(Dn.$$.fragment),dr=b(),Jl=m("div"),vr=T("IP"),hr=m("br"),br=b(),ql=m("div"),fl=m("select"),In=m("option"),In.textContent="DHCP",On=m("option"),On.textContent="Static",gr=b(),Rt=m("input"),kr=b(),Lt=m("select"),re(Rn.$$.fragment),wr=b(),Tt&&Tt.c(),As=b(),ns=m("div"),is=m("label"),tl=m("input"),yr=T(" enable mDNS"),Cr=b(),mi=m("input"),Mr=b(),Bl=m("div"),Sr=T("NTP "),pi=m("label"),ll=m("input"),Tr=T(" obtain from DHCP"),$r=m("br"),Nr=b(),ss=m("div"),gl=m("input"),Ar=b(),tt=m("div"),os=m("strong"),os.textContent="MQTT",Er=b(),Ln=m("a"),re(Fn.$$.fragment),Pr=b(),_i=m("input"),Dr=b(),cl=m("div"),Ir=T(`Server + `),$t&&$t.c(),Es=b(),Or=m("br"),Rr=b(),qn=m("div"),kl=m("input"),Lr=b(),nl=m("input"),Fr=b(),ot&&ot.c(),Ps=b(),xl=m("div"),qr=T("Username"),Br=m("br"),Ur=b(),wl=m("input"),jr=b(),en=m("div"),Hr=T("Password"),Wr=m("br"),zr=b(),yl=m("input"),Gr=b(),Bn=m("div"),Un=m("div"),Vr=T("Client ID"),Kr=m("br"),Yr=b(),Cl=m("input"),Qr=b(),jn=m("div"),Xr=T("Payload"),Zr=m("br"),Jr=b(),gt=m("select"),Hn=m("option"),Hn.textContent="JSON",Wn=m("option"),Wn.textContent="Raw (minimal)",zn=m("option"),zn.textContent="Raw (full)",Gn=m("option"),Gn.textContent="Domoticz",Vn=m("option"),Vn.textContent="HomeAssistant",Kn=m("option"),Kn.textContent="HEX dump",xr=b(),tn=m("div"),ea=T("Publish topic"),ta=m("br"),la=b(),Ml=m("input"),na=b(),rt&&rt.c(),Ds=b(),at&&at.c(),Is=b(),ut&&ut.c(),Os=b(),ft&&ft.c(),Ls=b(),ml=m("div"),rs=m("strong"),rs.textContent="User interface",ia=b(),Yn=m("a"),re(Qn.$$.fragment),sa=b(),di=m("input"),oa=b(),vi=m("div");for(let q=0;qSave',Bs=b(),re(ln.$$.fragment),Us=b(),re(nn.$$.fragment),js=b(),re(sn.$$.fragment),Hs=b(),re(on.$$.fragment),r(i,"class","text-sm"),r(u,"href",Ut("General-configuration")),r(u,"target","_blank"),r(u,"class","float-right"),r(f,"type","hidden"),r(f,"name","g"),f.value="true",r($,"name","gh"),r($,"type","text"),r($,"class","in-f w-full"),r($,"pattern","[A-Za-z0-9-]+"),r(D,"name","gt"),r(D,"class","in-l w-full"),t[3].g.t===void 0&&Ke(()=>t[16].call(D)),r(h,"class","flex"),r(_,"class","my-1"),r(H,"type","hidden"),r(H,"name","p"),H.value="true",ue.__value="10YNO-1--------2",ue.value=ue.__value,x.__value="10YNO-2--------T",x.value=x.__value,W.__value="10YNO-3--------J",W.value=W.__value,U.__value="10YNO-4--------9",U.value=U.__value,ke.__value="10Y1001A1001A48H",ke.value=ke.__value,r(ee,"label","Norway"),Be.__value="10Y1001A1001A44P",Be.value=Be.__value,We.__value="10Y1001A1001A45N",We.value=We.__value,Ne.__value="10Y1001A1001A46L",Ne.value=Ne.__value,ge.__value="10Y1001A1001A47J",ge.value=ge.__value,r(He,"label","Sweden"),Me.__value="10YDK-1--------W",Me.value=Me.__value,S.__value="10YDK-2--------M",S.value=S.__value,r(Re,"label","Denmark"),k.__value="10YAT-APG------L",k.value=k.__value,y.__value="10YBE----------2",y.value=y.__value,N.__value="10YCZ-CEPS-----N",N.value=N.__value,R.__value="10Y1001A1001A39I",R.value=R.__value,J.__value="10YFI-1--------U",J.value=J.__value,te.__value="10YFR-RTE------C",te.value=te.__value,fe.__value="10Y1001A1001A83F",fe.value=fe.__value,de.__value="10YGB----------A",de.value=de.__value,we.__value="10YLV-1001A00074",we.value=we.__value,Ae.__value="10YLT-1001A0008Q",Ae.value=Ae.__value,ae.__value="10YNL----------L",ae.value=ae.__value,Ce.__value="10YPL-AREA-----S",Ce.value=Ce.__value,Je.__value="10YCH-SWISSGRIDZ",Je.value=Je.__value,r(j,"name","pr"),r(j,"class","in-f w-full"),t[3].p.r===void 0&&Ke(()=>t[17].call(j)),r(Q,"class","w-full"),r(Ye,"name","pc"),r(Ye,"class","in-l"),t[3].p.c===void 0&&Ke(()=>t[18].call(Ye)),r(Y,"class","flex"),r(G,"class","my-1"),r(qe,"name","pf"),r(qe,"type","number"),r(qe,"min","0.001"),r(qe,"max","65"),r(qe,"step","0.001"),r(qe,"class","in-f tr w-full"),r(ze,"class","w-1/2"),r(ye,"name","pm"),r(ye,"type","number"),r(ye,"min","0.001"),r(ye,"max","1000"),r(ye,"step","0.001"),r(ye,"class","in-l tr w-full"),r(Ee,"class","w-1/2"),r(bt,"class","flex"),r(Ht,"class","my-1"),r(Pt,"type","checkbox"),r(Pt,"name","pe"),Pt.__value="true",Pt.value=Pt.__value,r(Pt,"class","rounded mb-1"),r(hl,"class","my-1"),Nl.__value=0,Nl.value=Nl.__value,Al.__value=1,Al.value=Al.__value,El.__value=2,El.value=El.__value,r(Dt,"name","gs"),r(Dt,"class","in-s"),t[3].g.s===void 0&&Ke(()=>t[23].call(Dt)),r(bl,"class","my-1"),r(n,"class","cnt"),r(dn,"class","text-sm"),r(Pl,"href",Ut("Meter-configuration")),r(Pl,"target","_blank"),r(Pl,"class","float-right"),r(Gl,"type","hidden"),r(Gl,"name","m"),Gl.value="true",r(mt,"type","hidden"),r(mt,"name","mo"),mt.value="1",vn.__value=0,vn.value=vn.__value,hn.__value=9,hn.value=hn.__value,r(Wt,"name","ma"),r(Wt,"class","in-s"),t[3].m.a===void 0&&Ke(()=>t[26].call(Wt)),r(Il,"class","my-1"),r(Hi,"class","float-right"),r(Xt,"name","mi"),Xt.__value="true",Xt.value=Xt.__value,r(Xt,"type","checkbox"),r(Xt,"class","rounded mb-1"),r(fi,"class","mt-2 ml-3 whitespace-nowrap"),Ll.__value=0,Ll.value=Ll.__value,Ll.disabled=Wi=t[3].m.b!=0,r(al,"name","mb"),r(al,"class","in-f tr w-1/2"),t[3].m.b===void 0&&Ke(()=>t[28].call(al)),Fl.__value=0,Fl.value=Fl.__value,Fl.disabled=zi=t[3].m.b!=0,bn.__value=2,bn.value=bn.__value,gn.__value=3,gn.value=gn.__value,kn.__value=10,kn.value=kn.__value,wn.__value=11,wn.value=wn.__value,r(dt,"name","mp"),r(dt,"class","in-m"),dt.disabled=Gi=t[3].m.b==0,t[3].m.p===void 0&&Ke(()=>t[29].call(dt)),r(It,"name","ms"),r(It,"type","number"),r(It,"min",64),r(It,"max",Vi=t[0].chip=="esp8266"?t[3].i.h.p==3||t[3].i.h.p==113?512:128:4096),r(It,"step",64),r(It,"class","in-l tr w-1/2"),r(Rl,"class","flex w-full"),r(rl,"class","my-1"),yn.__value=2,yn.value=yn.__value,Cn.__value=1,Cn.value=Cn.__value,r(ul,"name","md"),r(ul,"class","in-s"),t[3].m.d===void 0&&Ke(()=>t[31].call(ul)),r(Kl,"class","my-1"),r(Zt,"name","mf"),r(Zt,"type","number"),r(Zt,"min","5"),r(Zt,"max","65535"),r(Zt,"class","in-f tr w-full"),r(Ki,"class","in-post"),r(Sn,"class","flex"),r(Yl,"class","mx-1"),r(Jt,"name","mr"),r(Jt,"type","number"),r(Jt,"min","0"),r(Jt,"max","65535"),r(Jt,"class","in-f tr w-full"),r(Yi,"class","in-post"),r(Tn,"class","flex"),r(Ql,"class","mx-1"),r(Mn,"class","my-1 flex"),r($s,"class","my-1"),r(xt,"type","checkbox"),r(xt,"name","me"),xt.__value="true",xt.value=xt.__value,r(xt,"class","rounded mb-1"),r(Xl,"class","my-1"),r(el,"type","checkbox"),r(el,"name","mm"),el.__value="true",el.value=el.__value,r(el,"class","rounded mb-1"),r(je,"class","cnt"),r(Zi,"class","text-sm"),r($n,"href",Ut("WiFi-configuration")),r($n,"target","_blank"),r($n,"class","float-right"),r(ci,"type","hidden"),r(ci,"name","w"),ci.value="true",An.__value=1,An.value=An.__value,En.__value=2,En.value=En.__value,r(zt,"name","nc"),r(zt,"class","in-s"),t[3].n.c===void 0&&Ke(()=>t[42].call(zt)),r(Zl,"class","my-1"),r(Ot,"class","cnt"),r(Ji,"class","text-sm"),r(Pn,"href",Ut("Network-configuration")),r(Pn,"target","_blank"),r(Pn,"class","float-right"),In.__value="dhcp",In.value=In.__value,On.__value="static",On.value=On.__value,r(fl,"name","nm"),r(fl,"class","in-f"),t[3].n.m===void 0&&Ke(()=>t[48].call(fl)),r(Rt,"name","ni"),r(Rt,"type","text"),r(Rt,"class","in-m w-full"),Rt.disabled=xi=t[3].n.m=="dhcp",Rt.required=es=t[3].n.m=="static",r(Lt,"name","ns"),r(Lt,"class","in-l"),Lt.disabled=ts=t[3].n.m=="dhcp",Lt.required=ls=t[3].n.m=="static",t[3].n.s===void 0&&Ke(()=>t[50].call(Lt)),r(ql,"class","flex"),r(Jl,"class","my-1"),r(tl,"name","nd"),tl.__value="true",tl.value=tl.__value,r(tl,"type","checkbox"),r(tl,"class","rounded mb-1"),r(ns,"class","my-1"),r(mi,"type","hidden"),r(mi,"name","ntp"),mi.value="true",r(ll,"name","ntpd"),ll.__value="true",ll.value=ll.__value,r(ll,"type","checkbox"),r(ll,"class","rounded mb-1"),r(pi,"class","ml-4"),r(gl,"name","ntph"),r(gl,"type","text"),r(gl,"class","in-s"),r(ss,"class","flex"),r(Bl,"class","my-1"),r(pt,"class","cnt"),r(os,"class","text-sm"),r(Ln,"href",Ut("MQTT-configuration")),r(Ln,"target","_blank"),r(Ln,"class","float-right"),r(_i,"type","hidden"),r(_i,"name","q"),_i.value="true",r(kl,"name","qh"),r(kl,"type","text"),r(kl,"class","in-f w-3/4"),r(nl,"name","qp"),r(nl,"type","number"),r(nl,"min","1024"),r(nl,"max","65535"),r(nl,"class","in-l tr w-1/4"),r(qn,"class","flex"),r(cl,"class","my-1"),r(wl,"name","qu"),r(wl,"type","text"),r(wl,"class","in-s"),r(xl,"class","my-1"),r(yl,"name","qa"),r(yl,"type","password"),r(yl,"class","in-s"),r(en,"class","my-1"),r(Cl,"name","qc"),r(Cl,"type","text"),r(Cl,"class","in-f w-full"),Hn.__value=0,Hn.value=Hn.__value,Wn.__value=1,Wn.value=Wn.__value,zn.__value=2,zn.value=zn.__value,Gn.__value=3,Gn.value=Gn.__value,Vn.__value=4,Vn.value=Vn.__value,Kn.__value=255,Kn.value=Kn.__value,r(gt,"name","qm"),r(gt,"class","in-l"),t[3].q.m===void 0&&Ke(()=>t[63].call(gt)),r(Bn,"class","my-1 flex"),r(Ml,"name","qb"),r(Ml,"type","text"),r(Ml,"class","in-s"),r(tn,"class","my-1"),r(tt,"class","cnt"),r(rs,"class","text-sm"),r(Yn,"href",Ut("User-interface")),r(Yn,"target","_blank"),r(Yn,"class","float-right"),r(di,"type","hidden"),r(di,"name","u"),di.value="true",r(vi,"class","flex flex-wrap"),r(ml,"class","cnt"),r(as,"class","text-sm"),r(Xn,"href","https://amsleser.no/blog/post/24-telnet-debug"),r(Xn,"target","_blank"),r(Xn,"class","float-right"),r(hi,"type","hidden"),r(hi,"name","d"),hi.value="true",r(il,"type","checkbox"),r(il,"name","ds"),il.__value="true",il.value=il.__value,r(il,"class","rounded mb-1"),r(us,"class","mt-3"),r(Ft,"class","cnt"),r(l,"class","grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2"),r(Jn,"type","button"),r(Jn,"class","py-2 px-4 rounded bg-red-500 text-white ml-2"),r(xn,"type","button"),r(xn,"class","py-2 px-4 rounded bg-yellow-500 text-white"),r(cs,"class","text-center"),r(ms,"class","text-right"),r(Ul,"class","grid grid-cols-3"),r(e,"autocomplete","off")},m(q,me){C(q,e,me),s(e,l),s(l,n),s(n,i),s(n,o),s(n,u),se(a,u,null),s(n,c),s(n,f),s(n,p),s(n,_),s(_,h),s(h,d),s(d,v),s(d,g),s(d,E),s(d,$),ne($,t[3].g.h),s(h,M),s(h,P),s(P,F),s(P,A),s(P,I),s(P,D),se(L,D,null),Se(D,t[3].g.t,!0),s(n,ie),s(n,H),s(n,K),s(n,G),s(G,Y),s(Y,Q),s(Q,z),s(Q,Z),s(Q,V),s(Q,j),s(j,ee),s(ee,ue),s(ee,x),s(ee,W),s(ee,U),s(ee,ke),s(j,He),s(He,Be),s(He,We),s(He,Ne),s(He,ge),s(j,Re),s(Re,Me),s(Re,S),s(j,k),s(j,y),s(j,N),s(j,R),s(j,J),s(j,te),s(j,fe),s(j,de),s(j,we),s(j,Ae),s(j,ae),s(j,Ce),s(j,Je),Se(j,t[3].p.r,!0),s(Y,At),s(Y,st),s(st,ht),s(st,lt),s(st,Et),s(st,Ye);for(let _t=0;_t<4;_t+=1)bi[_t]&&bi[_t].m(Ye,null);Se(Ye,t[3].p.c,!0),s(n,Qt),s(n,Ht),s(Ht,bt),s(bt,ze),s(ze,xe),s(ze,Xe),s(ze,Ue),s(ze,qe),ne(qe,t[3].p.f),s(bt,et),s(bt,Ee),s(Ee,Le),s(Ee,pe),s(Ee,ce),s(Ee,ye),ne(ye,t[3].p.m),s(n,zl),s(n,hl),s(hl,_n),s(_n,Pt),Pt.checked=t[3].p.e,s(_n,Ei),s(hl,Pi),kt&&kt.m(hl,null),s(n,Di),s(n,bl),s(bl,Ii),s(bl,Oi),s(bl,Ri),s(bl,Dt),s(Dt,Nl),s(Dt,Al),s(Dt,El),Se(Dt,t[3].g.s,!0),s(n,Li),wt&&wt.m(n,null),s(l,Fi),s(l,je),s(je,dn),s(je,qi),s(je,Pl),se(Dl,Pl,null),s(je,Bi),s(je,Gl),s(je,Ze),s(je,mt),s(je,Vl),s(je,Il),s(Il,Ui),s(Il,Ol),s(Il,ji),s(Il,Wt),s(Wt,vn),s(Wt,hn),Se(Wt,t[3].m.a,!0),s(je,Ao),s(je,rl),s(rl,Hi),s(rl,Eo),s(rl,Ts),s(rl,Po),s(rl,fi),s(fi,Xt),Xt.checked=t[3].m.i,s(fi,Do),s(rl,Io),s(rl,Rl),s(Rl,al),s(al,Ll),s(Ll,Oo);for(let _t=0;_t<7;_t+=1)gi[_t]&&gi[_t].m(al,null);Se(al,t[3].m.b,!0),s(Rl,Ro),s(Rl,dt),s(dt,Fl),s(Fl,Lo),s(dt,bn),s(dt,gn),s(dt,kn),s(dt,wn),Se(dt,t[3].m.p,!0),s(Rl,Fo),s(Rl,It),ne(It,t[3].m.s),s(je,qo),s(je,Kl),s(Kl,Bo),s(Kl,Uo),s(Kl,jo),s(Kl,ul),s(ul,yn),s(ul,Cn),Se(ul,t[3].m.d,!0),s(je,Ho),s(je,Mn),s(Mn,Yl),s(Yl,Wo),s(Yl,zo),s(Yl,Go),s(Yl,Sn),s(Sn,Zt),ne(Zt,t[3].m.f),s(Sn,Vo),s(Sn,Ki),s(Mn,Ko),s(Mn,Ql),s(Ql,Yo),s(Ql,Qo),s(Ql,Xo),s(Ql,Tn),s(Tn,Jt),ne(Jt,t[3].m.r),s(Tn,Zo),s(Tn,Yi),s(je,Jo),s(je,$s),s(je,xo),s(je,Xl),s(Xl,Qi),s(Qi,xt),xt.checked=t[3].m.e.e,s(Qi,er),s(Xl,tr),yt&&yt.m(Xl,null),s(je,lr),Ct&&Ct.m(je,null),s(je,Ns),s(je,Xi),s(Xi,el),el.checked=t[3].m.m.e,s(Xi,nr),s(je,ir),Mt&&Mt.m(je,null),s(l,sr),s(l,Ot),s(Ot,Zi),s(Ot,or),s(Ot,$n),se(Nn,$n,null),s(Ot,rr),s(Ot,ci),s(Ot,ar),s(Ot,Zl),s(Zl,ur),s(Zl,fr),s(Zl,cr),s(Zl,zt),s(zt,An),s(zt,En),qt&&qt.m(zt,null),Se(zt,t[3].n.c,!0),s(Ot,mr),St&&St.m(Ot,null),s(l,pr),s(l,pt),s(pt,Ji),s(pt,_r),s(pt,Pn),se(Dn,Pn,null),s(pt,dr),s(pt,Jl),s(Jl,vr),s(Jl,hr),s(Jl,br),s(Jl,ql),s(ql,fl),s(fl,In),s(fl,On),Se(fl,t[3].n.m,!0),s(ql,gr),s(ql,Rt),ne(Rt,t[3].n.i),s(ql,kr),s(ql,Lt),se(Rn,Lt,null),Se(Lt,t[3].n.s,!0),s(pt,wr),Tt&&Tt.m(pt,null),s(pt,As),s(pt,ns),s(ns,is),s(is,tl),tl.checked=t[3].n.d,s(is,yr),s(pt,Cr),s(pt,mi),s(pt,Mr),s(pt,Bl),s(Bl,Sr),s(Bl,pi),s(pi,ll),ll.checked=t[3].n.h,s(pi,Tr),s(Bl,$r),s(Bl,Nr),s(Bl,ss),s(ss,gl),ne(gl,t[3].n.n1),s(l,Ar),s(l,tt),s(tt,os),s(tt,Er),s(tt,Ln),se(Fn,Ln,null),s(tt,Pr),s(tt,_i),s(tt,Dr),s(tt,cl),s(cl,Ir),$t&&$t.m(cl,null),s(cl,Es),s(cl,Or),s(cl,Rr),s(cl,qn),s(qn,kl),ne(kl,t[3].q.h),s(qn,Lr),s(qn,nl),ne(nl,t[3].q.p),s(tt,Fr),ot&&ot.m(tt,null),s(tt,Ps),s(tt,xl),s(xl,qr),s(xl,Br),s(xl,Ur),s(xl,wl),ne(wl,t[3].q.u),s(tt,jr),s(tt,en),s(en,Hr),s(en,Wr),s(en,zr),s(en,yl),ne(yl,t[3].q.a),s(tt,Gr),s(tt,Bn),s(Bn,Un),s(Un,Vr),s(Un,Kr),s(Un,Yr),s(Un,Cl),ne(Cl,t[3].q.c),s(Bn,Qr),s(Bn,jn),s(jn,Xr),s(jn,Zr),s(jn,Jr),s(jn,gt),s(gt,Hn),s(gt,Wn),s(gt,zn),s(gt,Gn),s(gt,Vn),s(gt,Kn),Se(gt,t[3].q.m,!0),s(tt,xr),s(tt,tn),s(tn,ea),s(tn,ta),s(tn,la),s(tn,Ml),ne(Ml,t[3].q.b),s(l,na),rt&&rt.m(l,null),s(l,Ds),at&&at.m(l,null),s(l,Is),ut&&ut.m(l,null),s(l,Os),ft&&ft.m(l,null),s(l,Ls),s(l,ml),s(ml,rs),s(ml,ia),s(ml,Yn),se(Qn,Yn,null),s(ml,sa),s(ml,di),s(ml,oa),s(ml,vi);for(let _t=0;_t0?wt?wt.p(q,me):(wt=nf(q),wt.c(),wt.m(n,null)):wt&&(wt.d(1),wt=null),me[0]&8&&Se(Wt,q[3].m.a),me[0]&8&&(Xt.checked=q[3].m.i),(!Gt||me[0]&8&&Wi!==(Wi=q[3].m.b!=0))&&(Ll.disabled=Wi),me[0]&8&&Se(al,q[3].m.b),(!Gt||me[0]&8&&zi!==(zi=q[3].m.b!=0))&&(Fl.disabled=zi),(!Gt||me[0]&8&&Gi!==(Gi=q[3].m.b==0))&&(dt.disabled=Gi),me[0]&8&&Se(dt,q[3].m.p),(!Gt||me[0]&9&&Vi!==(Vi=q[0].chip=="esp8266"?q[3].i.h.p==3||q[3].i.h.p==113?512:128:4096))&&r(It,"max",Vi),me[0]&8&&he(It.value)!==q[3].m.s&&ne(It,q[3].m.s),me[0]&8&&Se(ul,q[3].m.d),me[0]&8&&he(Zt.value)!==q[3].m.f&&ne(Zt,q[3].m.f),me[0]&8&&he(Jt.value)!==q[3].m.r&&ne(Jt,q[3].m.r),me[0]&8&&(xt.checked=q[3].m.e.e),q[3].m.e.e?yt?yt.p(q,me):(yt=sf(q),yt.c(),yt.m(Xl,null)):yt&&(yt.d(1),yt=null),q[3].m.e.e?Ct?Ct.p(q,me):(Ct=of(q),Ct.c(),Ct.m(je,Ns)):Ct&&(Ct.d(1),Ct=null),me[0]&8&&(el.checked=q[3].m.m.e),q[3].m.m.e?Mt?Mt.p(q,me):(Mt=rf(q),Mt.c(),Mt.m(je,null)):Mt&&(Mt.d(1),Mt=null),q[0].if&&q[0].if.eth?qt||(qt=af(),qt.c(),qt.m(zt,null)):qt&&(qt.d(1),qt=null),me[0]&8&&Se(zt,q[3].n.c),q[3].n.c==1||q[3].n.c==2?St?St.p(q,me):(St=uf(q),St.c(),St.m(Ot,null)):St&&(St.d(1),St=null),me[0]&8&&Se(fl,q[3].n.m),(!Gt||me[0]&8&&xi!==(xi=q[3].n.m=="dhcp"))&&(Rt.disabled=xi),(!Gt||me[0]&8&&es!==(es=q[3].n.m=="static"))&&(Rt.required=es),me[0]&8&&Rt.value!==q[3].n.i&&ne(Rt,q[3].n.i),(!Gt||me[0]&8&&ts!==(ts=q[3].n.m=="dhcp"))&&(Lt.disabled=ts),(!Gt||me[0]&8&&ls!==(ls=q[3].n.m=="static"))&&(Lt.required=ls),me[0]&8&&Se(Lt,q[3].n.s),q[3].n.m=="static"?Tt?Tt.p(q,me):(Tt=ff(q),Tt.c(),Tt.m(pt,As)):Tt&&(Tt.d(1),Tt=null),me[0]&8&&(tl.checked=q[3].n.d),me[0]&8&&(ll.checked=q[3].n.h),me[0]&8&&gl.value!==q[3].n.n1&&ne(gl,q[3].n.n1),q[0].chip!="esp8266"?$t?$t.p(q,me):($t=cf(q),$t.c(),$t.m(cl,Es)):$t&&($t.d(1),$t=null),me[0]&8&&kl.value!==q[3].q.h&&ne(kl,q[3].q.h),me[0]&8&&he(nl.value)!==q[3].q.p&&ne(nl,q[3].q.p),q[3].q.s.e?ot?(ot.p(q,me),me[0]&8&&O(ot,1)):(ot=mf(q),ot.c(),O(ot,1),ot.m(tt,Ps)):ot&&(Ie(),B(ot,1,1,()=>{ot=null}),Oe()),me[0]&8&&wl.value!==q[3].q.u&&ne(wl,q[3].q.u),me[0]&8&&yl.value!==q[3].q.a&&ne(yl,q[3].q.a),me[0]&8&&Cl.value!==q[3].q.c&&ne(Cl,q[3].q.c),me[0]&8&&Se(gt,q[3].q.m),me[0]&8&&Ml.value!==q[3].q.b&&ne(Ml,q[3].q.b),q[3].q.m==3?rt?(rt.p(q,me),me[0]&8&&O(rt,1)):(rt=pf(q),rt.c(),O(rt,1),rt.m(l,Ds)):rt&&(Ie(),B(rt,1,1,()=>{rt=null}),Oe()),q[3].q.m==4?at?(at.p(q,me),me[0]&8&&O(at,1)):(at=_f(q),at.c(),O(at,1),at.m(l,Is)):at&&(Ie(),B(at,1,1,()=>{at=null}),Oe()),q[3].c.es!=null?ut?(ut.p(q,me),me[0]&8&&O(ut,1)):(ut=df(q),ut.c(),O(ut,1),ut.m(l,Os)):ut&&(Ie(),B(ut,1,1,()=>{ut=null}),Oe()),me[0]&8&&(Rs=q[3].p.r.startsWith("10YNO")||q[3].p.r=="10Y1001A1001A48H"),Rs?ft?(ft.p(q,me),me[0]&8&&O(ft,1)):(ft=bf(q),ft.c(),O(ft,1),ft.m(l,Ls)):ft&&(Ie(),B(ft,1,1,()=>{ft=null}),Oe()),me[0]&136){ei=q[7];let Vt;for(Vt=0;Vt20||q[0].chip=="esp8266"||q[3].i.d.d>0?ct?(ct.p(q,me),me[0]&9&&O(ct,1)):(ct=wf(q),ct.c(),O(ct,1),ct.m(l,Fs)):ct&&(Ie(),B(ct,1,1,()=>{ct=null}),Oe()),me[0]&8&&(il.checked=q[3].d.s),q[3].d.s?Nt?Nt.p(q,me):(Nt=Nf(q),Nt.c(),Nt.m(Ft,null)):Nt&&(Nt.d(1),Nt=null);const _t={};me[0]&2&&(_t.active=q[1]),ln.$set(_t);const ha={};me[0]&4&&(ha.active=q[2]),nn.$set(ha);const ba={};me[0]&16&&(ba.active=q[4]),sn.$set(ba);const ga={};me[0]&32&&(ga.active=q[5]),on.$set(ga)},i(q){Gt||(O(a.$$.fragment,q),O(L.$$.fragment,q),O(Dl.$$.fragment,q),O(Nn.$$.fragment,q),O(Dn.$$.fragment,q),O(Rn.$$.fragment,q),O(Fn.$$.fragment,q),O(ot),O(rt),O(at),O(ut),O(ft),O(Qn.$$.fragment,q),O(ct),O(Zn.$$.fragment,q),O(ln.$$.fragment,q),O(nn.$$.fragment,q),O(sn.$$.fragment,q),O(on.$$.fragment,q),Gt=!0)},o(q){B(a.$$.fragment,q),B(L.$$.fragment,q),B(Dl.$$.fragment,q),B(Nn.$$.fragment,q),B(Dn.$$.fragment,q),B(Rn.$$.fragment,q),B(Fn.$$.fragment,q),B(ot),B(rt),B(at),B(ut),B(ft),B(Qn.$$.fragment,q),B(ct),B(Zn.$$.fragment,q),B(ln.$$.fragment,q),B(nn.$$.fragment,q),B(sn.$$.fragment,q),B(on.$$.fragment,q),Gt=!1},d(q){q&&w(e),oe(a),oe(L),Kt(bi,q),kt&&kt.d(),wt&&wt.d(),oe(Dl),Kt(gi,q),yt&&yt.d(),Ct&&Ct.d(),Mt&&Mt.d(),oe(Nn),qt&&qt.d(),St&&St.d(),oe(Dn),oe(Rn),Tt&&Tt.d(),oe(Fn),$t&&$t.d(),ot&&ot.d(),rt&&rt.d(),at&&at.d(),ut&&ut.d(),ft&&ft.d(),oe(Qn),Kt(vt,q),ct&&ct.d(),oe(Zn),Nt&&Nt.d(),q&&w(Bs),oe(ln,q),q&&w(Us),oe(nn,q),q&&w(js),oe(sn,q),q&&w(Hs),oe(on,q),Ws=!1,Ge(va)}}}async function Np(){await(await fetch("/reboot",{method:"POST"})).json()}function Ap(t,e,l){let{sysinfo:n={}}=e,i=[{name:"Import gauge",key:"i"},{name:"Export gauge",key:"e"},{name:"Voltage",key:"v"},{name:"Amperage",key:"a"},{name:"Reactive",key:"r"},{name:"Realtime",key:"c"},{name:"Peaks",key:"t"},{name:"Realtime plot",key:"l"},{name:"Price",key:"p"},{name:"Day plot",key:"d"},{name:"Month plot",key:"m"},{name:"Temperature plot",key:"s"},{name:"Dark mode",key:"k"}],o=!0,u=!1,a={g:{t:"",h:"",s:0,u:"",p:""},m:{b:2400,p:11,i:!1,d:0,f:0,r:0,e:{e:!1,k:"",a:""},m:{e:!1,w:!1,v:!1,a:!1,c:!1}},w:{s:"",p:"",w:0,z:255,a:!0,b:!0},n:{m:"",i:"",s:"",g:"",d1:"",d2:"",d:!1,n1:"",n2:"",h:!1},q:{h:"",p:1883,u:"",a:"",b:"",s:{e:!1,c:!1,r:!0,k:!1}},o:{e:"",c:"",u1:"",u2:"",u3:""},t:{t:[0,0,0,0,0,0,0,0,0,0],h:1},p:{e:!1,t:"",r:"",c:"",m:1,f:null},d:{s:!1,t:!1,l:5},u:{i:0,e:0,v:0,a:0,r:0,c:0,t:0,p:0,d:0,m:0,s:0},i:{h:{p:null,u:!0},a:null,l:{p:null,i:!1},r:{r:null,g:null,b:null,i:!1},d:{d:null,b:0},t:{d:null,a:null},v:{p:null,d:{v:null,g:null},o:null,m:null,b:null}},h:{t:"",h:"",n:""},c:{e:!1,i:null,s:null,es:null}};yi.subscribe(Ze=>{Ze.version&&(l(3,a=Ze),l(1,o=!1))}),Vm();let c=!1,f=!1;async function p(){if(confirm("Are you sure you want to factory reset the device?")){l(4,c=!0);const Ze=new URLSearchParams;Ze.append("perform","true");let Vl=await(await fetch("/reset",{method:"POST",body:Ze})).json();l(4,c=!1),l(5,f=Vl.success)}}async function _(Ze){l(2,u=!0);const mt=new FormData(Ze.target),Vl=new URLSearchParams;for(let Ol of mt){const[ji,Wt]=Ol;Vl.append(ji,Wt)}let Ui=await(await fetch("/save",{method:"POST",body:Vl})).json();Yt.update(Ol=>(Ol.booting=Ui.reboot,Ol.ui=a.u,Ol)),l(2,u=!1),si("/")}const h=function(){confirm("Are you sure you want to reboot the device?")&&(Yt.update(Ze=>(Ze.booting=!0,Ze)),Np())};async function d(){confirm("Are you sure you want to delete CA?")&&(await(await fetch("/mqtt-ca",{method:"POST"})).text(),yi.update(mt=>(mt.q.s.c=!1,mt)))}async function v(){confirm("Are you sure you want to delete cert?")&&(await(await fetch("/mqtt-cert",{method:"POST"})).text(),yi.update(mt=>(mt.q.s.r=!1,mt)))}async function g(){confirm("Are you sure you want to delete key?")&&(await(await fetch("/mqtt-key",{method:"POST"})).text(),yi.update(mt=>(mt.q.s.k=!1,mt)))}const E=function(){a.q.s.e?a.q.p==1883&&l(3,a.q.p=8883,a):a.q.p==8883&&l(3,a.q.p=1883,a)};let $=44;function M(){a.g.h=this.value,l(3,a)}function P(){a.g.t=nt(this),l(3,a)}function F(){a.p.r=nt(this),l(3,a)}function A(){a.p.c=nt(this),l(3,a)}function I(){a.p.f=he(this.value),l(3,a)}function D(){a.p.m=he(this.value),l(3,a)}function L(){a.p.e=this.checked,l(3,a)}function ie(){a.p.t=this.value,l(3,a)}function H(){a.g.s=nt(this),l(3,a)}function K(){a.g.u=this.value,l(3,a)}function G(){a.g.p=this.value,l(3,a)}function Y(){a.m.a=nt(this),l(3,a)}function Q(){a.m.i=this.checked,l(3,a)}function z(){a.m.b=nt(this),l(3,a)}function Z(){a.m.p=nt(this),l(3,a)}function V(){a.m.s=he(this.value),l(3,a)}function j(){a.m.d=nt(this),l(3,a)}function ee(){a.m.f=he(this.value),l(3,a)}function ue(){a.m.r=he(this.value),l(3,a)}function x(){a.m.e.e=this.checked,l(3,a)}function W(){a.m.e.k=this.value,l(3,a)}function U(){a.m.e.a=this.value,l(3,a)}function ke(){a.m.m.e=this.checked,l(3,a)}function He(){a.m.m.w=he(this.value),l(3,a)}function Be(){a.m.m.v=he(this.value),l(3,a)}function We(){a.m.m.a=he(this.value),l(3,a)}function Ne(){a.m.m.c=he(this.value),l(3,a)}function ge(){a.n.c=nt(this),l(3,a)}function Re(){a.w.s=this.value,l(3,a)}function Me(){a.w.p=this.value,l(3,a)}function S(){a.w.z=nt(this),l(3,a)}function k(){a.w.w=he(this.value),l(3,a)}function y(){a.w.b=this.checked,l(3,a)}function N(){a.n.m=nt(this),l(3,a)}function R(){a.n.i=this.value,l(3,a)}function J(){a.n.s=nt(this),l(3,a)}function te(){a.n.g=this.value,l(3,a)}function fe(){a.n.d1=this.value,l(3,a)}function de(){a.n.d2=this.value,l(3,a)}function we(){a.n.d=this.checked,l(3,a)}function Ae(){a.n.h=this.checked,l(3,a)}function ae(){a.n.n1=this.value,l(3,a)}function Ce(){a.q.s.e=this.checked,l(3,a)}function Je(){a.q.h=this.value,l(3,a)}function At(){a.q.p=he(this.value),l(3,a)}function st(){a.q.u=this.value,l(3,a)}function ht(){a.q.a=this.value,l(3,a)}function lt(){a.q.c=this.value,l(3,a)}function Et(){a.q.m=nt(this),l(3,a)}function Ye(){a.q.b=this.value,l(3,a)}function Qt(){a.o.e=this.value,l(3,a)}function Ht(){a.o.c=this.value,l(3,a)}function bt(){a.o.u1=this.value,l(3,a)}function ze(){a.o.u2=this.value,l(3,a)}function xe(){a.o.u3=this.value,l(3,a)}function Xe(){a.h.t=this.value,l(3,a)}function Ue(){a.h.h=this.value,l(3,a)}function qe(){a.h.n=this.value,l(3,a)}function et(){a.c.e=this.checked,l(3,a)}function Ee(){a.c.i=this.value,l(3,a)}function Le(){a.c.s=this.value,l(3,a)}function pe(){a.c.es=this.checked,l(3,a)}function ce(Ze){a.t.t[Ze]=he(this.value),l(3,a)}function ye(){a.t.h=he(this.value),l(3,a)}function zl(Ze){a.u[Ze.key]=nt(this),l(3,a)}function hl(){a.i.h.p=nt(this),l(3,a)}function _n(){a.i.h.t=nt(this),l(3,a)}function Pt(){a.i.h.u=this.checked,l(3,a)}function Ei(){a.i.a=he(this.value),l(3,a)}function Pi(){a.i.l.p=he(this.value),l(3,a)}function Di(){a.i.l.i=this.checked,l(3,a)}function bl(){a.i.r.i=this.checked,l(3,a)}function Ii(){a.i.r.r=he(this.value),l(3,a)}function Oi(){a.i.r.g=he(this.value),l(3,a)}function Ri(){a.i.r.b=he(this.value),l(3,a)}function Dt(){a.i.d.d=he(this.value),l(3,a)}function Nl(){a.i.t.d=he(this.value),l(3,a)}function Al(){a.i.t.a=he(this.value),l(3,a)}function El(){a.i.v.p=he(this.value),l(3,a)}function Li(){a.i.v.d.v=he(this.value),l(3,a)}function Fi(){a.i.v.d.g=he(this.value),l(3,a)}function je(){a.i.d.b=nt(this),l(3,a)}function dn(){a.i.v.o=he(this.value),l(3,a)}function qi(){a.i.v.m=he(this.value),l(3,a)}function Pl(){a.i.v.b=he(this.value),l(3,a)}function Dl(){a.d.s=this.checked,l(3,a)}function Bi(){a.d.t=this.checked,l(3,a)}function Gl(){a.d.l=nt(this),l(3,a)}return t.$$set=Ze=>{"sysinfo"in Ze&&l(0,n=Ze.sysinfo)},t.$$.update=()=>{t.$$.dirty[0]&1&&l(6,$=n.chip=="esp8266"?16:n.chip=="esp32s2"?44:39)},[n,o,u,a,c,f,$,i,p,_,h,d,v,g,E,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j,ee,ue,x,W,U,ke,He,Be,We,Ne,ge,Re,Me,S,k,y,N,R,J,te,fe,de,we,Ae,ae,Ce,Je,At,st,ht,lt,Et,Ye,Qt,Ht,bt,ze,xe,Xe,Ue,qe,et,Ee,Le,pe,ce,ye,zl,hl,_n,Pt,Ei,Pi,Di,bl,Ii,Oi,Ri,Dt,Nl,Al,El,Li,Fi,je,dn,qi,Pl,Dl,Bi,Gl]}class Ep extends De{constructor(e){super(),Pe(this,e,Ap,$p,$e,{sysinfo:0},null,[-1,-1,-1,-1])}}function Ef(t,e,l){const n=t.slice();return n[20]=e[l],n}function Pp(t){let e=ve(t[1].chip,t[1].board)+"",l;return{c(){l=T(e)},m(n,i){C(n,l,i)},p(n,i){i&2&&e!==(e=ve(n[1].chip,n[1].board)+"")&&X(l,e)},d(n){n&&w(l)}}}function Pf(t){let e,l,n=t[1].apmac+"",i,o,u,a,c,f,p,_,h,d=Fa(t[1])+"",v,g,E=t[1].boot_reason+"",$,M,P=t[1].ex_cause+"",F,A,I;const D=[Ip,Dp],L=[];function ie(H,K){return H[0].u>0?0:1}return c=ie(t),f=L[c]=D[c](t),{c(){e=m("div"),l=T("AP MAC: "),i=T(n),o=b(),u=m("div"),a=T(`Last boot: + `),f.c(),p=b(),_=m("div"),h=T("Reason: "),v=T(d),g=T(" ("),$=T(E),M=T("/"),F=T(P),A=T(")"),r(e,"class","my-2"),r(u,"class","my-2"),r(_,"class","my-2")},m(H,K){C(H,e,K),s(e,l),s(e,i),C(H,o,K),C(H,u,K),s(u,a),L[c].m(u,null),C(H,p,K),C(H,_,K),s(_,h),s(_,v),s(_,g),s(_,$),s(_,M),s(_,F),s(_,A),I=!0},p(H,K){(!I||K&2)&&n!==(n=H[1].apmac+"")&&X(i,n);let G=c;c=ie(H),c===G?L[c].p(H,K):(Ie(),B(L[G],1,1,()=>{L[G]=null}),Oe(),f=L[c],f?f.p(H,K):(f=L[c]=D[c](H),f.c()),O(f,1),f.m(u,null)),(!I||K&2)&&d!==(d=Fa(H[1])+"")&&X(v,d),(!I||K&2)&&E!==(E=H[1].boot_reason+"")&&X($,E),(!I||K&2)&&P!==(P=H[1].ex_cause+"")&&X(F,P)},i(H){I||(O(f),I=!0)},o(H){B(f),I=!1},d(H){H&&w(e),H&&w(o),H&&w(u),L[c].d(),H&&w(p),H&&w(_)}}}function Dp(t){let e;return{c(){e=T("-")},m(l,n){C(l,e,n)},p:_e,i:_e,o:_e,d(l){l&&w(e)}}}function Ip(t){let e,l;return e=new Yc({props:{timestamp:new Date(new Date().getTime()-t[0].u*1e3),fullTimeColor:""}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.timestamp=new Date(new Date().getTime()-n[0].u*1e3)),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function Op(t){let e;return{c(){e=m("span"),e.textContent="Update consents",r(e,"class","btn-pri-sm")},m(l,n){C(l,e,n)},p:_e,d(l){l&&w(e)}}}function Df(t){let e,l,n,i,o,u=ys(t[1].meter.mfg)+"",a,c,f,p,_=(t[1].meter.model?t[1].meter.model:"unknown")+"",h,d,v,g,E=(t[1].meter.id?t[1].meter.id:"unknown")+"",$;return{c(){e=m("div"),l=m("strong"),l.textContent="Meter",n=b(),i=m("div"),o=T("Manufacturer: "),a=T(u),c=b(),f=m("div"),p=T("Model: "),h=T(_),d=b(),v=m("div"),g=T("ID: "),$=T(E),r(l,"class","text-sm"),r(i,"class","my-2"),r(f,"class","my-2"),r(v,"class","my-2"),r(e,"class","cnt")},m(M,P){C(M,e,P),s(e,l),s(e,n),s(e,i),s(i,o),s(i,a),s(e,c),s(e,f),s(f,p),s(f,h),s(e,d),s(e,v),s(v,g),s(v,$)},p(M,P){P&2&&u!==(u=ys(M[1].meter.mfg)+"")&&X(a,u),P&2&&_!==(_=(M[1].meter.model?M[1].meter.model:"unknown")+"")&&X(h,_),P&2&&E!==(E=(M[1].meter.id?M[1].meter.id:"unknown")+"")&&X($,E)},d(M){M&&w(e)}}}function If(t){let e,l,n,i,o,u=t[1].net.ip+"",a,c,f,p,_=t[1].net.mask+"",h,d,v,g,E=t[1].net.gw+"",$,M,P,F,A=t[1].net.dns1+"",I,D,L=t[1].net.dns2&&Of(t);return{c(){e=m("div"),l=m("strong"),l.textContent="Network",n=b(),i=m("div"),o=T("IP: "),a=T(u),c=b(),f=m("div"),p=T("Mask: "),h=T(_),d=b(),v=m("div"),g=T("Gateway: "),$=T(E),M=b(),P=m("div"),F=T("DNS: "),I=T(A),D=b(),L&&L.c(),r(l,"class","text-sm"),r(i,"class","my-2"),r(f,"class","my-2"),r(v,"class","my-2"),r(P,"class","my-2"),r(e,"class","cnt")},m(ie,H){C(ie,e,H),s(e,l),s(e,n),s(e,i),s(i,o),s(i,a),s(e,c),s(e,f),s(f,p),s(f,h),s(e,d),s(e,v),s(v,g),s(v,$),s(e,M),s(e,P),s(P,F),s(P,I),s(P,D),L&&L.m(P,null)},p(ie,H){H&2&&u!==(u=ie[1].net.ip+"")&&X(a,u),H&2&&_!==(_=ie[1].net.mask+"")&&X(h,_),H&2&&E!==(E=ie[1].net.gw+"")&&X($,E),H&2&&A!==(A=ie[1].net.dns1+"")&&X(I,A),ie[1].net.dns2?L?L.p(ie,H):(L=Of(ie),L.c(),L.m(P,null)):L&&(L.d(1),L=null)},d(ie){ie&&w(e),L&&L.d()}}}function Of(t){let e,l=t[1].net.dns2+"",n;return{c(){e=T("/ "),n=T(l)},m(i,o){C(i,e,o),C(i,n,o)},p(i,o){o&2&&l!==(l=i[1].net.dns2+"")&&X(n,l)},d(i){i&&w(e),i&&w(n)}}}function Rf(t){let e,l,n,i=t[1].upgrade.t+"",o,u,a=t[1].version+"",c,f,p=t[1].upgrade.x+"",_,h,d=t[1].upgrade.e+"",v,g;return{c(){e=m("div"),l=m("div"),n=T("Previous upgrade attempt ("),o=T(i),u=T(") does not match current version ("),c=T(a),f=T(") ["),_=T(p),h=T("/"),v=T(d),g=T("]"),r(l,"class","bd-yellow"),r(e,"class","my-2")},m(E,$){C(E,e,$),s(e,l),s(l,n),s(l,o),s(l,u),s(l,c),s(l,f),s(l,_),s(l,h),s(l,v),s(l,g)},p(E,$){$&2&&i!==(i=E[1].upgrade.t+"")&&X(o,i),$&2&&a!==(a=E[1].version+"")&&X(c,a),$&2&&p!==(p=E[1].upgrade.x+"")&&X(_,p),$&2&&d!==(d=E[1].upgrade.e+"")&&X(v,d)},d(E){E&&w(e)}}}function Lf(t){let e,l,n,i=t[2].tag_name+"",o,u,a,c,f,p,_=(t[1].security==0||t[0].a)&&t[1].fwconsent===1&&t[2]&&t[2].tag_name!=t[1].version&&Ff(t),h=t[1].fwconsent===2&&qf();return{c(){e=m("div"),l=T(`Latest version: + `),n=m("a"),o=T(i),a=b(),_&&_.c(),c=b(),h&&h.c(),f=Ve(),r(n,"href",u=t[2].html_url),r(n,"class","ml-2 text-blue-600 hover:text-blue-800"),r(n,"target","_blank"),r(n,"rel","noreferrer"),r(e,"class","my-2 flex")},m(d,v){C(d,e,v),s(e,l),s(e,n),s(n,o),s(e,a),_&&_.m(e,null),C(d,c,v),h&&h.m(d,v),C(d,f,v),p=!0},p(d,v){(!p||v&4)&&i!==(i=d[2].tag_name+"")&&X(o,i),(!p||v&4&&u!==(u=d[2].html_url))&&r(n,"href",u),(d[1].security==0||d[0].a)&&d[1].fwconsent===1&&d[2]&&d[2].tag_name!=d[1].version?_?(_.p(d,v),v&7&&O(_,1)):(_=Ff(d),_.c(),O(_,1),_.m(e,null)):_&&(Ie(),B(_,1,1,()=>{_=null}),Oe()),d[1].fwconsent===2?h||(h=qf(),h.c(),h.m(f.parentNode,f)):h&&(h.d(1),h=null)},i(d){p||(O(_),p=!0)},o(d){B(_),p=!1},d(d){d&&w(e),_&&_.d(),d&&w(c),h&&h.d(d),d&&w(f)}}}function Ff(t){let e,l,n,i,o,u;return n=new Qc({}),{c(){e=m("div"),l=m("button"),re(n.$$.fragment),r(e,"class","flex-none ml-2 text-green-500"),r(e,"title","Install this version")},m(a,c){C(a,e,c),s(e,l),se(n,l,null),i=!0,o||(u=le(l,"click",t[10]),o=!0)},p:_e,i(a){i||(O(n.$$.fragment,a),i=!0)},o(a){B(n.$$.fragment,a),i=!1},d(a){a&&w(e),oe(n),o=!1,u()}}}function qf(t){let e;return{c(){e=m("div"),e.innerHTML='
You have disabled one-click firmware upgrade, link to self-upgrade is disabled
',r(e,"class","my-2")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Bf(t){let e,l=Cs(ve(t[1].chip,t[1].board))+"",n;return{c(){e=m("div"),n=T(l),r(e,"class","bd-red")},m(i,o){C(i,e,o),s(e,n)},p(i,o){o&2&&l!==(l=Cs(ve(i[1].chip,i[1].board))+"")&&X(n,l)},d(i){i&&w(e)}}}function Uf(t){let e,l,n,i,o,u;function a(p,_){return p[4].length==0?Lp:Rp}let c=a(t),f=c(t);return{c(){e=m("div"),l=m("form"),n=m("input"),i=b(),f.c(),nc(n,"display","none"),r(n,"name","file"),r(n,"type","file"),r(n,"accept",".bin"),r(l,"action","/firmware"),r(l,"enctype","multipart/form-data"),r(l,"method","post"),r(l,"autocomplete","off"),r(e,"class","my-2 flex")},m(p,_){C(p,e,_),s(e,l),s(l,n),t[12](n),s(l,i),f.m(l,null),o||(u=[le(n,"change",t[13]),le(l,"submit",t[15])],o=!0)},p(p,_){c===(c=a(p))&&f?f.p(p,_):(f.d(1),f=c(p),f&&(f.c(),f.m(l,null)))},d(p){p&&w(e),t[12](null),f.d(),o=!1,Ge(u)}}}function Rp(t){let e=t[4][0].name+"",l,n,i;return{c(){l=T(e),n=b(),i=m("button"),i.textContent="Upload",r(i,"type","submit"),r(i,"class","btn-pri-sm float-right")},m(o,u){C(o,l,u),C(o,n,u),C(o,i,u)},p(o,u){u&16&&e!==(e=o[4][0].name+"")&&X(l,e)},d(o){o&&w(l),o&&w(n),o&&w(i)}}}function Lp(t){let e,l,n;return{c(){e=m("button"),e.textContent="Select firmware file for upgrade",r(e,"type","button"),r(e,"class","btn-pri-sm float-right")},m(i,o){C(i,e,o),l||(n=le(e,"click",t[14]),l=!0)},p:_e,d(i){i&&w(e),l=!1,n()}}}function jf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g=t[9],E=[];for(let A=0;A Include Secrets
(SSID, PSK, passwords and tokens)',c=b(),$&&$.c(),f=b(),p=m("form"),_=m("input"),h=b(),F.c(),r(l,"class","text-sm"),r(a,"class","my-1 mx-3 col-span-2"),r(o,"class","grid grid-cols-2"),r(i,"method","get"),r(i,"action","/configfile.cfg"),r(i,"autocomplete","off"),nc(_,"display","none"),r(_,"name","file"),r(_,"type","file"),r(_,"accept",".cfg"),r(p,"action","/configfile"),r(p,"enctype","multipart/form-data"),r(p,"method","post"),r(p,"autocomplete","off"),r(e,"class","cnt")},m(A,I){C(A,e,I),s(e,l),s(e,n),s(e,i),s(i,o);for(let D=0;D{N=null}),Oe());const At={};Ce&8388608&&(At.$$scope={dirty:Ce,ctx:ae}),ie.$set(At),ae[1].meter?R?R.p(ae,Ce):(R=Df(ae),R.c(),R.m(e,Y)):R&&(R.d(1),R=null),ae[1].net?J?J.p(ae,Ce):(J=If(ae),J.c(),J.m(e,Q)):J&&(J.d(1),J=null),(!S||Ce&2)&&ue!==(ue=ae[1].version+"")&&X(x,ue),ae[1].upgrade.t&&ae[1].upgrade.t!=ae[1].version?te?te.p(ae,Ce):(te=Rf(ae),te.c(),te.m(z,U)):te&&(te.d(1),te=null),ae[2]?fe?(fe.p(ae,Ce),Ce&4&&O(fe,1)):(fe=Lf(ae),fe.c(),O(fe,1),fe.m(z,ke)):fe&&(Ie(),B(fe,1,1,()=>{fe=null}),Oe()),Ce&3&&(He=(ae[1].security==0||ae[0].a)&&oi(ae[1].board)),He?de?de.p(ae,Ce):(de=Bf(ae),de.c(),de.m(z,Be)):de&&(de.d(1),de=null),ae[1].security==0||ae[0].a?we?we.p(ae,Ce):(we=Uf(ae),we.c(),we.m(z,null)):we&&(we.d(1),we=null),ae[1].security==0||ae[0].a?Ae?Ae.p(ae,Ce):(Ae=jf(ae),Ae.c(),Ae.m(e,null)):Ae&&(Ae.d(1),Ae=null);const st={};Ce&32&&(st.active=ae[5]),ge.$set(st);const ht={};Ce&256&&(ht.active=ae[8]),Me.$set(ht)},i(ae){S||(O(E.$$.fragment,ae),O(N),O(ie.$$.fragment,ae),O(fe),O(ge.$$.fragment,ae),O(Me.$$.fragment,ae),S=!0)},o(ae){B(E.$$.fragment,ae),B(N),B(ie.$$.fragment,ae),B(fe),B(ge.$$.fragment,ae),B(Me.$$.fragment,ae),S=!1},d(ae){ae&&w(e),oe(E),N&&N.d(),oe(ie),R&&R.d(),J&&J.d(),te&&te.d(),fe&&fe.d(),de&&de.d(),we&&we.d(),Ae&&Ae.d(),ae&&w(Ne),oe(ge,ae),ae&&w(Re),oe(Me,ae),k=!1,y()}}}async function Up(){await(await fetch("/reboot",{method:"POST"})).json()}function jp(t,e,l){let{data:n}=e,{sysinfo:i}=e,o=[{name:"WiFi",key:"iw"},{name:"MQTT",key:"im"},{name:"Web",key:"ie"},{name:"Meter",key:"it"},{name:"Thresholds",key:"ih"},{name:"GPIO",key:"ig"},{name:"NTP",key:"in"},{name:"Price API",key:"is"}],u={};To.subscribe(D=>{l(2,u=Kc(i.version,D)),u||l(2,u=D[0])});function a(){confirm("Do you want to upgrade this device to "+u.tag_name+"?")&&(i.board!=2&&i.board!=4&&i.board!=7||confirm(Cs(ve(i.chip,i.board))))&&(Yt.update(D=>(D.upgrading=!0,D)),Vc(u.tag_name))}const c=function(){confirm("Are you sure you want to reboot the device?")&&(Yt.update(D=>(D.booting=!0,D)),Up())};let f,p=[],_=!1,h,d=[],v=!1;yo();function g(D){ks[D?"unshift":"push"](()=>{f=D,l(3,f)})}function E(){p=this.files,l(4,p)}const $=()=>{f.click()},M=()=>l(5,_=!0);function P(D){ks[D?"unshift":"push"](()=>{h=D,l(6,h)})}function F(){d=this.files,l(7,d)}const A=()=>{h.click()},I=()=>l(8,v=!0);return t.$$set=D=>{"data"in D&&l(0,n=D.data),"sysinfo"in D&&l(1,i=D.sysinfo)},[n,i,u,f,p,_,h,d,v,o,a,c,g,E,$,M,P,F,A,I]}class Hp extends De{constructor(e){super(),Pe(this,e,jp,Bp,$e,{data:0,sysinfo:1})}}function zf(t){let e,l,n=ve(t[0],7)+"",i,o,u=ve(t[0],5)+"",a,c,f=ve(t[0],4)+"",p,_,h=ve(t[0],3)+"",d,v,g,E,$=ve(t[0],2)+"",M,P,F=ve(t[0],1)+"",A,I,D=ve(t[0],0)+"",L,ie,H,K,G=ve(t[0],101)+"",Y,Q,z=ve(t[0],100)+"",Z;return{c(){e=m("optgroup"),l=m("option"),i=T(n),o=m("option"),a=T(u),c=m("option"),p=T(f),_=m("option"),d=T(h),v=b(),g=m("optgroup"),E=m("option"),M=T($),P=m("option"),A=T(F),I=m("option"),L=T(D),ie=b(),H=m("optgroup"),K=m("option"),Y=T(G),Q=m("option"),Z=T(z),l.__value=7,l.value=l.__value,o.__value=5,o.value=o.__value,c.__value=4,c.value=c.__value,_.__value=3,_.value=_.__value,r(e,"label","amsleser.no"),E.__value=2,E.value=E.__value,P.__value=1,P.value=P.__value,I.__value=0,I.value=I.__value,r(g,"label","Custom hardware"),K.__value=101,K.value=K.__value,Q.__value=100,Q.value=Q.__value,r(H,"label","Generic hardware")},m(V,j){C(V,e,j),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),s(e,_),s(_,d),C(V,v,j),C(V,g,j),s(g,E),s(E,M),s(g,P),s(P,A),s(g,I),s(I,L),C(V,ie,j),C(V,H,j),s(H,K),s(K,Y),s(H,Q),s(Q,Z)},p(V,j){j&1&&n!==(n=ve(V[0],7)+"")&&X(i,n),j&1&&u!==(u=ve(V[0],5)+"")&&X(a,u),j&1&&f!==(f=ve(V[0],4)+"")&&X(p,f),j&1&&h!==(h=ve(V[0],3)+"")&&X(d,h),j&1&&$!==($=ve(V[0],2)+"")&&X(M,$),j&1&&F!==(F=ve(V[0],1)+"")&&X(A,F),j&1&&D!==(D=ve(V[0],0)+"")&&X(L,D),j&1&&G!==(G=ve(V[0],101)+"")&&X(Y,G),j&1&&z!==(z=ve(V[0],100)+"")&&X(Z,z)},d(V){V&&w(e),V&&w(v),V&&w(g),V&&w(ie),V&&w(H)}}}function Gf(t){let e,l,n=ve(t[0],201)+"",i,o,u=ve(t[0],202)+"",a,c,f=ve(t[0],203)+"",p,_,h=ve(t[0],241)+"",d,v,g=ve(t[0],242)+"",E,$,M=ve(t[0],243)+"",P,F,A=ve(t[0],200)+"",I;return{c(){e=m("optgroup"),l=m("option"),i=T(n),o=m("option"),a=T(u),c=m("option"),p=T(f),_=m("option"),d=T(h),v=m("option"),E=T(g),$=m("option"),P=T(M),F=m("option"),I=T(A),l.__value=201,l.value=l.__value,o.__value=202,o.value=o.__value,c.__value=203,c.value=c.__value,_.__value=241,_.value=_.__value,v.__value=242,v.value=v.__value,$.__value=243,$.value=$.__value,F.__value=200,F.value=F.__value,r(e,"label","Generic hardware")},m(D,L){C(D,e,L),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),s(e,_),s(_,d),s(e,v),s(v,E),s(e,$),s($,P),s(e,F),s(F,I)},p(D,L){L&1&&n!==(n=ve(D[0],201)+"")&&X(i,n),L&1&&u!==(u=ve(D[0],202)+"")&&X(a,u),L&1&&f!==(f=ve(D[0],203)+"")&&X(p,f),L&1&&h!==(h=ve(D[0],241)+"")&&X(d,h),L&1&&g!==(g=ve(D[0],242)+"")&&X(E,g),L&1&&M!==(M=ve(D[0],243)+"")&&X(P,M),L&1&&A!==(A=ve(D[0],200)+"")&&X(I,A)},d(D){D&&w(e)}}}function Vf(t){let e,l,n=ve(t[0],7)+"",i,o,u=ve(t[0],6)+"",a,c,f=ve(t[0],5)+"",p,_,h,d,v=ve(t[0],51)+"",g,E,$=ve(t[0],50)+"",M;return{c(){e=m("optgroup"),l=m("option"),i=T(n),o=m("option"),a=T(u),c=m("option"),p=T(f),_=b(),h=m("optgroup"),d=m("option"),g=T(v),E=m("option"),M=T($),l.__value=7,l.value=l.__value,o.__value=6,o.value=o.__value,c.__value=5,c.value=c.__value,r(e,"label","amsleser.no"),d.__value=51,d.value=d.__value,E.__value=50,E.value=E.__value,r(h,"label","Generic hardware")},m(P,F){C(P,e,F),s(e,l),s(l,i),s(e,o),s(o,a),s(e,c),s(c,p),C(P,_,F),C(P,h,F),s(h,d),s(d,g),s(h,E),s(E,M)},p(P,F){F&1&&n!==(n=ve(P[0],7)+"")&&X(i,n),F&1&&u!==(u=ve(P[0],6)+"")&&X(a,u),F&1&&f!==(f=ve(P[0],5)+"")&&X(p,f),F&1&&v!==(v=ve(P[0],51)+"")&&X(g,v),F&1&&$!==($=ve(P[0],50)+"")&&X(M,$)},d(P){P&&w(e),P&&w(_),P&&w(h)}}}function Kf(t){let e,l,n=ve(t[0],8)+"",i,o,u,a,c=ve(t[0],71)+"",f,p,_=ve(t[0],70)+"",h;return{c(){e=m("optgroup"),l=m("option"),i=T(n),o=b(),u=m("optgroup"),a=m("option"),f=T(c),p=m("option"),h=T(_),l.__value=8,l.value=l.__value,r(e,"label","Custom hardware"),a.__value=71,a.value=a.__value,p.__value=70,p.value=p.__value,r(u,"label","Generic hardware")},m(d,v){C(d,e,v),s(e,l),s(l,i),C(d,o,v),C(d,u,v),s(u,a),s(a,f),s(u,p),s(p,h)},p(d,v){v&1&&n!==(n=ve(d[0],8)+"")&&X(i,n),v&1&&c!==(c=ve(d[0],71)+"")&&X(f,c),v&1&&_!==(_=ve(d[0],70)+"")&&X(h,_)},d(d){d&&w(e),d&&w(o),d&&w(u)}}}function Yf(t){let e,l,n=ve(t[0],200)+"",i;return{c(){e=m("optgroup"),l=m("option"),i=T(n),l.__value=200,l.value=l.__value,r(e,"label","Generic hardware")},m(o,u){C(o,e,u),s(e,l),s(l,i)},p(o,u){u&1&&n!==(n=ve(o[0],200)+"")&&X(i,n)},d(o){o&&w(e)}}}function Wp(t){let e,l,n,i,o,u,a,c=t[0]=="esp8266"&&zf(t),f=t[0]=="esp32"&&Gf(t),p=t[0]=="esp32s2"&&Vf(t),_=t[0]=="esp32c3"&&Kf(t),h=t[0]=="esp32solo"&&Yf(t);return{c(){e=m("option"),l=b(),c&&c.c(),n=b(),f&&f.c(),i=b(),p&&p.c(),o=b(),_&&_.c(),u=b(),h&&h.c(),a=Ve(),e.__value=-1,e.value=e.__value},m(d,v){C(d,e,v),C(d,l,v),c&&c.m(d,v),C(d,n,v),f&&f.m(d,v),C(d,i,v),p&&p.m(d,v),C(d,o,v),_&&_.m(d,v),C(d,u,v),h&&h.m(d,v),C(d,a,v)},p(d,[v]){d[0]=="esp8266"?c?c.p(d,v):(c=zf(d),c.c(),c.m(n.parentNode,n)):c&&(c.d(1),c=null),d[0]=="esp32"?f?f.p(d,v):(f=Gf(d),f.c(),f.m(i.parentNode,i)):f&&(f.d(1),f=null),d[0]=="esp32s2"?p?p.p(d,v):(p=Vf(d),p.c(),p.m(o.parentNode,o)):p&&(p.d(1),p=null),d[0]=="esp32c3"?_?_.p(d,v):(_=Kf(d),_.c(),_.m(u.parentNode,u)):_&&(_.d(1),_=null),d[0]=="esp32solo"?h?h.p(d,v):(h=Yf(d),h.c(),h.m(a.parentNode,a)):h&&(h.d(1),h=null)},i:_e,o:_e,d(d){d&&w(e),d&&w(l),c&&c.d(d),d&&w(n),f&&f.d(d),d&&w(i),p&&p.d(d),d&&w(o),_&&_.d(d),d&&w(u),h&&h.d(d),d&&w(a)}}}function zp(t,e,l){let{chip:n}=e;return t.$$set=i=>{"chip"in i&&l(0,n=i.chip)},[n]}class Gp extends De{constructor(e){super(),Pe(this,e,zp,Wp,$e,{chip:0})}}function Qf(t){let e;return{c(){e=m("div"),e.textContent="WARNING: Changing this configuration will affect basic configuration of your device. Only make changes here if instructed by vendor",r(e,"class","bd-red")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Xf(t){let e,l,n,i,o,u,a;return u=new fo({props:{chip:t[0].chip}}),{c(){e=m("div"),l=T("HAN GPIO"),n=m("br"),i=b(),o=m("select"),re(u.$$.fragment),r(o,"name","vh"),r(o,"class","in-s"),r(e,"class","my-3")},m(c,f){C(c,e,f),s(e,l),s(e,n),s(e,i),s(e,o),se(u,o,null),a=!0},p(c,f){const p={};f&1&&(p.chip=c[0].chip),u.$set(p)},i(c){a||(O(u.$$.fragment,c),a=!0)},o(c){B(u.$$.fragment,c),a=!1},d(c){c&&w(e),oe(u)}}}function Vp(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q=t[0].usrcfg&&Qf();v=new Gp({props:{chip:t[0].chip}});let z=t[0].board&&t[0].board>20&&Xf(t);return H=new jt({props:{active:t[1],message:"Saving device configuration"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("input"),o=b(),u=m("strong"),u.textContent="Initial configuration",a=b(),Q&&Q.c(),c=b(),f=m("div"),p=T("Board type"),_=m("br"),h=b(),d=m("select"),re(v.$$.fragment),g=b(),z&&z.c(),E=b(),$=m("div"),M=m("label"),P=m("input"),F=T(" Clear all other configuration"),A=b(),I=m("div"),I.innerHTML='',D=b(),L=m("span"),L.textContent=" ",ie=b(),re(H.$$.fragment),r(i,"type","hidden"),r(i,"name","v"),i.value="true",r(u,"class","text-sm"),r(d,"name","vb"),r(d,"class","in-s"),t[0].board===void 0&&Ke(()=>t[4].call(d)),r(f,"class","my-3"),r(P,"type","checkbox"),r(P,"name","vr"),P.__value="true",P.value=P.__value,r(P,"class","rounded mb-1"),r($,"class","my-3"),r(I,"class","my-3"),r(L,"class","clear-both"),r(n,"autocomplete","off"),r(l,"class","cnt"),r(e,"class","grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2")},m(Z,V){C(Z,e,V),s(e,l),s(l,n),s(n,i),s(n,o),s(n,u),s(n,a),Q&&Q.m(n,null),s(n,c),s(n,f),s(f,p),s(f,_),s(f,h),s(f,d),se(v,d,null),Se(d,t[0].board,!0),s(n,g),z&&z.m(n,null),s(n,E),s(n,$),s($,M),s(M,P),P.checked=t[2],s(M,F),s(n,A),s(n,I),s(n,D),s(n,L),C(Z,ie,V),se(H,Z,V),K=!0,G||(Y=[le(d,"change",t[4]),le(P,"change",t[5]),le(n,"submit",Ms(t[3]))],G=!0)},p(Z,[V]){Z[0].usrcfg?Q||(Q=Qf(),Q.c(),Q.m(n,c)):Q&&(Q.d(1),Q=null);const j={};V&1&&(j.chip=Z[0].chip),v.$set(j),V&1&&Se(d,Z[0].board),Z[0].board&&Z[0].board>20?z?(z.p(Z,V),V&1&&O(z,1)):(z=Xf(Z),z.c(),O(z,1),z.m(n,E)):z&&(Ie(),B(z,1,1,()=>{z=null}),Oe()),V&4&&(P.checked=Z[2]);const ee={};V&2&&(ee.active=Z[1]),H.$set(ee)},i(Z){K||(O(v.$$.fragment,Z),O(z),O(H.$$.fragment,Z),K=!0)},o(Z){B(v.$$.fragment,Z),B(z),B(H.$$.fragment,Z),K=!1},d(Z){Z&&w(e),Q&&Q.d(),oe(v),z&&z.d(),Z&&w(ie),oe(H,Z),G=!1,Ge(Y)}}}function Kp(t,e,l){let{sysinfo:n={}}=e,i=!1;async function o(f){l(1,i=!0);const p=new FormData(f.target),_=new URLSearchParams;for(let v of p){const[g,E]=v;_.append(g,E)}let d=await(await fetch("/save",{method:"POST",body:_})).json();l(1,i=!1),Yt.update(v=>(v.vndcfg=d.success,v.booting=d.reboot,v)),si(n.usrcfg?"/":"/setup")}let u=!1;function a(){n.board=nt(this),l(0,n)}function c(){u=this.checked,l(2,u),l(0,n)}return t.$$set=f=>{"sysinfo"in f&&l(0,n=f.sysinfo)},t.$$.update=()=>{t.$$.dirty&1&&l(2,u=!n.usrcfg)},[n,i,u,o,a,c]}class Yp extends De{constructor(e){super(),Pe(this,e,Kp,Vp,$e,{sysinfo:0})}}function Zf(t){let e;return{c(){e=m("option"),e.textContent="Ethernet",e.__value=3,e.value=e.__value},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Jf(t){let e,l,n,i,o,u,a,c,f,p,_,h,d;return{c(){e=m("div"),l=T("SSID"),n=m("br"),i=b(),o=m("input"),a=b(),c=m("div"),f=T("PSK"),p=m("br"),_=b(),h=m("input"),r(o,"name","ss"),r(o,"type","text"),r(o,"class","in-s"),o.required=u=t[2]==1||t[2]==2,r(e,"class","my-3"),r(h,"name","sp"),r(h,"type","password"),r(h,"class","in-s"),r(h,"autocomplete","off"),h.required=d=t[2]==2,r(c,"class","my-3")},m(v,g){C(v,e,g),s(e,l),s(e,n),s(e,i),s(e,o),C(v,a,g),C(v,c,g),s(c,f),s(c,p),s(c,_),s(c,h)},p(v,g){g&4&&u!==(u=v[2]==1||v[2]==2)&&(o.required=u),g&4&&d!==(d=v[2]==2)&&(h.required=d)},d(v){v&&w(e),v&&w(a),v&&w(c)}}}function xf(t){let e,l,n,i,o,u,a,c;return a=new Zc({}),{c(){e=m("br"),l=b(),n=m("div"),i=m("input"),o=b(),u=m("select"),re(a.$$.fragment),r(i,"name","si"),r(i,"type","text"),r(i,"class","in-f w-full"),i.required=t[1],r(u,"name","su"),r(u,"class","in-l"),u.required=t[1],r(n,"class","flex")},m(f,p){C(f,e,p),C(f,l,p),C(f,n,p),s(n,i),s(n,o),s(n,u),se(a,u,null),c=!0},p(f,p){(!c||p&2)&&(i.required=f[1]),(!c||p&2)&&(u.required=f[1])},i(f){c||(O(a.$$.fragment,f),c=!0)},o(f){B(a.$$.fragment,f),c=!1},d(f){f&&w(e),f&&w(l),f&&w(n),oe(a)}}}function ec(t){let e;return{c(){e=m("div"),e.innerHTML=`
Gateway
DNS
-
`,u(e,"class","my-3 flex")},m(l,n){w(l,e,n)},d(l){l&&k(e)}}}function L0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z=t[1]&&Jf(t),q=t[1]&&xf();return Y=new Et({props:{active:t[2],message:"Saving your configuration to the device"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("input"),o=h(),r=m("strong"),r.textContent="Setup",a=h(),c=m("div"),c.innerHTML=`SSID
- `,f=h(),p=m("div"),p.innerHTML=`PSK
- `,_=h(),b=m("div"),d=y(`Hostname - `),v=m("input"),g=h(),T=m("div"),C=m("label"),$=m("input"),M=y(" Static IP"),F=h(),z&&z.c(),S=h(),q&&q.c(),D=h(),A=m("div"),A.innerHTML='',E=h(),Z(Y.$$.fragment),u(i,"type","hidden"),u(i,"name","s"),i.value="true",u(r,"class","text-sm"),u(c,"class","my-3"),u(p,"class","my-3"),u(v,"name","sh"),u(v,"type","text"),u(v,"class","in-s"),u(v,"maxlength","32"),u(v,"pattern","[a-z0-9_-]+"),u(v,"placeholder","Optional, ex.: ams-reader"),u(v,"autocomplete","off"),u($,"type","checkbox"),u($,"name","sm"),$.__value="static",$.value=$.__value,u($,"class","rounded mb-1"),u(T,"class","my-3"),u(A,"class","my-3"),u(l,"class","cnt"),u(e,"class","grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2")},m(L,B){w(L,e,B),s(e,l),s(l,n),s(n,i),s(n,o),s(n,r),s(n,a),s(n,c),s(n,f),s(n,p),s(n,_),s(n,b),s(b,d),s(b,v),V(v,t[0].hostname),s(n,g),s(n,T),s(T,C),s(C,$),$.checked=t[1],s(C,M),s(T,F),z&&z.m(T,null),s(n,S),q&&q.m(n,null),s(n,D),s(n,A),w(L,E,B),Q(Y,L,B),R=!0,U||(H=[K(v,"input",t[4]),K($,"change",t[5]),K(n,"submit",Ms(t[3]))],U=!0)},p(L,[B]){B&1&&v.value!==L[0].hostname&&V(v,L[0].hostname),B&2&&($.checked=L[1]),L[1]?z?(z.p(L,B),B&2&&P(z,1)):(z=Jf(L),z.c(),P(z,1),z.m(T,null)):z&&(Ae(),I(z,1,1,()=>{z=null}),Ee()),L[1]?q||(q=xf(),q.c(),q.m(n,D)):q&&(q.d(1),q=null);const O={};B&4&&(O.active=L[2]),Y.$set(O)},i(L){R||(P(z),P(Y.$$.fragment,L),R=!0)},o(L){I(z),I(Y.$$.fragment,L),R=!1},d(L){L&&k(e),z&&z.d(),q&&q.d(),L&&k(E),X(Y,L),U=!1,Be(H)}}}function O0(t,e,l){let{sysinfo:n={}}=e,i=!1,o=!1,r=0;function a(){var _="";r++;var b=function(){setTimeout(a,1e3)};if(n.net.ip&&r%3==0){if(!n.net.ip){b();return}_="http://"+n.net.ip}else n.hostname&&r%3==1?_="http://"+n.hostname:n.hostname&&r%3==2?_="http://"+n.hostname+".local":_="";console&&console.log("Trying url "+_),Ht.update(v=>(v.trying=_,v));var d=new XMLHttpRequest;d.timeout=5e3,d.addEventListener("abort",b),d.addEventListener("error",b),d.addEventListener("timeout",b),d.addEventListener("load",function(v){window.location.href=_||"/"}),d.open("GET",_+"/is-alive",!0),d.send()}async function c(_){l(2,o=!0);const b=new FormData(_.target),d=new URLSearchParams;for(let T of b){const[C,$]=T;d.append(C,$)}let g=await(await fetch("/save",{method:"POST",body:d})).json();l(2,o=!1),Ht.update(T=>(T.hostname=b.get("sh"),T.usrcfg=g.success,T.booting=g.reboot,i&&(T.net.ip=b.get("si"),T.net.mask=b.get("su"),T.net.gw=b.get("sg"),T.net.dns1=b.get("sd")),setTimeout(a,5e3),T))}function f(){n.hostname=this.value,l(0,n)}function p(){i=this.checked,l(1,i)}return t.$$set=_=>{"sysinfo"in _&&l(0,n=_.sysinfo)},[n,i,o,c,f,p]}class q0 extends Me{constructor(e){super(),Se(this,e,O0,L0,we,{sysinfo:0})}}function U0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C;return v=new Et({props:{active:t[2],message:"Uploading file, please wait"}}),{c(){e=m("div"),l=m("div"),n=m("strong"),i=y("Upload "),o=y(t[1]),r=h(),a=m("p"),a.textContent="Select a suitable file and click upload",c=h(),f=m("form"),p=m("input"),_=h(),b=m("div"),b.innerHTML='',d=h(),Z(v.$$.fragment),u(a,"class","mb-4"),u(p,"name","file"),u(p,"type","file"),u(b,"class","w-full text-right mt-4"),u(f,"action",t[0]),u(f,"enctype","multipart/form-data"),u(f,"method","post"),u(f,"autocomplete","off"),u(l,"class","cnt"),u(e,"class","grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2")},m($,M){w($,e,M),s(e,l),s(l,n),s(n,i),s(n,o),s(l,r),s(l,a),s(l,c),s(l,f),s(f,p),s(f,_),s(f,b),w($,d,M),Q(v,$,M),g=!0,T||(C=K(f,"submit",t[3]),T=!0)},p($,[M]){(!g||M&2)&&W(o,$[1]),(!g||M&1)&&u(f,"action",$[0]);const F={};M&4&&(F.active=$[2]),v.$set(F)},i($){g||(P(v.$$.fragment,$),g=!0)},o($){I(v.$$.fragment,$),g=!1},d($){$&&k(e),$&&k(d),X(v,$),T=!1,C()}}}function H0(t,e,l){let{action:n}=e,{title:i}=e,o=!1;const r=()=>l(2,o=!0);return t.$$set=a=>{"action"in a&&l(0,n=a.action),"title"in a&&l(1,i=a.title)},[n,i,o,r]}class Po extends Me{constructor(e){super(),Se(this,e,H0,U0,we,{action:0,title:1})}}function j0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F,S,D,A,E,Y,R,U,H,z,q,L;return H=new Et({props:{active:t[1],message:"Saving preferences"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("div"),i.textContent="Various permissions we need to do stuff:",o=h(),r=m("hr"),a=h(),c=m("div"),f=y("Enable one-click upgrade? (implies data collection)"),p=m("br"),_=h(),b=m("a"),d=y("Read more"),v=m("br"),g=h(),T=m("label"),C=m("input"),M=y(" Yes"),F=m("label"),S=m("input"),A=y(" No"),E=m("br"),Y=h(),R=m("div"),R.innerHTML='',U=h(),Z(H.$$.fragment),u(b,"href",Ut("Data-collection-on-one-click-firmware-upgrade")),u(b,"target","_blank"),u(b,"class","text-blue-600 hover:text-blue-800"),u(C,"type","radio"),u(C,"name","sf"),C.value=1,C.checked=$=t[0].fwconsent===1,u(C,"class","rounded m-2"),C.required=!0,u(S,"type","radio"),u(S,"name","sf"),S.value=2,S.checked=D=t[0].fwconsent===2,u(S,"class","rounded m-2"),S.required=!0,u(c,"class","my-3"),u(R,"class","my-3"),u(n,"autocomplete","off"),u(l,"class","cnt"),u(e,"class","grid xl:grid-cols-3 lg:grid-cols-2")},m(B,O){w(B,e,O),s(e,l),s(l,n),s(n,i),s(n,o),s(n,r),s(n,a),s(n,c),s(c,f),s(c,p),s(c,_),s(c,b),s(b,d),s(c,v),s(c,g),s(c,T),s(T,C),s(T,M),s(c,F),s(F,S),s(F,A),s(c,E),s(n,Y),s(n,R),w(B,U,O),Q(H,B,O),z=!0,q||(L=K(n,"submit",Ms(t[2])),q=!0)},p(B,[O]){(!z||O&1&&$!==($=B[0].fwconsent===1))&&(C.checked=$),(!z||O&1&&D!==(D=B[0].fwconsent===2))&&(S.checked=D);const j={};O&2&&(j.active=B[1]),H.$set(j)},i(B){z||(P(H.$$.fragment,B),z=!0)},o(B){I(H.$$.fragment,B),z=!1},d(B){B&&k(e),B&&k(U),X(H,B),q=!1,L()}}}function W0(t,e,l){let{sysinfo:n={}}=e,i=!1;async function o(r){l(1,i=!0);const a=new FormData(r.target),c=new URLSearchParams;for(let _ of a){const[b,d]=_;c.append(b,d)}let p=await(await fetch("/save",{method:"POST",body:c})).json();l(1,i=!1),Ht.update(_=>(_.fwconsent=a.sf===!0?1:a.sf===!1?2:0,_.booting=p.reboot,_)),oi("/")}return t.$$set=r=>{"sysinfo"in r&&l(0,n=r.sysinfo)},[n,i,o]}class G0 extends Me{constructor(e){super(),Se(this,e,W0,j0,we,{sysinfo:0})}}function B0(t){let e,l;return e=new Up({props:{data:t[1],sysinfo:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&2&&(o.data=n[1]),i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function z0(t){let e,l;return e=new h0({props:{sysinfo:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function Y0(t){let e,l;return e=new N0({props:{sysinfo:t[0],data:t[1]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),i&2&&(o.data=n[1]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function K0(t){let e,l;return e=new Po({props:{title:"CA",action:"/mqtt-ca"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function V0(t){let e,l;return e=new Po({props:{title:"certificate",action:"/mqtt-cert"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function Q0(t){let e,l;return e=new Po({props:{title:"private key",action:"/mqtt-key"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function X0(t){let e,l;return e=new G0({props:{sysinfo:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function Z0(t){let e,l;return e=new q0({props:{sysinfo:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function J0(t){let e,l;return e=new R0({props:{sysinfo:t[0]}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function x0(t){let e,l,n,i,o,r,a,c,f,p,_,b,d,v,g,T,C,$,M,F;return e=new xm({props:{data:t[1]}}),n=new Tl({props:{path:"/",$$slots:{default:[B0]},$$scope:{ctx:t}}}),o=new Tl({props:{path:"/configuration",$$slots:{default:[z0]},$$scope:{ctx:t}}}),a=new Tl({props:{path:"/status",$$slots:{default:[Y0]},$$scope:{ctx:t}}}),f=new Tl({props:{path:"/mqtt-ca",$$slots:{default:[K0]},$$scope:{ctx:t}}}),_=new Tl({props:{path:"/mqtt-cert",$$slots:{default:[V0]},$$scope:{ctx:t}}}),d=new Tl({props:{path:"/mqtt-key",$$slots:{default:[Q0]},$$scope:{ctx:t}}}),g=new Tl({props:{path:"/consent",$$slots:{default:[X0]},$$scope:{ctx:t}}}),C=new Tl({props:{path:"/setup",$$slots:{default:[Z0]},$$scope:{ctx:t}}}),M=new Tl({props:{path:"/vendor",$$slots:{default:[J0]},$$scope:{ctx:t}}}),{c(){Z(e.$$.fragment),l=h(),Z(n.$$.fragment),i=h(),Z(o.$$.fragment),r=h(),Z(a.$$.fragment),c=h(),Z(f.$$.fragment),p=h(),Z(_.$$.fragment),b=h(),Z(d.$$.fragment),v=h(),Z(g.$$.fragment),T=h(),Z(C.$$.fragment),$=h(),Z(M.$$.fragment)},m(S,D){Q(e,S,D),w(S,l,D),Q(n,S,D),w(S,i,D),Q(o,S,D),w(S,r,D),Q(a,S,D),w(S,c,D),Q(f,S,D),w(S,p,D),Q(_,S,D),w(S,b,D),Q(d,S,D),w(S,v,D),Q(g,S,D),w(S,T,D),Q(C,S,D),w(S,$,D),Q(M,S,D),F=!0},p(S,D){const A={};D&2&&(A.data=S[1]),e.$set(A);const E={};D&7&&(E.$$scope={dirty:D,ctx:S}),n.$set(E);const Y={};D&5&&(Y.$$scope={dirty:D,ctx:S}),o.$set(Y);const R={};D&7&&(R.$$scope={dirty:D,ctx:S}),a.$set(R);const U={};D&4&&(U.$$scope={dirty:D,ctx:S}),f.$set(U);const H={};D&4&&(H.$$scope={dirty:D,ctx:S}),_.$set(H);const z={};D&4&&(z.$$scope={dirty:D,ctx:S}),d.$set(z);const q={};D&5&&(q.$$scope={dirty:D,ctx:S}),g.$set(q);const L={};D&5&&(L.$$scope={dirty:D,ctx:S}),C.$set(L);const B={};D&5&&(B.$$scope={dirty:D,ctx:S}),M.$set(B)},i(S){F||(P(e.$$.fragment,S),P(n.$$.fragment,S),P(o.$$.fragment,S),P(a.$$.fragment,S),P(f.$$.fragment,S),P(_.$$.fragment,S),P(d.$$.fragment,S),P(g.$$.fragment,S),P(C.$$.fragment,S),P(M.$$.fragment,S),F=!0)},o(S){I(e.$$.fragment,S),I(n.$$.fragment,S),I(o.$$.fragment,S),I(a.$$.fragment,S),I(f.$$.fragment,S),I(_.$$.fragment,S),I(d.$$.fragment,S),I(g.$$.fragment,S),I(C.$$.fragment,S),I(M.$$.fragment,S),F=!1},d(S){X(e,S),S&&k(l),X(n,S),S&&k(i),X(o,S),S&&k(r),X(a,S),S&&k(c),X(f,S),S&&k(p),X(_,S),S&&k(b),X(d,S),S&&k(v),X(g,S),S&&k(T),X(C,S),S&&k($),X(M,S)}}}function e_(t){let e,l,n,i;const o=[n_,l_],r=[];function a(c,f){return c[0].trying?0:1}return e=a(t),l=r[e]=o[e](t),{c(){l.c(),n=Ke()},m(c,f){r[e].m(c,f),w(c,n,f),i=!0},p(c,f){let p=e;e=a(c),e===p?r[e].p(c,f):(Ae(),I(r[p],1,1,()=>{r[p]=null}),Ee(),l=r[e],l?l.p(c,f):(l=r[e]=o[e](c),l.c()),P(l,1),l.m(n.parentNode,n))},i(c){i||(P(l),i=!0)},o(c){I(l),i=!1},d(c){r[e].d(c),c&&k(n)}}}function t_(t){let e,l;return e=new Et({props:{active:"true",message:"Device is upgrading, please wait"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function l_(t){let e,l;return e=new Et({props:{active:"true",message:"Device is booting, please wait"}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p:ne,i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function n_(t){let e,l;return e=new Et({props:{active:"true",message:"Device is booting, please wait. Trying to reach it on "+t[0].trying}}),{c(){Z(e.$$.fragment)},m(n,i){Q(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.message="Device is booting, please wait. Trying to reach it on "+n[0].trying),e.$set(o)},i(n){l||(P(e.$$.fragment,n),l=!0)},o(n){I(e.$$.fragment,n),l=!1},d(n){X(e,n)}}}function i_(t){let e,l,n,i,o,r;l=new Mc({props:{$$slots:{default:[x0]},$$scope:{ctx:t}}});const a=[t_,e_],c=[];function f(p,_){return p[0].upgrading?0:p[0].booting?1:-1}return~(i=f(t))&&(o=c[i]=a[i](t)),{c(){e=m("div"),Z(l.$$.fragment),n=h(),o&&o.c(),u(e,"class","container mx-auto m-3")},m(p,_){w(p,e,_),Q(l,e,null),s(e,n),~i&&c[i].m(e,null),r=!0},p(p,[_]){const b={};_&7&&(b.$$scope={dirty:_,ctx:p}),l.$set(b);let d=i;i=f(p),i===d?~i&&c[i].p(p,_):(o&&(Ae(),I(c[d],1,1,()=>{c[d]=null}),Ee()),~i?(o=c[i],o?o.p(p,_):(o=c[i]=a[i](p),o.c()),P(o,1),o.m(e,null)):o=null)},i(p){r||(P(l.$$.fragment,p),P(o),r=!0)},o(p){I(l.$$.fragment,p),I(o),r=!1},d(p){p&&k(e),X(l),~i&&c[i].d()}}}function s_(t,e,l){let n={};Ht.subscribe(o=>{l(0,n=o),n.vndcfg===!1?oi("/vendor"):n.usrcfg===!1?oi("/setup"):n.fwconsent===0&&oi("/consent")}),yo();let i={};return wm.subscribe(o=>{l(1,i=o)}),[n,i]}class o_ extends Me{constructor(e){super(),Se(this,e,s_,i_,we,{})}}new o_({target:document.getElementById("app")}); +
`,r(e,"class","my-3 flex")},m(l,n){C(l,e,n)},d(l){l&&w(e)}}}function Qp(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z,Z,V,j=t[0].if&&t[0].if.eth&&Zf(),ee=(t[2]==1||t[2]==2)&&Jf(t),ue=t[1]&&xf(t),x=t[1]&&ec();return Q=new jt({props:{active:t[3],message:"Saving your configuration to the device"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("input"),o=b(),u=m("strong"),u.textContent="Setup",a=b(),c=m("div"),f=T("Connection"),p=m("br"),_=b(),h=m("select"),d=m("option"),d.textContent="Connect to WiFi",v=m("option"),v.textContent="Standalone access point",j&&j.c(),g=b(),ee&&ee.c(),E=b(),$=m("div"),M=T(`Hostname + `),P=m("input"),F=b(),A=m("div"),I=m("label"),D=m("input"),L=T(" Static IP"),ie=b(),ue&&ue.c(),H=b(),x&&x.c(),K=b(),G=m("div"),G.innerHTML='',Y=b(),re(Q.$$.fragment),r(i,"type","hidden"),r(i,"name","s"),i.value="true",r(u,"class","text-sm"),d.__value=1,d.value=d.__value,v.__value=2,v.value=v.__value,r(h,"name","sc"),r(h,"class","in-s"),t[2]===void 0&&Ke(()=>t[5].call(h)),r(c,"class","my-3"),r(P,"name","sh"),r(P,"type","text"),r(P,"class","in-s"),r(P,"maxlength","32"),r(P,"pattern","[a-z0-9_-]+"),r(P,"placeholder","Optional, ex.: ams-reader"),r(P,"autocomplete","off"),r(D,"type","checkbox"),r(D,"name","sm"),D.__value="static",D.value=D.__value,r(D,"class","rounded mb-1"),r(A,"class","my-3"),r(G,"class","my-3"),r(l,"class","cnt"),r(e,"class","grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2")},m(W,U){C(W,e,U),s(e,l),s(l,n),s(n,i),s(n,o),s(n,u),s(n,a),s(n,c),s(c,f),s(c,p),s(c,_),s(c,h),s(h,d),s(h,v),j&&j.m(h,null),Se(h,t[2],!0),s(n,g),ee&&ee.m(n,null),s(n,E),s(n,$),s($,M),s($,P),ne(P,t[0].hostname),s(n,F),s(n,A),s(A,I),s(I,D),D.checked=t[1],s(I,L),s(A,ie),ue&&ue.m(A,null),s(n,H),x&&x.m(n,null),s(n,K),s(n,G),C(W,Y,U),se(Q,W,U),z=!0,Z||(V=[le(h,"change",t[5]),le(P,"input",t[6]),le(D,"change",t[7]),le(n,"submit",Ms(t[4]))],Z=!0)},p(W,[U]){W[0].if&&W[0].if.eth?j||(j=Zf(),j.c(),j.m(h,null)):j&&(j.d(1),j=null),U&4&&Se(h,W[2]),W[2]==1||W[2]==2?ee?ee.p(W,U):(ee=Jf(W),ee.c(),ee.m(n,E)):ee&&(ee.d(1),ee=null),U&1&&P.value!==W[0].hostname&&ne(P,W[0].hostname),U&2&&(D.checked=W[1]),W[1]?ue?(ue.p(W,U),U&2&&O(ue,1)):(ue=xf(W),ue.c(),O(ue,1),ue.m(A,null)):ue&&(Ie(),B(ue,1,1,()=>{ue=null}),Oe()),W[1]?x||(x=ec(),x.c(),x.m(n,K)):x&&(x.d(1),x=null);const ke={};U&8&&(ke.active=W[3]),Q.$set(ke)},i(W){z||(O(ue),O(Q.$$.fragment,W),z=!0)},o(W){B(ue),B(Q.$$.fragment,W),z=!1},d(W){W&&w(e),j&&j.d(),ee&&ee.d(),ue&&ue.d(),x&&x.d(),W&&w(Y),oe(Q,W),Z=!1,Ge(V)}}}function Xp(t,e,l){let{sysinfo:n={}}=e,i=!1,o=1,u=!1,a=0;function c(){var d="";a++;var v=function(){setTimeout(c,1e3)};if(n.net.ip&&a%3==0){if(!n.net.ip){v();return}d="http://"+n.net.ip}else n.hostname&&a%3==1?d="http://"+n.hostname:n.hostname&&a%3==2?d="http://"+n.hostname+".local":d="";console&&console.log("Trying url "+d),Yt.update(E=>(E.trying=d,E));var g=new XMLHttpRequest;g.timeout=5e3,g.addEventListener("abort",v),g.addEventListener("error",v),g.addEventListener("timeout",v),g.addEventListener("load",function(E){window.location.href=d||"/"}),g.open("GET",d+"/is-alive",!0),g.send()}async function f(d){l(3,u=!0);const v=new FormData(d.target),g=new URLSearchParams;for(let M of v){const[P,F]=M;g.append(P,F)}let $=await(await fetch("/save",{method:"POST",body:g})).json();l(3,u=!1),Yt.update(M=>(M.hostname=v.get("sh"),M.usrcfg=$.success,M.booting=$.reboot,i&&(M.net.ip=v.get("si"),M.net.mask=v.get("su"),M.net.gw=v.get("sg"),M.net.dns1=v.get("sd")),setTimeout(c,5e3),M))}function p(){o=nt(this),l(2,o)}function _(){n.hostname=this.value,l(0,n)}function h(){i=this.checked,l(1,i)}return t.$$set=d=>{"sysinfo"in d&&l(0,n=d.sysinfo)},[n,i,o,u,f,p,_,h]}class Zp extends De{constructor(e){super(),Pe(this,e,Xp,Qp,$e,{sysinfo:0})}}function Jp(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$;return v=new jt({props:{active:t[2],message:"Uploading file, please wait"}}),{c(){e=m("div"),l=m("div"),n=m("strong"),i=T("Upload "),o=T(t[1]),u=b(),a=m("p"),a.textContent="Select a suitable file and click upload",c=b(),f=m("form"),p=m("input"),_=b(),h=m("div"),h.innerHTML='',d=b(),re(v.$$.fragment),r(a,"class","mb-4"),r(p,"name","file"),r(p,"type","file"),r(h,"class","w-full text-right mt-4"),r(f,"action",t[0]),r(f,"enctype","multipart/form-data"),r(f,"method","post"),r(f,"autocomplete","off"),r(l,"class","cnt"),r(e,"class","grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2")},m(M,P){C(M,e,P),s(e,l),s(l,n),s(n,i),s(n,o),s(l,u),s(l,a),s(l,c),s(l,f),s(f,p),s(f,_),s(f,h),C(M,d,P),se(v,M,P),g=!0,E||($=le(f,"submit",t[3]),E=!0)},p(M,[P]){(!g||P&2)&&X(o,M[1]),(!g||P&1)&&r(f,"action",M[0]);const F={};P&4&&(F.active=M[2]),v.$set(F)},i(M){g||(O(v.$$.fragment,M),g=!0)},o(M){B(v.$$.fragment,M),g=!1},d(M){M&&w(e),M&&w(d),oe(v,M),E=!1,$()}}}function xp(t,e,l){let{action:n}=e,{title:i}=e,o=!1;const u=()=>l(2,o=!0);return t.$$set=a=>{"action"in a&&l(0,n=a.action),"title"in a&&l(1,i=a.title)},[n,i,o,u]}class No extends De{constructor(e){super(),Pe(this,e,xp,Jp,$e,{action:0,title:1})}}function e_(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F,A,I,D,L,ie,H,K,G,Y,Q,z;return G=new jt({props:{active:t[1],message:"Saving preferences"}}),{c(){e=m("div"),l=m("div"),n=m("form"),i=m("div"),i.textContent="Various permissions we need to do stuff:",o=b(),u=m("hr"),a=b(),c=m("div"),f=T("Enable one-click upgrade? (implies data collection)"),p=m("br"),_=b(),h=m("a"),d=T("Read more"),v=m("br"),g=b(),E=m("label"),$=m("input"),P=T(" Yes"),F=m("label"),A=m("input"),D=T(" No"),L=m("br"),ie=b(),H=m("div"),H.innerHTML='',K=b(),re(G.$$.fragment),r(h,"href",Ut("Data-collection-on-one-click-firmware-upgrade")),r(h,"target","_blank"),r(h,"class","text-blue-600 hover:text-blue-800"),r($,"type","radio"),r($,"name","sf"),$.value=1,$.checked=M=t[0].fwconsent===1,r($,"class","rounded m-2"),$.required=!0,r(A,"type","radio"),r(A,"name","sf"),A.value=2,A.checked=I=t[0].fwconsent===2,r(A,"class","rounded m-2"),A.required=!0,r(c,"class","my-3"),r(H,"class","my-3"),r(n,"autocomplete","off"),r(l,"class","cnt"),r(e,"class","grid xl:grid-cols-3 lg:grid-cols-2")},m(Z,V){C(Z,e,V),s(e,l),s(l,n),s(n,i),s(n,o),s(n,u),s(n,a),s(n,c),s(c,f),s(c,p),s(c,_),s(c,h),s(h,d),s(c,v),s(c,g),s(c,E),s(E,$),s(E,P),s(c,F),s(F,A),s(F,D),s(c,L),s(n,ie),s(n,H),C(Z,K,V),se(G,Z,V),Y=!0,Q||(z=le(n,"submit",Ms(t[2])),Q=!0)},p(Z,[V]){(!Y||V&1&&M!==(M=Z[0].fwconsent===1))&&($.checked=M),(!Y||V&1&&I!==(I=Z[0].fwconsent===2))&&(A.checked=I);const j={};V&2&&(j.active=Z[1]),G.$set(j)},i(Z){Y||(O(G.$$.fragment,Z),Y=!0)},o(Z){B(G.$$.fragment,Z),Y=!1},d(Z){Z&&w(e),Z&&w(K),oe(G,Z),Q=!1,z()}}}function t_(t,e,l){let{sysinfo:n={}}=e,i=!1;async function o(u){l(1,i=!0);const a=new FormData(u.target),c=new URLSearchParams;for(let _ of a){const[h,d]=_;c.append(h,d)}let p=await(await fetch("/save",{method:"POST",body:c})).json();l(1,i=!1),Yt.update(_=>(_.fwconsent=a.sf===!0?1:a.sf===!1?2:0,_.booting=p.reboot,_)),si("/")}return t.$$set=u=>{"sysinfo"in u&&l(0,n=u.sysinfo)},[n,i,o]}class l_ extends De{constructor(e){super(),Pe(this,e,t_,e_,$e,{sysinfo:0})}}function n_(t){let e,l;return e=new Gm({props:{data:t[1],sysinfo:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&2&&(o.data=n[1]),i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function i_(t){let e,l;return e=new Ep({props:{sysinfo:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function s_(t){let e,l;return e=new Hp({props:{sysinfo:t[0],data:t[1]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),i&2&&(o.data=n[1]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function o_(t){let e,l;return e=new No({props:{title:"CA",action:"/mqtt-ca"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function r_(t){let e,l;return e=new No({props:{title:"certificate",action:"/mqtt-cert"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function a_(t){let e,l;return e=new No({props:{title:"private key",action:"/mqtt-key"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function u_(t){let e,l;return e=new l_({props:{sysinfo:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function f_(t){let e,l;return e=new Zp({props:{sysinfo:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function c_(t){let e,l;return e=new Yp({props:{sysinfo:t[0]}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.sysinfo=n[0]),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function m_(t){let e,l,n,i,o,u,a,c,f,p,_,h,d,v,g,E,$,M,P,F;return e=new tm({props:{data:t[1]}}),n=new Sl({props:{path:"/",$$slots:{default:[n_]},$$scope:{ctx:t}}}),o=new Sl({props:{path:"/configuration",$$slots:{default:[i_]},$$scope:{ctx:t}}}),a=new Sl({props:{path:"/status",$$slots:{default:[s_]},$$scope:{ctx:t}}}),f=new Sl({props:{path:"/mqtt-ca",$$slots:{default:[o_]},$$scope:{ctx:t}}}),_=new Sl({props:{path:"/mqtt-cert",$$slots:{default:[r_]},$$scope:{ctx:t}}}),d=new Sl({props:{path:"/mqtt-key",$$slots:{default:[a_]},$$scope:{ctx:t}}}),g=new Sl({props:{path:"/consent",$$slots:{default:[u_]},$$scope:{ctx:t}}}),$=new Sl({props:{path:"/setup",$$slots:{default:[f_]},$$scope:{ctx:t}}}),P=new Sl({props:{path:"/vendor",$$slots:{default:[c_]},$$scope:{ctx:t}}}),{c(){re(e.$$.fragment),l=b(),re(n.$$.fragment),i=b(),re(o.$$.fragment),u=b(),re(a.$$.fragment),c=b(),re(f.$$.fragment),p=b(),re(_.$$.fragment),h=b(),re(d.$$.fragment),v=b(),re(g.$$.fragment),E=b(),re($.$$.fragment),M=b(),re(P.$$.fragment)},m(A,I){se(e,A,I),C(A,l,I),se(n,A,I),C(A,i,I),se(o,A,I),C(A,u,I),se(a,A,I),C(A,c,I),se(f,A,I),C(A,p,I),se(_,A,I),C(A,h,I),se(d,A,I),C(A,v,I),se(g,A,I),C(A,E,I),se($,A,I),C(A,M,I),se(P,A,I),F=!0},p(A,I){const D={};I&2&&(D.data=A[1]),e.$set(D);const L={};I&7&&(L.$$scope={dirty:I,ctx:A}),n.$set(L);const ie={};I&5&&(ie.$$scope={dirty:I,ctx:A}),o.$set(ie);const H={};I&7&&(H.$$scope={dirty:I,ctx:A}),a.$set(H);const K={};I&4&&(K.$$scope={dirty:I,ctx:A}),f.$set(K);const G={};I&4&&(G.$$scope={dirty:I,ctx:A}),_.$set(G);const Y={};I&4&&(Y.$$scope={dirty:I,ctx:A}),d.$set(Y);const Q={};I&5&&(Q.$$scope={dirty:I,ctx:A}),g.$set(Q);const z={};I&5&&(z.$$scope={dirty:I,ctx:A}),$.$set(z);const Z={};I&5&&(Z.$$scope={dirty:I,ctx:A}),P.$set(Z)},i(A){F||(O(e.$$.fragment,A),O(n.$$.fragment,A),O(o.$$.fragment,A),O(a.$$.fragment,A),O(f.$$.fragment,A),O(_.$$.fragment,A),O(d.$$.fragment,A),O(g.$$.fragment,A),O($.$$.fragment,A),O(P.$$.fragment,A),F=!0)},o(A){B(e.$$.fragment,A),B(n.$$.fragment,A),B(o.$$.fragment,A),B(a.$$.fragment,A),B(f.$$.fragment,A),B(_.$$.fragment,A),B(d.$$.fragment,A),B(g.$$.fragment,A),B($.$$.fragment,A),B(P.$$.fragment,A),F=!1},d(A){oe(e,A),A&&w(l),oe(n,A),A&&w(i),oe(o,A),A&&w(u),oe(a,A),A&&w(c),oe(f,A),A&&w(p),oe(_,A),A&&w(h),oe(d,A),A&&w(v),oe(g,A),A&&w(E),oe($,A),A&&w(M),oe(P,A)}}}function p_(t){let e,l,n,i;const o=[v_,d_],u=[];function a(c,f){return c[0].trying?0:1}return e=a(t),l=u[e]=o[e](t),{c(){l.c(),n=Ve()},m(c,f){u[e].m(c,f),C(c,n,f),i=!0},p(c,f){let p=e;e=a(c),e===p?u[e].p(c,f):(Ie(),B(u[p],1,1,()=>{u[p]=null}),Oe(),l=u[e],l?l.p(c,f):(l=u[e]=o[e](c),l.c()),O(l,1),l.m(n.parentNode,n))},i(c){i||(O(l),i=!0)},o(c){B(l),i=!1},d(c){u[e].d(c),c&&w(n)}}}function __(t){let e,l;return e=new jt({props:{active:"true",message:"Device is upgrading, please wait"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function d_(t){let e,l;return e=new jt({props:{active:"true",message:"Device is booting, please wait"}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p:_e,i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function v_(t){let e,l;return e=new jt({props:{active:"true",message:"Device is booting, please wait. Trying to reach it on "+t[0].trying}}),{c(){re(e.$$.fragment)},m(n,i){se(e,n,i),l=!0},p(n,i){const o={};i&1&&(o.message="Device is booting, please wait. Trying to reach it on "+n[0].trying),e.$set(o)},i(n){l||(O(e.$$.fragment,n),l=!0)},o(n){B(e.$$.fragment,n),l=!1},d(n){oe(e,n)}}}function h_(t){let e,l,n,i,o,u,a;n=new Ec({props:{$$slots:{default:[m_]},$$scope:{ctx:t}}});const c=[__,p_],f=[];function p(_,h){return _[0].upgrading?0:_[0].booting?1:-1}return~(o=p(t))&&(u=f[o]=c[o](t)),{c(){e=T(`/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + + + +`),l=m("div"),re(n.$$.fragment),i=b(),u&&u.c(),r(l,"class","container mx-auto m-3")},m(_,h){C(_,e,h),C(_,l,h),se(n,l,null),s(l,i),~o&&f[o].m(l,null),a=!0},p(_,[h]){const d={};h&7&&(d.$$scope={dirty:h,ctx:_}),n.$set(d);let v=o;o=p(_),o===v?~o&&f[o].p(_,h):(u&&(Ie(),B(f[v],1,1,()=>{f[v]=null}),Oe()),~o?(u=f[o],u?u.p(_,h):(u=f[o]=c[o](_),u.c()),O(u,1),u.m(l,null)):u=null)},i(_){a||(O(n.$$.fragment,_),O(u),a=!0)},o(_){B(n.$$.fragment,_),B(u),a=!1},d(_){_&&w(e),_&&w(l),oe(n),~o&&f[o].d()}}}function b_(t,e,l){let n={};Yt.subscribe(o=>{l(0,n=o),n.vndcfg===!1?si("/vendor"):n.usrcfg===!1?si("/setup"):n.fwconsent===0&&si("/consent"),n.ui.k===1?(console.log("dark"),document.documentElement.classList.add("dark")):n.ui.k===0?(console.log("light"),document.documentElement.classList.remove("dark")):window.matchMedia("(prefers-color-scheme: dark)").matches?(console.log("dark auto"),document.documentElement.classList.add("dark")):(console.log("light auto"),document.documentElement.classList.remove("dark"))}),yo();let i={};return Lc.subscribe(o=>{l(1,i=o)}),[n,i]}class g_ extends De{constructor(e){super(),Pe(this,e,b_,h_,$e,{})}}new g_({target:document.getElementById("app")}); diff --git a/lib/SvelteUi/app/index.html b/lib/SvelteUi/app/index.html index b1a58959..90da4e7b 100644 --- a/lib/SvelteUi/app/index.html +++ b/lib/SvelteUi/app/index.html @@ -7,7 +7,7 @@ AMS reader - +
diff --git a/lib/SvelteUi/app/package-lock.json b/lib/SvelteUi/app/package-lock.json index e4c930cd..767f7b29 100644 --- a/lib/SvelteUi/app/package-lock.json +++ b/lib/SvelteUi/app/package-lock.json @@ -8,20 +8,21 @@ "name": "svelte-gui", "version": "0.0.0", "dependencies": { - "cssnano": "^5.1.14" + "cssnano": "^5.1.15" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^1.0.1", - "@tailwindcss/forms": "^0.5.2", - "autoprefixer": "^10.4.7", - "http-proxy-middleware": "^2.0.1", + "@sveltejs/vite-plugin-svelte": "^2.1.0", + "@tailwindcss/forms": "^0.5.3", + "autoprefixer": "^10.4.14", + "http-proxy-middleware": "^2.0.6", "postcss": "^8.4.31", "postcss-load-config": "^4.0.1", - "svelte": "^3.49.0", + "svelte": "^3.58.0", "svelte-navigator": "^3.2.2", - "svelte-preprocess": "^4.10.7", - "tailwindcss": "^3.1.5", - "vite": "^3.2.7" + "svelte-preprocess": "^5.0.3", + "svelte-qrcode": "^1.0.0", + "tailwindcss": "^3.3.1", + "vite": "^4.3.1" } }, "node_modules/@alloc/quick-lru": { @@ -37,9 +38,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -52,10 +53,154 @@ "node": ">=12" } }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -68,6 +213,182 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -83,9 +404,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -107,21 +428,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -158,30 +473,48 @@ } }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.4.0.tgz", - "integrity": "sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz", + "integrity": "sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==", "dev": true, "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4", "debug": "^4.3.4", - "deepmerge": "^4.2.2", + "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.26.7", - "svelte-hmr": "^0.15.1", - "vitefu": "^0.2.2" + "magic-string": "^0.30.3", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.4" }, "engines": { "node": "^14.18.0 || >= 16" }, "peerDependencies": { - "svelte": "^3.44.0", - "vite": "^3.0.0" + "svelte": "^3.54.0 || ^4.0.0", + "vite": "^4.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz", + "integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^14.18.0 || >= 16" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^2.2.0", + "svelte": "^3.54.0 || ^4.0.0", + "vite": "^4.0.0" } }, "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz", + "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==", "dev": true, "dependencies": { "mini-svg-data-uri": "^1.2.3" @@ -199,36 +532,29 @@ } }, "node_modules/@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.13", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.13.tgz", + "integrity": "sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", - "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==", - "dev": true - }, - "node_modules/@types/pug": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", - "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", - "dev": true - }, - "node_modules/@types/sass": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.45.0.tgz", - "integrity": "sha512-jn7qwGFmJHwUSphV8zZneO3GmtlgLsmhs/LQyVvQbIIa+fzGMUiHI4HXJZL3FT8MJmgXWbLGiVVY7ElvHq6vDA==", - "deprecated": "This is a stub types definition. sass provides its own type definitions, so you do not need this installed.", + "version": "20.8.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", + "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", "dev": true, "dependencies": { - "sass": "*" + "undici-types": "~5.26.4" } }, + "node_modules/@types/pug": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.8.tgz", + "integrity": "sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==", + "dev": true + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -255,9 +581,9 @@ "dev": true }, "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "dev": true, "funding": [ { @@ -267,12 +593,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -330,9 +660,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "funding": [ { "type": "opencollective", @@ -348,10 +678,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -390,9 +720,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==", + "version": "1.0.30001555", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001555.tgz", + "integrity": "sha512-NzbUFKUnJ3DTcq6YyZB6+qqhfD112uR3uoEnkmfzm2wVzUNsFkU7AwBjKQ654Sp5cau0JxhFyRSn/tQZ+XfygA==", "funding": [ { "type": "opencollective", @@ -435,6 +765,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -455,9 +797,9 @@ "dev": true }, "node_modules/css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", "engines": { "node": "^10 || ^12 || >=14" }, @@ -703,9 +1045,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.447", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.447.tgz", - "integrity": "sha512-sxX0LXh+uL41hSJsujAN86PjhrV/6c79XmpY0TvjZStV6VxIgarf8SRkUoUTuYmFcZQTemsoqo8qXOGw5npWfw==" + "version": "1.4.569", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz", + "integrity": "sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg==" }, "node_modules/entities": { "version": "2.2.0", @@ -722,9 +1064,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -734,348 +1076,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escalade": { @@ -1093,9 +1115,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1108,6 +1130,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -1130,9 +1164,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "dev": true, "funding": [ { @@ -1150,16 +1184,16 @@ } }, "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fs.realpath": { @@ -1169,9 +1203,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1183,10 +1217,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/glob": { "version": "7.2.3", @@ -1209,15 +1246,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/graceful-fs": { @@ -1226,16 +1263,16 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4" } }, "node_modules/http-proxy": { @@ -1276,12 +1313,6 @@ } } }, - "node_modules/immutable": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", - "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", - "dev": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1311,12 +1342,12 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1365,9 +1396,9 @@ } }, "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", + "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", "dev": true, "bin": { "jiti": "bin/jiti.js" @@ -1416,12 +1447,12 @@ } }, "node_modules/magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" }, "engines": { "node": ">=12" @@ -1550,9 +1581,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -1862,9 +1893,9 @@ } }, "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", "dev": true, "engines": { "node": ">= 14" @@ -2244,12 +2275,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2283,15 +2314,16 @@ } }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.18.0", + "npm": ">=8.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" @@ -2332,36 +2364,19 @@ "rimraf": "^2.5.2" } }, - "node_modules/sass": { - "version": "1.63.6", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.6.tgz", - "integrity": "sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/sorcery": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", - "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", "dev": true, "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", "buffer-crc32": "^0.2.5", "minimist": "^1.2.0", - "sander": "^0.5.0", - "sourcemap-codec": "^1.3.0" + "sander": "^0.5.0" }, "bin": { - "sorcery": "bin/index.js" + "sorcery": "bin/sorcery" } }, "node_modules/source-map": { @@ -2380,13 +2395,6 @@ "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, "node_modules/stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -2421,9 +2429,9 @@ } }, "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -2493,15 +2501,15 @@ } }, "node_modules/svelte-hmr": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz", - "integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==", + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", "dev": true, "engines": { "node": "^12.20 || ^14.13.1 || >= 16" }, "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0-next.0" + "svelte": "^3.19.0 || ^4.0.0" } }, "node_modules/svelte-navigator": { @@ -2518,21 +2526,20 @@ } }, "node_modules/svelte-preprocess": { - "version": "4.10.7", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", - "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz", + "integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@types/pug": "^2.0.4", - "@types/sass": "^1.16.0", - "detect-indent": "^6.0.0", - "magic-string": "^0.25.7", - "sorcery": "^0.10.0", + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.27.0", + "sorcery": "^0.11.0", "strip-indent": "^3.0.0" }, "engines": { - "node": ">= 9.11.2" + "node": ">= 14.10.0" }, "peerDependencies": { "@babel/core": "^7.10.2", @@ -2543,9 +2550,9 @@ "pug": "^3.0.0", "sass": "^1.26.8", "stylus": "^0.55.0", - "sugarss": "^2.0.0", - "svelte": "^3.23.0", - "typescript": "^3.9.5 || ^4.0.0" + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" }, "peerDependenciesMeta": { "@babel/core": { @@ -2557,9 +2564,6 @@ "less": { "optional": true }, - "node-sass": { - "optional": true - }, "postcss": { "optional": true }, @@ -2584,14 +2588,23 @@ } }, "node_modules/svelte-preprocess/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" } }, + "node_modules/svelte-qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-qrcode/-/svelte-qrcode-1.0.0.tgz", + "integrity": "sha512-WrOvyyxtUzu32gVIDxcFMy0A7uUpbl/8yHaTNOsUaI8W5V4wa7AmReCjffhNY2aS42CqCLJ6qdwUoj/KxmeZzA==", + "dev": true + }, "node_modules/svelte2tsx": { "version": "0.1.193", "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.1.193.tgz", @@ -2627,9 +2640,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz", + "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==", "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -2637,10 +2650,10 @@ "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -2652,7 +2665,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, @@ -2664,18 +2676,6 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2716,9 +2716,9 @@ "dev": true }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/typescript": { @@ -2735,10 +2735,16 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -2770,15 +2776,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", - "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", "dev": true, "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -2786,12 +2791,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -2804,6 +2813,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -2819,12 +2831,12 @@ } }, "node_modules/vitefu": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz", - "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", "dev": true, "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, "peerDependenciesMeta": { "vite": { @@ -2855,16 +2867,156 @@ "dev": true }, "@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "dev": true, "optional": true }, @@ -2880,9 +3032,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, "@jridgewell/set-array": { @@ -2898,21 +3050,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -2942,23 +3086,33 @@ } }, "@sveltejs/vite-plugin-svelte": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.4.0.tgz", - "integrity": "sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz", + "integrity": "sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==", "dev": true, "requires": { + "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4", "debug": "^4.3.4", - "deepmerge": "^4.2.2", + "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.26.7", - "svelte-hmr": "^0.15.1", - "vitefu": "^0.2.2" + "magic-string": "^0.30.3", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.4" + } + }, + "@sveltejs/vite-plugin-svelte-inspector": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz", + "integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==", + "dev": true, + "requires": { + "debug": "^4.3.4" } }, "@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz", + "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==", "dev": true, "requires": { "mini-svg-data-uri": "^1.2.3" @@ -2970,35 +3124,29 @@ "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, "@types/http-proxy": { - "version": "1.17.11", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", - "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "version": "1.17.13", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.13.tgz", + "integrity": "sha512-GkhdWcMNiR5QSQRYnJ+/oXzu0+7JJEPC8vkWXK351BkhjraZF+1W13CUYARUvX9+NqIU2n6YHA4iwywsc/M6Sw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", - "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==", - "dev": true - }, - "@types/pug": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", - "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", - "dev": true - }, - "@types/sass": { - "version": "1.45.0", - "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.45.0.tgz", - "integrity": "sha512-jn7qwGFmJHwUSphV8zZneO3GmtlgLsmhs/LQyVvQbIIa+fzGMUiHI4HXJZL3FT8MJmgXWbLGiVVY7ElvHq6vDA==", + "version": "20.8.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", + "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", "dev": true, "requires": { - "sass": "*" + "undici-types": "~5.26.4" } }, + "@types/pug": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.8.tgz", + "integrity": "sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==", + "dev": true + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -3022,14 +3170,14 @@ "dev": true }, "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "dev": true, "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -3072,14 +3220,14 @@ } }, "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" } }, "buffer-crc32": { @@ -3106,9 +3254,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==" + "version": "1.0.30001555", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001555.tgz", + "integrity": "sha512-NzbUFKUnJ3DTcq6YyZB6+qqhfD112uR3uoEnkmfzm2wVzUNsFkU7AwBjKQ654Sp5cau0JxhFyRSn/tQZ+XfygA==" }, "chokidar": { "version": "3.5.3", @@ -3124,6 +3272,17 @@ "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "colord": { @@ -3143,9 +3302,9 @@ "dev": true }, "css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", "requires": {} }, "css-select": { @@ -3312,9 +3471,9 @@ } }, "electron-to-chromium": { - "version": "1.4.447", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.447.tgz", - "integrity": "sha512-sxX0LXh+uL41hSJsujAN86PjhrV/6c79XmpY0TvjZStV6VxIgarf8SRkUoUTuYmFcZQTemsoqo8qXOGw5npWfw==" + "version": "1.4.569", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz", + "integrity": "sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg==" }, "entities": { "version": "2.2.0", @@ -3328,175 +3487,35 @@ "dev": true }, "esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "requires": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, - "esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "dev": true, - "optional": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3509,9 +3528,9 @@ "dev": true }, "fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3519,6 +3538,17 @@ "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "fastq": { @@ -3540,15 +3570,15 @@ } }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "dev": true }, "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true }, "fs.realpath": { @@ -3558,16 +3588,16 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "glob": { @@ -3585,12 +3615,12 @@ } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "graceful-fs": { @@ -3599,13 +3629,13 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "function-bind": "^1.1.2" } }, "http-proxy": { @@ -3632,12 +3662,6 @@ "micromatch": "^4.0.2" } }, - "immutable": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", - "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3664,12 +3688,12 @@ } }, "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "is-extglob": { @@ -3700,9 +3724,9 @@ "dev": true }, "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", + "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", "dev": true }, "kleur": { @@ -3742,12 +3766,12 @@ } }, "magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dev": true, "requires": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "mdn-data": { @@ -3840,9 +3864,9 @@ } }, "node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "normalize-path": { "version": "3.0.0", @@ -4029,9 +4053,9 @@ }, "dependencies": { "yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", "dev": true } } @@ -4261,12 +4285,12 @@ "dev": true }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -4287,9 +4311,9 @@ } }, "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -4316,27 +4340,16 @@ "rimraf": "^2.5.2" } }, - "sass": { - "version": "1.63.6", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.6.tgz", - "integrity": "sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw==", - "dev": true, - "requires": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - } - }, "sorcery": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", - "integrity": "sha512-R5ocFmKZQFfSTstfOtHjJuAwbpGyf9qjQa1egyhvXSbM7emjrtLXtGdZsDJDABC85YBfVvrOiGWKSYXPKdvP1g==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", "dev": true, "requires": { + "@jridgewell/sourcemap-codec": "^1.4.14", "buffer-crc32": "^0.2.5", "minimist": "^1.2.0", - "sander": "^0.5.0", - "sourcemap-codec": "^1.3.0" + "sander": "^0.5.0" } }, "source-map": { @@ -4349,12 +4362,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", @@ -4379,9 +4386,9 @@ } }, "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.2", @@ -4428,9 +4435,9 @@ "dev": true }, "svelte-hmr": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz", - "integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==", + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", "dev": true, "requires": {} }, @@ -4444,30 +4451,35 @@ } }, "svelte-preprocess": { - "version": "4.10.7", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.7.tgz", - "integrity": "sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz", + "integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==", "dev": true, "requires": { - "@types/pug": "^2.0.4", - "@types/sass": "^1.16.0", - "detect-indent": "^6.0.0", - "magic-string": "^0.25.7", - "sorcery": "^0.10.0", + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.27.0", + "sorcery": "^0.11.0", "strip-indent": "^3.0.0" }, "dependencies": { "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dev": true, "requires": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" } } } }, + "svelte-qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-qrcode/-/svelte-qrcode-1.0.0.tgz", + "integrity": "sha512-WrOvyyxtUzu32gVIDxcFMy0A7uUpbl/8yHaTNOsUaI8W5V4wa7AmReCjffhNY2aS42CqCLJ6qdwUoj/KxmeZzA==", + "dev": true + }, "svelte2tsx": { "version": "0.1.193", "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.1.193.tgz", @@ -4493,9 +4505,9 @@ } }, "tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz", + "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==", "dev": true, "requires": { "@alloc/quick-lru": "^5.2.0", @@ -4503,10 +4515,10 @@ "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -4518,20 +4530,8 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" - }, - "dependencies": { - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - } } }, "thenify": { @@ -4568,9 +4568,9 @@ "dev": true }, "tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "typescript": { @@ -4580,10 +4580,16 @@ "dev": true, "peer": true }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -4595,22 +4601,21 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "vite": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz", - "integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", "dev": true, "requires": { - "esbuild": "^0.15.9", + "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "vitefu": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz", - "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", "dev": true, "requires": {} }, diff --git a/lib/SvelteUi/app/package.json b/lib/SvelteUi/app/package.json index a8e0de1c..74235a64 100644 --- a/lib/SvelteUi/app/package.json +++ b/lib/SvelteUi/app/package.json @@ -5,23 +5,25 @@ "type": "module", "scripts": { "dev": "vite", + "local": "vite --config vite.config.local.js", "build": "vite build", "preview": "vite preview" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^1.0.1", - "@tailwindcss/forms": "^0.5.2", - "autoprefixer": "^10.4.7", - "http-proxy-middleware": "^2.0.1", + "@sveltejs/vite-plugin-svelte": "^2.1.0", + "@tailwindcss/forms": "^0.5.3", + "autoprefixer": "^10.4.14", + "http-proxy-middleware": "^2.0.6", "postcss": "^8.4.31", "postcss-load-config": "^4.0.1", - "svelte": "^3.49.0", + "svelte": "^3.58.0", "svelte-navigator": "^3.2.2", - "svelte-preprocess": "^4.10.7", - "tailwindcss": "^3.1.5", - "vite": "^3.2.7" + "svelte-preprocess": "^5.0.3", + "svelte-qrcode": "^1.0.0", + "tailwindcss": "^3.3.1", + "vite": "^4.3.1" }, "dependencies": { - "cssnano": "^5.1.14" + "cssnano": "^5.1.15" } } diff --git a/lib/SvelteUi/app/src/App.svelte b/lib/SvelteUi/app/src/App.svelte index 96e7a160..b74b0c83 100644 --- a/lib/SvelteUi/app/src/App.svelte +++ b/lib/SvelteUi/app/src/App.svelte @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + - + diff --git a/lib/SvelteUi/app/src/lib/RealtimePlot.svelte b/lib/SvelteUi/app/src/lib/RealtimePlot.svelte new file mode 100644 index 00000000..d50ae703 --- /dev/null +++ b/lib/SvelteUi/app/src/lib/RealtimePlot.svelte @@ -0,0 +1,145 @@ + + +
+ Realtime ({unit}) + {#if yTicks} + + + + + {#each yTicks as tick} + {#if !isNaN(yScale(tick.value))} + + + {tick.label} + + {/if} + {/each} + + + + + {#each xTicks as point, i} + {#if !isNaN(xScale(point.value))} + {#if i%Math.round(6/barWidth) == 0} + + {point.label} + + {/if} + {/if} + {/each} + + + + + + {/if} +
diff --git a/lib/SvelteUi/app/src/lib/SetupPanel.svelte b/lib/SvelteUi/app/src/lib/SetupPanel.svelte index 2dededde..a04bb6a6 100644 --- a/lib/SvelteUi/app/src/lib/SetupPanel.svelte +++ b/lib/SvelteUi/app/src/lib/SetupPanel.svelte @@ -6,6 +6,7 @@ export let sysinfo = {} let staticIp = false; + let connectionMode = 1; let loadingOrSaving = false; let tries = 0; @@ -87,13 +88,25 @@ Setup
- SSID
- -
-
- PSK
- + Connection
+
+ {#if connectionMode == 1 || connectionMode == 2} +
+ SSID
+ +
+
+ PSK
+ +
+ {/if}
Hostname diff --git a/lib/SvelteUi/app/src/lib/StatusPage.svelte b/lib/SvelteUi/app/src/lib/StatusPage.svelte index 11896cbe..e8e96a41 100644 --- a/lib/SvelteUi/app/src/lib/StatusPage.svelte +++ b/lib/SvelteUi/app/src/lib/StatusPage.svelte @@ -126,10 +126,10 @@ Manufacturer: {metertype(sysinfo.meter.mfg)}
- Model: {sysinfo.meter.model} + Model: {sysinfo.meter.model ? sysinfo.meter.model : "unknown"}
- ID: {sysinfo.meter.id} + ID: {sysinfo.meter.id ? sysinfo.meter.id : "unknown"}
{/if} diff --git a/lib/SvelteUi/app/src/main.js b/lib/SvelteUi/app/src/main.js index bc3d21d3..c030412b 100644 --- a/lib/SvelteUi/app/src/main.js +++ b/lib/SvelteUi/app/src/main.js @@ -1,7 +1,6 @@ import "./app.postcss"; import App from "./App.svelte"; - const app = new App({ target: document.getElementById("app"), }); diff --git a/lib/SvelteUi/app/tailwind.config.cjs b/lib/SvelteUi/app/tailwind.config.cjs index 122253e3..e1fd9633 100644 --- a/lib/SvelteUi/app/tailwind.config.cjs +++ b/lib/SvelteUi/app/tailwind.config.cjs @@ -8,6 +8,8 @@ const config = { plugins: [ require('@tailwindcss/forms') ], + + darkMode: 'class' }; module.exports = config; diff --git a/lib/SvelteUi/include/AmsWebHeaders.h b/lib/SvelteUi/include/AmsWebHeaders.h index 582e50ad..be9d20aa 100644 --- a/lib/SvelteUi/include/AmsWebHeaders.h +++ b/lib/SvelteUi/include/AmsWebHeaders.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + static const char HEADER_CACHE_CONTROL[] PROGMEM = "Cache-Control"; static const char HEADER_CONTENT_ENCODING[] PROGMEM = "Content-Encoding"; static const char HEADER_PRAGMA[] PROGMEM = "Pragma"; diff --git a/lib/SvelteUi/include/AmsWebServer.h b/lib/SvelteUi/include/AmsWebServer.h index db2666c3..fec93406 100644 --- a/lib/SvelteUi/include/AmsWebServer.h +++ b/lib/SvelteUi/include/AmsWebServer.h @@ -1,8 +1,14 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _AMSWEBSERVER_h #define _AMSWEBSERVER_h #include "Arduino.h" -#include +#include "AmsMqttHandler.h" #include "AmsConfiguration.h" #include "HwTools.h" #include "AmsData.h" @@ -12,6 +18,7 @@ #include "Uptime.h" #include "RemoteDebug.h" #include "EntsoeApi.h" +#include "RealtimePlot.h" #if defined(ESP8266) #include @@ -32,29 +39,34 @@ class AmsWebServer { public: AmsWebServer(uint8_t* buf, RemoteDebug* Debug, HwTools* hw); - void setup(AmsConfiguration*, GpioConfig*, MeterConfig*, AmsData*, AmsDataStorage*, EnergyAccounting*); + void setup(AmsConfiguration*, GpioConfig*, AmsData*, AmsDataStorage*, EnergyAccounting*, RealtimePlot*); void loop(); void setMqtt(MQTTClient* mqtt); void setTimezone(Timezone* tz); void setMqttEnabled(bool); void setEntsoeApi(EntsoeApi* eapi); void setPriceSettings(String region, String currency); + void setMeterConfig(uint8_t distributionSystem, uint16_t mainFuse, uint16_t productionCapacity); + void setMqttHandler(AmsMqttHandler* mqttHandler); private: RemoteDebug* debugger; bool mqttEnabled = false; int maxPwr = 0; + uint8_t distributionSystem = 0; + uint16_t mainFuse = 0, productionCapacity = 0; + HwTools* hw; Timezone* tz; EntsoeApi* eapi = NULL; AmsConfiguration* config; GpioConfig* gpioConfig; - MeterConfig* meterConfig; WebConfig webConfig; AmsData* meterState; AmsDataStorage* ds; EnergyAccounting* ea = NULL; - MQTTClient* mqtt = NULL; + RealtimePlot* rtp = NULL; + AmsMqttHandler* mqttHandler = NULL; bool uploading = false; File file; bool performRestart = false; @@ -92,6 +104,7 @@ private: void energyPriceJson(); void temperatureJson(); void tariffJson(); + void realtimeJson(); void configurationJson(); void handleSave(); diff --git a/lib/SvelteUi/json/conf_cloud.json b/lib/SvelteUi/json/conf_cloud.json new file mode 100644 index 00000000..0379bc52 --- /dev/null +++ b/lib/SvelteUi/json/conf_cloud.json @@ -0,0 +1,6 @@ +"c": { + "e" : %s, + "i" : "%s", + "s" : "%s", + "es": %s +} diff --git a/lib/SvelteUi/json/conf_gpio.json b/lib/SvelteUi/json/conf_gpio.json index 6a0bc0e9..e7d45f70 100644 --- a/lib/SvelteUi/json/conf_gpio.json +++ b/lib/SvelteUi/json/conf_gpio.json @@ -1,7 +1,8 @@ "i": { "h": { "p": %s, - "u": %s + "u": %s, + "t": %s }, "a": %s, "l": { @@ -14,6 +15,10 @@ "b": %s, "i": %s }, + "d": { + "d": %s, + "b": %d + }, "t": { "d": %s, "a": %s diff --git a/lib/SvelteUi/json/conf_ha.json b/lib/SvelteUi/json/conf_ha.json index 9ca02761..e1e5013e 100644 --- a/lib/SvelteUi/json/conf_ha.json +++ b/lib/SvelteUi/json/conf_ha.json @@ -2,4 +2,4 @@ "t" : "%s", "h" : "%s", "n" : "%s" -} +}, diff --git a/lib/SvelteUi/json/conf_meter.json b/lib/SvelteUi/json/conf_meter.json index 8c0c5974..52bfe390 100644 --- a/lib/SvelteUi/json/conf_meter.json +++ b/lib/SvelteUi/json/conf_meter.json @@ -1,4 +1,6 @@ "m": { + "o": %d, + "a": %d, "b": %d, "p": %d, "i": %s, diff --git a/lib/SvelteUi/json/conf_net.json b/lib/SvelteUi/json/conf_net.json index 4eaa1141..a1303a9f 100644 --- a/lib/SvelteUi/json/conf_net.json +++ b/lib/SvelteUi/json/conf_net.json @@ -1,4 +1,5 @@ "n": { + "c": %d, "m": "%s", "i": "%s", "s": "%s", diff --git a/lib/SvelteUi/json/conf_ui.json b/lib/SvelteUi/json/conf_ui.json index 97fd05e3..60fff2e7 100644 --- a/lib/SvelteUi/json/conf_ui.json +++ b/lib/SvelteUi/json/conf_ui.json @@ -9,5 +9,7 @@ "p": %d, "d": %d, "m": %d, - "s": %d + "s": %d, + "l": %d, + "k": %d }, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_wifi.json b/lib/SvelteUi/json/conf_wifi.json index 977a7538..81a565e6 100644 --- a/lib/SvelteUi/json/conf_wifi.json +++ b/lib/SvelteUi/json/conf_wifi.json @@ -3,6 +3,5 @@ "p": "%s", "w": %.1f, "z": %d, - "a": %s, "b": %s }, diff --git a/lib/SvelteUi/json/sysinfo.json b/lib/SvelteUi/json/sysinfo.json index a8aab8b8..151055f0 100644 --- a/lib/SvelteUi/json/sysinfo.json +++ b/lib/SvelteUi/json/sysinfo.json @@ -19,6 +19,9 @@ "dns1": "%s", "dns2": "%s" }, + "if": { + "eth": %s + }, "meter": { "mfg": %d, "model": "%s", @@ -35,7 +38,9 @@ "p": %d, "d": %d, "m": %d, - "s": %d + "s": %d, + "l": %d, + "k": %d }, "security": %d, "boot_reason": %d, diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index 5cd41f6f..51af4c87 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "AmsWebServer.h" #include "AmsWebHeaders.h" #include "FirmwareVersion.h" @@ -30,12 +36,13 @@ #include "html/conf_domoticz_json.h" #include "html/conf_ha_json.h" #include "html/conf_ui_json.h" +#include "html/conf_cloud_json.h" #include "html/firmware_html.h" #if defined(ESP32) #include #include -#include +#include #endif @@ -55,13 +62,13 @@ AmsWebServer::AmsWebServer(uint8_t* buf, RemoteDebug* Debug, HwTools* hw) { this->buf = (char*) buf; } -void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, MeterConfig* meterConfig, AmsData* meterState, AmsDataStorage* ds, EnergyAccounting* ea) { +void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, AmsData* meterState, AmsDataStorage* ds, EnergyAccounting* ea, RealtimePlot* rtp) { this->config = config; this->gpioConfig = gpioConfig; - this->meterConfig = meterConfig; this->meterState = meterState; this->ds = ds; this->ea = ea; + this->rtp = rtp; server.on(F("/"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this)); snprintf_P(buf, 32, PSTR("/index-%s.js"), FirmwareVersion::VersionString); @@ -87,6 +94,7 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter server.on(F("/energyprice.json"), HTTP_GET, std::bind(&AmsWebServer::energyPriceJson, this)); server.on(F("/temperature.json"), HTTP_GET, std::bind(&AmsWebServer::temperatureJson, this)); server.on(F("/tariff.json"), HTTP_GET, std::bind(&AmsWebServer::tariffJson, this)); + server.on(F("/realtime.json"), HTTP_GET, std::bind(&AmsWebServer::realtimeJson, this)); server.on(F("/configuration.json"), HTTP_GET, std::bind(&AmsWebServer::configurationJson, this)); server.on(F("/save"), HTTP_POST, std::bind(&AmsWebServer::handleSave, this)); @@ -124,11 +132,6 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter mqttEnabled = strlen(mqttConfig.host) > 0; } - -void AmsWebServer::setMqtt(MQTTClient* mqtt) { - this->mqtt = mqtt; -} - void AmsWebServer::setTimezone(Timezone* tz) { this->tz = tz; } @@ -136,28 +139,38 @@ void AmsWebServer::setTimezone(Timezone* tz) { void AmsWebServer::setMqttEnabled(bool enabled) { mqttEnabled = enabled; } +void AmsWebServer::setMqttHandler(AmsMqttHandler* mqttHandler) { + this->mqttHandler = mqttHandler; +} void AmsWebServer::setEntsoeApi(EntsoeApi* eapi) { this->eapi = eapi; } +void AmsWebServer::setMeterConfig(uint8_t distributionSystem, uint16_t mainFuse, uint16_t productionCapacity) { + maxPwr = 0; + this->distributionSystem = distributionSystem; + this->mainFuse = mainFuse; + this->productionCapacity = productionCapacity; +} + void AmsWebServer::loop() { server.handleClient(); - if(maxPwr == 0 && meterState->getListType() > 1 && meterConfig->mainFuse > 0 && meterConfig->distributionSystem > 0) { - int voltage = meterConfig->distributionSystem == 2 ? 400 : 230; + if(maxPwr == 0 && meterState->getListType() > 1 && mainFuse > 0 && distributionSystem > 0) { + int voltage = distributionSystem == 2 ? 400 : 230; if(meterState->isThreePhase()) { - maxPwr = meterConfig->mainFuse * sqrt(3) * voltage; + maxPwr = mainFuse * sqrt(3) * voltage; } else if(meterState->isTwoPhase()) { - maxPwr = meterConfig->mainFuse * voltage; + maxPwr = mainFuse * voltage; } else { - maxPwr = meterConfig->mainFuse * 230; + maxPwr = mainFuse * 230; } } } bool AmsWebServer::checkSecurity(byte level, bool send401) { - bool access = WiFi.getMode() == WIFI_AP || webConfig.security < level; + bool access = WiFi.getMode() == WIFI_AP || WiFi.getMode() == WIFI_AP_STA || webConfig.security < level; if(!access && webConfig.security >= level && server.hasHeader(F("Authorization"))) { String expectedAuth = String(webConfig.username) + ":" + String(webConfig.password); @@ -218,9 +231,9 @@ void AmsWebServer::sysinfoJson() { String hostname; if(sys.userConfigured) { - WiFiConfig wifiConfig; - config->getWiFiConfig(wifiConfig); - hostname = String(wifiConfig.hostname); + NetworkConfig networkConfig; + config->getNetworkConfig(networkConfig); + hostname = String(networkConfig.hostname); } else { hostname = "ams-"+chipIdStr; } @@ -303,6 +316,7 @@ void AmsWebServer::sysinfoJson() { dns1 != INADDR_NONE ? dns1.toString().c_str() : "", dns2 != INADDR_NONE ? dns2.toString().c_str() : "", #endif + sys.boardType > 240 && sys.boardType < 250 ? "true" : "false", meterState->getMeterType(), meterModel.c_str(), meterId.c_str(), @@ -317,6 +331,8 @@ void AmsWebServer::sysinfoJson() { ui.showDayPlot, ui.showMonthPlot, ui.showTemperaturePlot, + ui.showRealtimePlot, + ui.darkMode, webConfig.security, #if defined(ESP32) rtc_get_reset_reason(0), @@ -396,7 +412,7 @@ void AmsWebServer::dataJson() { uint8_t hanStatus; if(meterState->getLastError() != 0) { hanStatus = 3; - } else if((meterConfig->baud == 0 || meterState->getLastUpdateMillis() == 0) && millis < 30000) { + } else if(meterState->getLastUpdateMillis() == 0 && millis < 30000) { hanStatus = 0; } else if(millis - meterState->getLastUpdateMillis() < 15000) { hanStatus = 1; @@ -418,9 +434,9 @@ void AmsWebServer::dataJson() { uint8_t mqttStatus; if(!mqttEnabled) { mqttStatus = 0; - } else if(mqtt != NULL && mqtt->connected()) { + } else if(mqttHandler != NULL && mqttHandler->connected()) { mqttStatus = 1; - } else if(mqtt != NULL && mqtt->lastError() == 0) { + } else if(mqttHandler != NULL && mqttHandler->lastError() == 0) { mqttStatus = 2; } else { mqttStatus = 3; @@ -438,8 +454,8 @@ void AmsWebServer::dataJson() { snprintf_P(buf, BufferSize, DATA_JSON, maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr, - meterConfig->productionCapacity, - meterConfig->mainFuse == 0 ? 40 : meterConfig->mainFuse, + productionCapacity, + mainFuse == 0 ? 40 : mainFuse, meterState->getActiveImportPower(), meterState->getActiveExportPower(), meterState->getReactiveImportPower(), @@ -467,10 +483,10 @@ void AmsWebServer::dataJson() { hanStatus, wifiStatus, mqttStatus, - mqtt == NULL ? 0 : (int) mqtt->lastError(), + mqttHandler == NULL ? 0 : (int) mqttHandler->lastError(), price == ENTSOE_NO_VALUE ? "null" : String(price, 2).c_str(), meterState->getMeterType(), - meterConfig->distributionSystem, + distributionSystem, ea->getMonthMax(), peaks.c_str(), ea->getCurrentThreshold(), @@ -728,13 +744,12 @@ void AmsWebServer::temperatureJson() { TempSensorData* data = hw->getTempSensorData(i); if(data == NULL) continue; - TempSensorConfig* conf = config->getTempSensorConfig(data->address); char* pos = buf+strlen(buf); snprintf_P(pos, 72, TEMPSENSOR_JSON, i, toHex(data->address, 8).c_str(), - conf == NULL ? "" : String(conf->name).substring(0,16).c_str(), - conf == NULL || conf->common ? 1 : 0, + "", + 1, data->lastRead ); yield(); @@ -791,14 +806,19 @@ void AmsWebServer::configurationJson() { if(!checkSecurity(1)) return; + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); + + SystemConfig sysConfig; + config->getSystemConfig(sysConfig); NtpConfig ntpConfig; config->getNtpConfig(ntpConfig); - WiFiConfig wifiConfig; - config->getWiFiConfig(wifiConfig); + NetworkConfig networkConfig; + config->getNetworkConfig(networkConfig); bool encen = false; for(uint8_t i = 0; i < 16; i++) { - if(meterConfig->encryptionKey[i] > 0) { + if(meterConfig.encryptionKey[i] > 0) { encen = true; } } @@ -817,6 +837,8 @@ void AmsWebServer::configurationJson() { config->getUiConfig(ui); HomeAssistantConfig haconf; config->getHomeAssistantConfig(haconf); + CloudConfig cloud; + config->getCloudConfig(cloud); bool qsc = false; bool qsr = false; @@ -839,28 +861,30 @@ void AmsWebServer::configurationJson() { server.sendContent_P(PSTR("\",")); snprintf_P(buf, BufferSize, CONF_GENERAL_JSON, ntpConfig.timezone, - wifiConfig.hostname, + networkConfig.hostname, webConfig.security, webConfig.username, strlen(webConfig.password) > 0 ? "***" : "" ); server.sendContent(buf); snprintf_P(buf, BufferSize, CONF_METER_JSON, - meterConfig->baud, - meterConfig->parity, - meterConfig->invert ? "true" : "false", - meterConfig->bufferSize * 64, - meterConfig->distributionSystem, - meterConfig->mainFuse, - meterConfig->productionCapacity, + meterConfig.source, + meterConfig.parser, + meterConfig.baud, + meterConfig.parity, + meterConfig.invert ? "true" : "false", + meterConfig.bufferSize * 64, + meterConfig.distributionSystem, + meterConfig.mainFuse, + meterConfig.productionCapacity, encen ? "true" : "false", - toHex(meterConfig->encryptionKey, 16).c_str(), - toHex(meterConfig->authenticationKey, 16).c_str(), - meterConfig->wattageMultiplier > 1 || meterConfig->voltageMultiplier > 1 || meterConfig->amperageMultiplier > 1 || meterConfig->accumulatedMultiplier > 1 ? "true" : "false", - meterConfig->wattageMultiplier / 1000.0, - meterConfig->voltageMultiplier / 1000.0, - meterConfig->amperageMultiplier / 1000.0, - meterConfig->accumulatedMultiplier / 1000.0 + toHex(meterConfig.encryptionKey, 16).c_str(), + toHex(meterConfig.authenticationKey, 16).c_str(), + meterConfig.wattageMultiplier > 1 || meterConfig.voltageMultiplier > 1 || meterConfig.amperageMultiplier > 1 || meterConfig.accumulatedMultiplier > 1 ? "true" : "false", + meterConfig.wattageMultiplier / 1000.0, + meterConfig.voltageMultiplier / 1000.0, + meterConfig.amperageMultiplier / 1000.0, + meterConfig.accumulatedMultiplier / 1000.0 ); server.sendContent(buf); @@ -879,22 +903,22 @@ void AmsWebServer::configurationJson() { ); server.sendContent(buf); snprintf_P(buf, BufferSize, CONF_WIFI_JSON, - wifiConfig.ssid, - strlen(wifiConfig.psk) > 0 ? "***" : "", - wifiConfig.power / 10.0, - wifiConfig.sleep, - wifiConfig.autoreboot ? "true" : "false", - wifiConfig.use11b ? "true" : "false" + networkConfig.ssid, + strlen(networkConfig.psk) > 0 ? "***" : "", + networkConfig.power / 10.0, + networkConfig.sleep, + networkConfig.use11b ? "true" : "false" ); server.sendContent(buf); snprintf_P(buf, BufferSize, CONF_NET_JSON, - strlen(wifiConfig.ip) > 0 ? "static" : "dhcp", - wifiConfig.ip, - wifiConfig.subnet, - wifiConfig.gateway, - wifiConfig.dns1, - wifiConfig.dns2, - wifiConfig.mdns ? "true" : "false", + networkConfig.mode, + strlen(networkConfig.ip) > 0 ? "static" : "dhcp", + networkConfig.ip, + networkConfig.subnet, + networkConfig.gateway, + networkConfig.dns1, + networkConfig.dns2, + networkConfig.mdns ? "true" : "false", ntpConfig.server, ntpConfig.dhcp ? "true" : "false" ); @@ -929,8 +953,9 @@ void AmsWebServer::configurationJson() { ); server.sendContent(buf); snprintf_P(buf, BufferSize, CONF_GPIO_JSON, - gpioConfig->hanPin == 0xff ? "null" : String(gpioConfig->hanPin, 10).c_str(), - gpioConfig->hanPinPullup ? "true" : "false", + meterConfig.rxPin == 0xff ? "null" : String(meterConfig.rxPin, 10).c_str(), + meterConfig.rxPinPullup ? "true" : "false", + meterConfig.txPin == 0xff ? "null" : String(meterConfig.txPin, 10).c_str(), gpioConfig->apPin == 0xff ? "null" : String(gpioConfig->apPin, 10).c_str(), gpioConfig->ledPin == 0xff ? "null" : String(gpioConfig->ledPin, 10).c_str(), gpioConfig->ledInverted ? "true" : "false", @@ -938,6 +963,8 @@ void AmsWebServer::configurationJson() { gpioConfig->ledPinGreen == 0xff ? "null" : String(gpioConfig->ledPinGreen, 10).c_str(), gpioConfig->ledPinBlue == 0xff ? "null" : String(gpioConfig->ledPinBlue, 10).c_str(), gpioConfig->ledRgbInverted ? "true" : "false", + gpioConfig->ledDisablePin == 0xff ? "null" : String(gpioConfig->ledDisablePin, 10).c_str(), + gpioConfig->ledBehaviour, gpioConfig->tempSensorPin == 0xff ? "null" : String(gpioConfig->tempSensorPin, 10).c_str(), gpioConfig->tempAnalogSensorPin == 0xff ? "null" : String(gpioConfig->tempAnalogSensorPin, 10).c_str(), gpioConfig->vccPin == 0xff ? "null" : String(gpioConfig->vccPin, 10).c_str(), @@ -959,7 +986,9 @@ void AmsWebServer::configurationJson() { ui.showPricePlot, ui.showDayPlot, ui.showMonthPlot, - ui.showTemperaturePlot + ui.showTemperaturePlot, + ui.showRealtimePlot, + ui.darkMode ); server.sendContent(buf); snprintf_P(buf, BufferSize, CONF_DOMOTICZ_JSON, @@ -976,6 +1005,17 @@ void AmsWebServer::configurationJson() { haconf.discoveryNameTag ); server.sendContent(buf); + snprintf_P(buf, BufferSize, CONF_CLOUD_JSON, + cloud.enabled ? "true" : "false", + cloud.clientId, + strlen(cloud.clientSecret) > 0 ? "***" : "", + #if defined(ENERGY_SPEEDOMETER_PASS) + sysConfig.energyspeedometer == 7 ? "true" : "false" + #else + "null" + #endif + ); + server.sendContent(buf); server.sendContent_P(PSTR("}")); } @@ -992,13 +1032,16 @@ void AmsWebServer::handleSave() { config->clear(); } + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); + #if defined(CONFIG_IDF_TARGET_ESP32S2) switch(boardType) { case 5: // Pow-K+ case 7: // Pow-U+ case 6: // Pow-P1 config->clearGpio(*gpioConfig); - gpioConfig->hanPin = 16; + meterConfig.rxPin = 16; gpioConfig->apPin = 0; gpioConfig->ledPinRed = 13; gpioConfig->ledPinGreen = 14; @@ -1006,20 +1049,21 @@ void AmsWebServer::handleSave() { gpioConfig->vccPin = 10; gpioConfig->vccResistorGnd = 22; gpioConfig->vccResistorVcc = 33; + gpioConfig->ledDisablePin = 6; break; case 51: // Wemos S2 mini gpioConfig->ledPin = 15; gpioConfig->ledInverted = false; gpioConfig->apPin = 0; - gpioConfig->hanPin = hanPin > 0 ? hanPin : 18; - if(gpioConfig->hanPin != 18) { + meterConfig.rxPin = hanPin > 0 ? hanPin : 18; + if(meterConfig.rxPin != 18) { gpioConfig->vccPin = 18; gpioConfig->vccResistorGnd = 45; gpioConfig->vccResistorVcc = 10; } break; case 50: // Generic ESP32-S2 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 18; + meterConfig.rxPin = hanPin > 0 ? hanPin : 18; break; default: success = false; @@ -1027,8 +1071,8 @@ void AmsWebServer::handleSave() { #elif defined(CONFIG_IDF_TARGET_ESP32C3) switch(boardType) { case 8: // dbeinder: HAN mosquito - gpioConfig->hanPin = 7; - gpioConfig->hanPinPullup = false; + meterConfig.rxPin = 7; + meterConfig.rxPinPullup = false; gpioConfig->apPin = 9; gpioConfig->ledRgbInverted = true; gpioConfig->ledPinRed = 5; @@ -1038,15 +1082,27 @@ void AmsWebServer::handleSave() { case 71: // ESP32-C3-DevKitM-1 gpioConfig->apPin = 9; case 70: // Generic ESP32-C3 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 7; + meterConfig.rxPin = hanPin > 0 ? hanPin : 7; break; default: success = false; } #elif defined(ESP32) switch(boardType) { + case 241: // LilyGO T-ETH-POE + gpioConfig->apPin = 0; + meterConfig.rxPin = hanPin > 0 ? hanPin : 39; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; + break; + case 242: // M5 PoESP32 + meterConfig.rxPin = hanPin > 0 ? hanPin : 16; + break; + case 243: // WT32-ETH01 + meterConfig.rxPin = hanPin > 0 ? hanPin : 39; + break; case 201: // D32 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 16; + meterConfig.rxPin = hanPin > 0 ? hanPin : 16; gpioConfig->apPin = 4; gpioConfig->ledPin = 5; gpioConfig->ledInverted = true; @@ -1054,7 +1110,7 @@ void AmsWebServer::handleSave() { case 202: // Feather case 203: // DevKitC case 200: // ESP32 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 16; + meterConfig.rxPin = hanPin > 0 ? hanPin : 16; gpioConfig->ledPin = 2; gpioConfig->ledInverted = false; break; @@ -1066,7 +1122,7 @@ void AmsWebServer::handleSave() { case 2: // spenceme config->clearGpio(*gpioConfig); gpioConfig->vccBootLimit = 32; - gpioConfig->hanPin = 3; + meterConfig.rxPin = 3; gpioConfig->apPin = 0; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; @@ -1074,7 +1130,7 @@ void AmsWebServer::handleSave() { break; case 0: // roarfred config->clearGpio(*gpioConfig); - gpioConfig->hanPin = 3; + meterConfig.rxPin = 3; gpioConfig->apPin = 0; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; @@ -1084,7 +1140,7 @@ void AmsWebServer::handleSave() { case 3: // Pow-K UART0 case 4: // Pow-U UART0 config->clearGpio(*gpioConfig); - gpioConfig->hanPin = 3; + meterConfig.rxPin = 3; gpioConfig->apPin = 0; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; @@ -1095,7 +1151,7 @@ void AmsWebServer::handleSave() { case 5: // Pow-K GPIO12 case 7: // Pow-U GPIO12 config->clearGpio(*gpioConfig); - gpioConfig->hanPin = 12; + meterConfig.rxPin = 12; gpioConfig->apPin = 0; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; @@ -1104,14 +1160,14 @@ void AmsWebServer::handleSave() { gpioConfig->ledRgbInverted = true; break; case 101: // D1 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 5; + meterConfig.rxPin = hanPin > 0 ? hanPin : 5; gpioConfig->apPin = 4; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; gpioConfig->vccMultiplier = 1100; break; case 100: // ESP8266 - gpioConfig->hanPin = hanPin > 0 ? hanPin : 3; + meterConfig.rxPin = hanPin > 0 ? hanPin : 3; gpioConfig->ledPin = 2; gpioConfig->ledInverted = true; break; @@ -1130,69 +1186,72 @@ void AmsWebServer::handleSave() { } } - if(server.hasArg(F("s")) && server.arg(F("s")) == F("true") && server.hasArg(F("ss")) && !server.arg(F("ss")).isEmpty()) { + if(server.hasArg(F("s")) && server.arg(F("s")) == F("true")) { SystemConfig sys; config->getSystemConfig(sys); + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); config->clear(); - WiFiConfig wifi; - config->clearWifi(wifi); + NetworkConfig network; + config->clearNetworkConfig(network); - strcpy(wifi.ssid, server.arg(F("ss")).c_str()); + strcpy(network.ssid, server.arg(F("ss")).c_str()); String psk = server.arg(F("sp")); if(!psk.equals("***")) { - strcpy(wifi.psk, psk.c_str()); + strcpy(network.psk, psk.c_str()); } + network.mode = server.arg(F("sc")).toInt(); + if(network.mode > 3 || network.mode == 0) network.mode = 1; // WiFi Client - if(server.hasArg(F("sm")) && server.arg(F("sm")) == "static") { - strcpy(wifi.ip, server.arg(F("si")).c_str()); - strcpy(wifi.gateway, server.arg(F("sg")).c_str()); - strcpy(wifi.subnet, server.arg(F("su")).c_str()); - strcpy(wifi.dns1, server.arg(F("sd")).c_str()); - } + if(network.mode == 3 || strlen(network.ssid) > 0) { + if(server.hasArg(F("sm")) && server.arg(F("sm")) == "static") { + strcpy(network.ip, server.arg(F("si")).c_str()); + strcpy(network.gateway, server.arg(F("sg")).c_str()); + strcpy(network.subnet, server.arg(F("su")).c_str()); + strcpy(network.dns1, server.arg(F("sd")).c_str()); + } - if(server.hasArg(F("sh")) && !server.arg(F("sh")).isEmpty()) { - strcpy(wifi.hostname, server.arg(F("sh")).c_str()); - wifi.mdns = true; - } else { - wifi.mdns = false; - } - - switch(sys.boardType) { - case 6: // Pow-P1 - meterConfig->baud = 115200; - meterConfig->parity = 3; // 8N1 - break; - case 3: // Pow-K UART0 - case 5: // Pow-K+ - meterConfig->baud = 2400; - meterConfig->parity = 3; // 8N1 - case 2: // spenceme - case 50: // Generic ESP32-S2 - case 51: // Wemos S2 mini - case 70: // Generic ESP32-C3 - case 71: // ESP32-C3-DevKitM-1 - wifi.sleep = 1; // Modem sleep - break; - case 4: // Pow-U UART0 - case 7: // Pow-U+ - wifi.sleep = 2; // Light sleep - break; - case 8: // dbeinder: HAN mosquito - wifi.sleep = 1; // Modem sleep - wifi.use11b = 0; - break; - } - config->setWiFiConfig(wifi); - config->setMeterConfig(*meterConfig); - - sys.userConfigured = success; - sys.dataCollectionConsent = 0; - config->setSystemConfig(sys); + if(server.hasArg(F("sh")) && !server.arg(F("sh")).isEmpty()) { + strcpy(network.hostname, server.arg(F("sh")).c_str()); + network.mdns = true; + } else { + network.mdns = false; + } + + switch(sys.boardType) { + case 6: // Pow-P1 + meterConfig.baud = 115200; + meterConfig.parity = 3; // 8N1 + break; + case 3: // Pow-K UART0 + case 5: // Pow-K+ + meterConfig.baud = 2400; + meterConfig.parity = 3; // 8N1 + case 2: // spenceme + case 8: // dbeinder: HAN mosquito + case 50: // Generic ESP32-S2 + case 51: // Wemos S2 mini + case 70: // Generic ESP32-C3 + case 71: // ESP32-C3-DevKitM-1 + network.sleep = 1; // Modem sleep + break; + case 4: // Pow-U UART0 + case 7: // Pow-U+ + network.sleep = 2; // Light sleep + break; + } + config->setNetworkConfig(network); + config->setMeterConfig(meterConfig); + + sys.userConfigured = success; + sys.dataCollectionConsent = 0; + config->setSystemConfig(sys); - performRestart = true; + performRestart = true; + } } else if(server.hasArg(F("sf")) && !server.arg(F("sf")).isEmpty()) { SystemConfig sys; config->getSystemConfig(sys); @@ -1202,76 +1261,80 @@ void AmsWebServer::handleSave() { if(server.hasArg(F("m")) && server.arg(F("m")) == F("true")) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received meter config\n")); - config->getMeterConfig(*meterConfig); - meterConfig->baud = server.arg(F("mb")).toInt(); - meterConfig->parity = server.arg(F("mp")).toInt(); - meterConfig->invert = server.hasArg(F("mi")) && server.arg(F("mi")) == F("true"); - meterConfig->distributionSystem = server.arg(F("md")).toInt(); - meterConfig->mainFuse = server.arg(F("mf")).toInt(); - meterConfig->productionCapacity = server.arg(F("mr")).toInt(); - meterConfig->bufferSize = min((double) 64, ceil((server.arg(F("ms")).toInt()) / 64)); + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); + meterConfig.source = server.arg(F("mo")).toInt(); + meterConfig.parser = server.arg(F("ma")).toInt(); + meterConfig.baud = server.arg(F("mb")).toInt(); + meterConfig.parity = server.arg(F("mp")).toInt(); + meterConfig.invert = server.hasArg(F("mi")) && server.arg(F("mi")) == F("true"); + meterConfig.distributionSystem = server.arg(F("md")).toInt(); + meterConfig.mainFuse = server.arg(F("mf")).toInt(); + meterConfig.productionCapacity = server.arg(F("mr")).toInt(); + meterConfig.bufferSize = min((double) 64, ceil((server.arg(F("ms")).toInt()) / 64)); maxPwr = 0; if(server.hasArg(F("me")) && server.arg(F("me")) == F("true")) { String encryptionKeyHex = server.arg(F("mek")); if(!encryptionKeyHex.isEmpty()) { encryptionKeyHex.replace(F("0x"), F("")); - fromHex(meterConfig->encryptionKey, encryptionKeyHex, 16); + fromHex(meterConfig.encryptionKey, encryptionKeyHex, 16); } else { - memset(meterConfig->encryptionKey, 0, 16); + memset(meterConfig.encryptionKey, 0, 16); } String authenticationKeyHex = server.arg(F("mea")); if(!authenticationKeyHex.isEmpty()) { authenticationKeyHex.replace(F("0x"), F("")); - fromHex(meterConfig->authenticationKey, authenticationKeyHex, 16); + fromHex(meterConfig.authenticationKey, authenticationKeyHex, 16); } else { - memset(meterConfig->authenticationKey, 0, 16); + memset(meterConfig.authenticationKey, 0, 16); } } else { - memset(meterConfig->encryptionKey, 0, 16); - memset(meterConfig->authenticationKey, 0, 16); + memset(meterConfig.encryptionKey, 0, 16); + memset(meterConfig.authenticationKey, 0, 16); } - meterConfig->wattageMultiplier = server.arg(F("mmw")).toFloat() * 1000; - meterConfig->voltageMultiplier = server.arg(F("mmv")).toFloat() * 1000; - meterConfig->amperageMultiplier = server.arg(F("mma")).toFloat() * 1000; - meterConfig->accumulatedMultiplier = server.arg(F("mmc")).toFloat() * 1000; - config->setMeterConfig(*meterConfig); + meterConfig.wattageMultiplier = server.arg(F("mmw")).toFloat() * 1000; + meterConfig.voltageMultiplier = server.arg(F("mmv")).toFloat() * 1000; + meterConfig.amperageMultiplier = server.arg(F("mma")).toFloat() * 1000; + meterConfig.accumulatedMultiplier = server.arg(F("mmc")).toFloat() * 1000; + config->setMeterConfig(meterConfig); } if(server.hasArg(F("w")) && server.arg(F("w")) == F("true")) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received WiFi config\n")); - WiFiConfig wifi; - config->getWiFiConfig(wifi); - strcpy(wifi.ssid, server.arg(F("ws")).c_str()); + NetworkConfig network; + config->getNetworkConfig(network); + strcpy(network.ssid, server.arg(F("ws")).c_str()); String psk = server.arg(F("wp")); if(!psk.equals("***")) { - strcpy(wifi.psk, psk.c_str()); + strcpy(network.psk, psk.c_str()); } - wifi.power = server.arg(F("ww")).toFloat() * 10; - wifi.sleep = server.arg(F("wz")).toInt(); - wifi.autoreboot = server.hasArg(F("wa")) && server.arg(F("wa")) == F("true"); - wifi.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true"); - config->setWiFiConfig(wifi); + network.power = server.arg(F("ww")).toFloat() * 10; + network.sleep = server.arg(F("wz")).toInt(); + network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true"); + network.mode = server.arg(F("nc")).toInt(); + if(network.mode > 3) network.mode = 1; // WiFi Client + config->setNetworkConfig(network); if(server.hasArg(F("nm"))) { if(server.arg(F("nm")) == "static") { - strcpy(wifi.ip, server.arg(F("ni")).c_str()); - strcpy(wifi.gateway, server.arg(F("ng")).c_str()); - strcpy(wifi.subnet, server.arg(F("ns")).c_str()); - strcpy(wifi.dns1, server.arg(F("nd1")).c_str()); - strcpy(wifi.dns2, server.arg(F("nd2")).c_str()); + strcpy(network.ip, server.arg(F("ni")).c_str()); + strcpy(network.gateway, server.arg(F("ng")).c_str()); + strcpy(network.subnet, server.arg(F("ns")).c_str()); + strcpy(network.dns1, server.arg(F("nd1")).c_str()); + strcpy(network.dns2, server.arg(F("nd2")).c_str()); } else if(server.arg(F("nm")) == "dhcp") { - strcpy(wifi.ip, ""); - strcpy(wifi.gateway, ""); - strcpy(wifi.subnet, ""); - strcpy(wifi.dns1, ""); - strcpy(wifi.dns2, ""); + strcpy(network.ip, ""); + strcpy(network.gateway, ""); + strcpy(network.subnet, ""); + strcpy(network.dns1, ""); + strcpy(network.dns2, ""); } } - wifi.mdns = server.hasArg(F("nd")) && server.arg(F("nd")) == F("true"); - config->setWiFiConfig(wifi); + network.mdns = server.hasArg(F("nd")) && server.arg(F("nd")) == F("true"); + config->setNetworkConfig(network); } if(server.hasArg(F("ntp")) && server.arg(F("ntp")) == F("true")) { @@ -1353,12 +1416,12 @@ void AmsWebServer::handleSave() { } config->setWebConfig(webConfig); - WiFiConfig wifi; - config->getWiFiConfig(wifi); + NetworkConfig network; + config->getNetworkConfig(network); if(server.hasArg(F("gh")) && !server.arg(F("gh")).isEmpty()) { - strcpy(wifi.hostname, server.arg(F("gh")).c_str()); + strcpy(network.hostname, server.arg(F("gh")).c_str()); } - config->setWiFiConfig(wifi); + config->setNetworkConfig(network); NtpConfig ntp; config->getNtpConfig(ntp); @@ -1368,8 +1431,13 @@ void AmsWebServer::handleSave() { if(server.hasArg(F("i")) && server.arg(F("i")) == F("true")) { if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received GPIO config\n")); - gpioConfig->hanPin = server.hasArg(F("ihp")) && !server.arg(F("ihp")).isEmpty() ? server.arg(F("ihp")).toInt() : 3; - gpioConfig->hanPinPullup = server.hasArg(F("ihu")) && server.arg(F("ihu")) == F("true"); + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); + meterConfig.rxPin = server.hasArg(F("ihp")) && !server.arg(F("ihp")).isEmpty() ? server.arg(F("ihp")).toInt() : 3; + meterConfig.rxPinPullup = server.hasArg(F("ihu")) && server.arg(F("ihu")) == F("true"); + meterConfig.txPin = server.hasArg(F("iht")) && !server.arg(F("iht")).isEmpty() ? server.arg(F("iht")).toInt() : 1; + config->setMeterConfig(meterConfig); + gpioConfig->ledPin = server.hasArg(F("ilp")) && !server.arg(F("ilp")).isEmpty() ? server.arg(F("ilp")).toInt() : 0xFF; gpioConfig->ledInverted = server.hasArg(F("ili")) && server.arg(F("ili")) == F("true"); gpioConfig->ledPinRed = server.hasArg(F("irr")) && !server.arg(F("irr")).isEmpty() ? server.arg(F("irr")).toInt() : 0xFF; @@ -1382,6 +1450,12 @@ void AmsWebServer::handleSave() { gpioConfig->vccPin = server.hasArg(F("ivp")) && !server.arg(F("ivp")).isEmpty() ? server.arg(F("ivp")).toInt() : 0xFF; gpioConfig->vccResistorGnd = server.hasArg(F("ivdg")) && !server.arg(F("ivdg")).isEmpty() ? server.arg(F("ivdg")).toInt() : 0; gpioConfig->vccResistorVcc = server.hasArg(F("ivdv")) && !server.arg(F("ivdv")).isEmpty() ? server.arg(F("ivdv")).toInt() : 0; + gpioConfig->ledDisablePin = server.hasArg(F("idd")) && !server.arg(F("idd")).isEmpty() ? server.arg(F("idd")).toInt() : 0; + config->setGpioConfig(*gpioConfig); + } + + if(server.hasArg(F("idb"))) { + gpioConfig->ledBehaviour = server.hasArg(F("idb")) && !server.arg(F("idb")).isEmpty() ? server.arg(F("idb")).toInt() : 0; config->setGpioConfig(*gpioConfig); } @@ -1410,9 +1484,9 @@ void AmsWebServer::handleSave() { debugger->setPassword(F("")); } debugger->setSerialEnabled(debug.serial); - WiFiConfig wifi; - if(config->getWiFiConfig(wifi) && strlen(wifi.hostname) > 0) { - debugger->begin(wifi.hostname, (uint8_t) debug.level); + NetworkConfig network; + if(config->getNetworkConfig(network) && strlen(network.hostname) > 0) { + debugger->begin(network.hostname, (uint8_t) debug.level); if(!debug.telnet) { debugger->stop(); } @@ -1437,6 +1511,8 @@ void AmsWebServer::handleSave() { ui.showDayPlot = server.arg(F("ud")).toInt(); ui.showMonthPlot = server.arg(F("um")).toInt(); ui.showTemperaturePlot = server.arg(F("us")).toInt(); + ui.showRealtimePlot = server.arg(F("ul")).toInt(); + ui.darkMode = server.arg(F("uk")).toInt(); config->setUiConfig(ui); } @@ -1471,11 +1547,38 @@ void AmsWebServer::handleSave() { config->setEnergyAccountingConfig(eac); } + if(server.hasArg(F("c")) && server.arg(F("c")) == F("true")) { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received cloud config\n")); + SystemConfig sys; + config->getSystemConfig(sys); + sys.energyspeedometer = server.hasArg(F("ces")) && server.arg(F("ces")) == F("true") ? 7 : 0; + config->setSystemConfig(sys); + + CloudConfig cloud; + config->getCloudConfig(cloud); + cloud.enabled = server.hasArg(F("ce")) && server.arg(F("ce")) == F("true"); + if(cloud.enabled) { + String host = server.arg("ch"); + if(!host.isEmpty()) { + strcpy(cloud.hostname, host.c_str()); + } + String clientId = server.arg(F("ci")).c_str(); + if(!clientId.isEmpty()) { + strcpy(cloud.clientId, clientId.c_str()); + } + String secret = server.arg(F("cs")); + if(!secret.isEmpty() && !secret.equals("***")) { + strcpy(cloud.clientSecret, secret.c_str()); + } + } + config->setCloudConfig(cloud); + } + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Saving configuration now...\n")); if (config->save()) { if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Successfully saved.\n")); - if(config->isWifiChanged() || performRestart) { + if(config->isNetworkConfigChanged() || performRestart) { performRestart = true; } else { hw->setup(gpioConfig, config); @@ -1702,14 +1805,8 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) { } } } else if(upload.status == UPLOAD_FILE_WRITE) { - if(debugger->isActive(RemoteDebug::DEBUG)) { - debugger->printf_P(PSTR("handleFileUpload Writing: %u\n"), upload.currentSize); - } if(file) { size_t written = file.write(upload.buf, upload.currentSize); - if(debugger->isActive(RemoteDebug::DEBUG)) { - debugger->printf_P(PSTR("handleFileUpload Written: %u\n"), written); - } delay(1); if(written != upload.currentSize) { file.flush(); @@ -1942,6 +2039,30 @@ void AmsWebServer::tariffJson() { server.send(200, MIME_JSON, buf); } +void AmsWebServer::realtimeJson() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /realtime.json over http...\n")); + if(rtp == NULL) { + server.send_P(500, MIME_PLAIN, PSTR("500: Not available")); + return; + } + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + server.setContentLength(CONTENT_LENGTH_UNKNOWN); + snprintf_P(buf, BufferSize, PSTR("{\"size\":\"%d\",\"data\":["), rtp->getSize()); + server.send(200, MIME_JSON, buf); + bool first = true; + for(uint16_t i = 0; i < rtp->getSize(); i++) { + snprintf_P(buf, BufferSize, PSTR("%s%d"), first ? "" : ",", rtp->getValue(i)); + server.sendContent(buf); + first = false; + } + snprintf_P(buf, BufferSize, PSTR("]}")); + server.sendContent(buf); +} + void AmsWebServer::setPriceSettings(String region, String currency) { this->priceRegion = region; this->priceCurrency = currency; @@ -1977,20 +2098,21 @@ void AmsWebServer::configFileDownload() { server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("boardType %d\n"), sys.boardType)); if(includeWifi) { - WiFiConfig wifi; - config->getWiFiConfig(wifi); - if(includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("hostname %s\n"), wifi.hostname)); - if(includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("ssid %s\n"), wifi.ssid)); - if(includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("psk %s\n"), wifi.psk)); - if(strlen(wifi.ip) > 0) { - server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("ip %s\n"), wifi.ip)); - if(strlen(wifi.gateway) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gateway %s\n"), wifi.gateway)); - if(strlen(wifi.subnet) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("subnet %s\n"), wifi.subnet)); - if(strlen(wifi.dns1) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("dns1 %s\n"), wifi.dns1)); - if(strlen(wifi.dns2) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("dns2 %s\n"), wifi.dns2)); + NetworkConfig network; + config->getNetworkConfig(network); + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("netmode %d\n"), network.mode)); + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("hostname %s\n"), network.hostname)); + if(includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("ssid %s\n"), network.ssid)); + if(includeSecrets) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("psk %s\n"), network.psk)); + if(strlen(network.ip) > 0) { + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("ip %s\n"), network.ip)); + if(strlen(network.gateway) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gateway %s\n"), network.gateway)); + if(strlen(network.subnet) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("subnet %s\n"), network.subnet)); + if(strlen(network.dns1) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("dns1 %s\n"), network.dns1)); + if(strlen(network.dns2) > 0) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("dns2 %s\n"), network.dns2)); } - server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("mdns %d\n"), wifi.mdns ? 1 : 0)); - server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("use11b %d\n"), wifi.use11b ? 1 : 0)); + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("mdns %d\n"), network.mdns ? 1 : 0)); + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("use11b %d\n"), network.use11b ? 1 : 0)); } if(includeMqtt) { @@ -2065,10 +2187,12 @@ void AmsWebServer::configFileDownload() { } if(includeGpio) { + MeterConfig meter; + config->getMeterConfig(meter); GpioConfig gpio; config->getGpioConfig(gpio); - if(gpio.hanPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioHanPin %d\n"), gpio.hanPin)); - if(gpio.hanPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioHanPinPullup %d\n"), gpio.hanPinPullup ? 1 : 0)); + if(meter.rxPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioHanPin %d\n"), meter.rxPin)); + if(meter.rxPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioHanPinPullup %d\n"), meter.rxPinPullup ? 1 : 0)); if(gpio.apPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioApPin %d\n"), gpio.apPin)); if(gpio.ledPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioLedPin %d\n"), gpio.ledPin)); if(gpio.ledPin != 0xFF) server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("gpioLedInverted %d\n"), gpio.ledInverted ? 1 : 0)); diff --git a/lib/Uptime/include/Uptime.h b/lib/Uptime/include/Uptime.h index aeea9732..1fcb8a2f 100644 --- a/lib/Uptime/include/Uptime.h +++ b/lib/Uptime/include/Uptime.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _UPTIME_H #define _UPTIME_H diff --git a/lib/Uptime/src/Uptime.cpp b/lib/Uptime/src/Uptime.cpp index 65b5bd1d..5af24c37 100644 --- a/lib/Uptime/src/Uptime.cpp +++ b/lib/Uptime/src/Uptime.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "Uptime.h" uint32_t _uptime_last_value = 0; diff --git a/platformio.ini b/platformio.ini index 4310874b..417f917b 100755 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ extra_configs = platformio-user.ini [common] -lib_deps = EEPROM, LittleFS, DNSServer, https://github.com/256dpi/arduino-mqtt.git, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, FirmwareVersion, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi +lib_deps = EEPROM, LittleFS, DNSServer, https://github.com/256dpi/arduino-mqtt.git, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, FirmwareVersion, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, AmsMqttHandler, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, RealtimePlot, SvelteUi lib_ignore = OneWire extra_scripts = pre:scripts/addversion.py @@ -17,7 +17,7 @@ build_flags = -fexceptions [esp32] -lib_deps = WiFi, ESPmDNS, WiFiClientSecure, HTTPClient, FS, Update, HTTPUpdate, WebServer, ${common.lib_deps} +lib_deps = WiFi, Ethernet, ESPmDNS, WiFiClientSecure, HTTPClient, FS, Update, HTTPUpdate, WebServer, ${common.lib_deps}, CloudConnector [env:esp8266] platform = espressif8266@4.2.0 diff --git a/src/AmsToMqttBridge.cpp b/src/AmsToMqttBridge.cpp index f5a7bb5b..6c000186 100644 --- a/src/AmsToMqttBridge.cpp +++ b/src/AmsToMqttBridge.cpp @@ -12,22 +12,42 @@ #include #if defined(ESP8266) +#include +#include ADC_MODE(ADC_VCC); -#endif - -#if defined(ESP32) -#include +#elif defined(ESP32) +#include +#include +#include +#include "Update.h" #include #include +#include "CloudConnector.h" #endif + #define WDT_TIMEOUT 60 -#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) -#include -#endif +#define METER_SOURCE_NONE 0 +#define METER_SOURCE_SERIAL 1 +#define METER_SOURCE_MQTT 2 +#define METER_SOURCE_ESPNOW 3 + +#define METER_PARSER_PASSIVE 0 +#define METER_PARSER_KAMSTRUP 9 + +#define METER_ERROR_NO_DATA 90 +#define METER_ERROR_BREAK 91 +#define METER_ERROR_BUFFER 92 +#define METER_ERROR_FIFO 93 +#define METER_ERROR_FRAME 94 +#define METER_ERROR_PARITY 95 +#define METER_ERROR_RX 96 +#define METER_ERROR_EXCEPTION 98 +#define METER_ERROR_AUTODETECT 99 + +#include "LittleFS.h" #include "FirmwareVersion.h" -#include "AmsToMqttBridge.h" #include "AmsStorage.h" #include "AmsDataStorage.h" #include "EnergyAccounting.h" @@ -38,8 +58,12 @@ ADC_MODE(ADC_VCC); #include "hexutils.h" #include "HwTools.h" +#include "ConnectionHandler.h" +#include "WiFiClientConnectionHandler.h" +#include "WiFiAccessPointConnectionHandler.h" +#include "EthernetConnectionHandler.h" #include "EntsoeApi.h" - +#include "RealtimePlot.h" #include "AmsWebServer.h" #include "AmsConfiguration.h" @@ -48,32 +72,29 @@ ADC_MODE(ADC_VCC); #include "RawMqttHandler.h" #include "DomoticzMqttHandler.h" #include "HomeAssistantMqttHandler.h" +#include "PassthroughMqttHandler.h" + +#include "MeterCommunicator.h" +#include "PassiveMeterCommunicator.h" +#include "KamstrupPullCommunicator.h" #include "Uptime.h" #include "RemoteDebug.h" -#define debugV_P(x, ...) if (Debug.isActive(Debug.VERBOSE)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} +#define debugV_P(x, ...) if (Debug.isActive(Debug.VERBOSE)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} #define debugD_P(x, ...) if (Debug.isActive(Debug.DEBUG)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} #define debugI_P(x, ...) if (Debug.isActive(Debug.INFO)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} #define debugW_P(x, ...) if (Debug.isActive(Debug.WARNING)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} #define debugE_P(x, ...) if (Debug.isActive(Debug.ERROR)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} #define debugA_P(x, ...) if (Debug.isActive(Debug.ANY)) {Debug.printf_P(x, ##__VA_ARGS__);Debug.println();} - #define BUF_SIZE_COMMON (2048) -#define BUF_SIZE_HAN (1280) -#include "IEC6205621.h" -#include "IEC6205675.h" -#include "LNG.h" -#include "LNG2.h" - -#include "DataParsers.h" #include "Timezones.h" uint8_t commonBuffer[BUF_SIZE_COMMON]; -uint8_t hanBuffer[BUF_SIZE_HAN]; + HwTools hw; @@ -87,23 +108,38 @@ EntsoeApi* eapi = NULL; Timezone* tz = NULL; +ConnectionHandler* ch = NULL; AmsWebServer ws(commonBuffer, &Debug, &hw); -MQTTClient *mqtt = NULL; -WiFiClient *mqttClient = NULL; -WiFiClientSecure *mqttSecureClient = NULL; +bool mqttEnabled = false; AmsMqttHandler* mqttHandler = NULL; -Stream *hanSerial; -SoftwareSerial *swSerial = NULL; -HardwareSerial *hwSerial = NULL; -uint8_t rxBufferErrors = 0; - SystemConfig sysConfig; GpioConfig gpioConfig; +#if defined(ESP32) +JsonMqttHandler* energySpeedometer = NULL; +MqttConfig energySpeedometerConfig = { + "mqtt.sandtime.energy", + 8883, + "", + "amsleser", + "", + #if defined(ENERGY_SPEEDOMETER_USER) + ENERGY_SPEEDOMETER_USER, + #else + "", + #endif + #if defined(ENERGY_SPEEDOMETER_PASS) + ENERGY_SPEEDOMETER_PASS, + #else + "", + #endif + 0, + true +}; +#endif + MeterConfig meterConfig; -bool mqttEnabled = false; -String topic = "ams"; AmsData meterState; bool ntpEnabled = false; @@ -111,64 +147,47 @@ bool mdnsEnabled = false; AmsDataStorage ds(&Debug); #if defined(ESP32) +CloudConnector *cloud = NULL; __NOINIT_ATTR EnergyAccountingRealtimeData rtd; #else EnergyAccountingRealtimeData rtd; #endif EnergyAccounting ea(&Debug, &rtd); -uint8_t wifiReconnectCount = 0; -bool wifiDisable11b = false; - -HDLCParser *hdlcParser = NULL; -MBUSParser *mbusParser = NULL; -GBTParser *gbtParser = NULL; -GCMParser *gcmParser = NULL; -LLCParser *llcParser = NULL; -DLMSParser *dlmsParser = NULL; -DSMRParser *dsmrParser = NULL; - -bool maxDetectPayloadDetectDone = false; -uint8_t maxDetectedPayloadSize = 64; +RealtimePlot rtp; +MeterCommunicator* mc = NULL; +PassiveMeterCommunicator* passiveMc = NULL; +KamstrupPullCommunicator* kamstrupMc = NULL; +HardwareSerial* hwSerial = NULL; +bool networkConnected = false; +bool setupMode = false; void configFileParse(); -void swapWifiMode(); -void WiFi_connect(); -void WiFi_post_connect(); -void WiFi_disconnect(unsigned long timeout); +void connectToNetwork(); +void toggleSetupMode(); +void postConnect(); void MQTT_connect(); void handleNtpChange(); void handleDataSuccess(AmsData* data); void handleTemperature(unsigned long now); void handleSystem(unsigned long now); -void handleAutodetect(unsigned long now); void handleButton(unsigned long now); void handlePriceApi(unsigned long now); void handleClear(unsigned long now); void handleEnergyAccountingChanged(); bool handleVoltageCheck(); bool readHanPort(); -void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, bool invert); -void rxerr(int err); -int16_t unwrapData(uint8_t *buf, DataParserContext &context); void errorBlink(); -void printHanReadError(int pos); -void debugPrint(byte *buffer, int start, int length); - #if defined(ESP32) uint8_t dnsState = 0; ip_addr_t dns0; void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { + if(setupMode) return; // None of this necessary in setup mode + if(ch != NULL) ch->eventHandler(event, info); switch(event) { - case ARDUINO_EVENT_WIFI_READY: - if (wifiDisable11b) { - esp_wifi_config_11b_rate(WIFI_IF_AP, true); - esp_wifi_config_11b_rate(WIFI_IF_STA, true); - } - break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: { const ip_addr_t* dns = dns_getserver(0); memcpy(&dns0, dns, sizeof(dns0)); @@ -184,25 +203,36 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { } break; } - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - wifi_err_reason_t reason = (wifi_err_reason_t) info.wifi_sta_disconnected.reason; - const char* descr = WiFi.disconnectReasonName(reason); - debugI_P(PSTR("WiFi disconnected, reason %s"), descr); - switch(reason) { - case WIFI_REASON_AUTH_FAIL: - case WIFI_REASON_NO_AP_FOUND: - if(sysConfig.dataCollectionConsent == 0) { - swapWifiMode(); - } else if(strlen(descr) > 0) { - WiFi_disconnect(5000); - } - break; - default: - if(strlen(descr) > 0) { - WiFi_disconnect(2000); - } + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: { + if(WiFi.getMode() == WIFI_STA) { + wifi_err_reason_t reason = (wifi_err_reason_t) info.wifi_sta_disconnected.reason; + switch(reason) { + case WIFI_REASON_AUTH_FAIL: + case WIFI_REASON_NO_AP_FOUND: + if(sysConfig.dataCollectionConsent == 0) { + debugI_P(PSTR("Unable to connect to configured AP, swapping to AP mode")); + toggleSetupMode(); + } + break; + } } break; + } + case ARDUINO_EVENT_SC_FOUND_CHANNEL: + debugI_P(PSTR("SmartConfig found channel")); + break; + case ARDUINO_EVENT_SC_GOT_SSID_PSWD: + debugI_P(PSTR("SmartConfig got config")); + break; + } +} + +void rxerr(int err) { + if(passiveMc != NULL) { + passiveMc->rxerr(err); + } + if(kamstrupMc != NULL) { + kamstrupMc->rxerr(err); } } #endif @@ -224,7 +254,6 @@ void setup() { } delay(1); - config.loadTempSensors(); hw.setup(&gpioConfig, &config); if(gpioConfig.apPin >= 0) { @@ -269,10 +298,11 @@ void setup() { ws.setPriceSettings(entsoe.area, entsoe.currency); ea.setFixedPrice(entsoe.fixedPrice / 1000.0, entsoe.currency); bool shared = false; - config.getMeterConfig(meterConfig); Serial.flush(); Serial.end(); - if(gpioConfig.hanPin == 3) { + MeterConfig meterConfig; + config.getMeterConfig(meterConfig); + if(meterConfig.rxPin == 3) { shared = true; #if defined(ESP8266) SerialConfig serialConfig; @@ -332,11 +362,9 @@ void setup() { WiFi.disconnect(true); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_OFF); - - WiFiConfig wifiConf; - if(config.getWiFiConfig(wifiConf)) { - wifiDisable11b = !wifiConf.use11b; - } + #if defined(ESP32) + WiFi.onEvent(WiFiEvent); + #endif bool hasFs = false; #if defined(ESP32) @@ -427,14 +455,14 @@ void setup() { if(config.hasConfig()) { if(Debug.isActive(RemoteDebug::INFO)) config.print(&Debug); - WiFi_connect(); + connectToNetwork(); handleNtpChange(); ds.load(); } else { if(Debug.isActive(RemoteDebug::INFO)) { debugI_P(PSTR("No configuration, booting AP")); } - swapWifiMode(); + toggleSetupMode(); } EnergyAccountingConfig *eac = new EnergyAccountingConfig(); @@ -446,7 +474,7 @@ void setup() { ea.setup(&ds, eac); ea.load(); ea.setEapi(eapi); - ws.setup(&config, &gpioConfig, &meterConfig, &meterState, &ds, &ea); + ws.setup(&config, &gpioConfig, &meterState, &ds, &ea, &rtp); #if defined(ESP32) esp_task_wdt_init(WDT_TIMEOUT, true); @@ -461,21 +489,12 @@ bool buttonActive = false; unsigned long longPressTime = 5000; bool longPressActive = false; -bool wifiConnected = false; - unsigned long lastTemperatureRead = 0; unsigned long lastSysupdate = 0; unsigned long lastErrorBlink = 0; unsigned long lastVoltageCheck = 0; int lastError = 0; -bool meterAutodetect = false; -unsigned long meterAutodetectLastChange = 0; -uint8_t meterAutoIndex = 0; -uint32_t bauds[] = { 2400, 2400, 115200, 115200 }; -uint8_t parities[] = { 11, 3, 3, 3 }; -bool inverts[] = { false, false, false, true }; - void loop() { unsigned long now = millis(); unsigned long start = now; @@ -491,32 +510,21 @@ void loop() { errorBlink(); } - if(hwSerial != NULL) { - #if defined ESP8266 - if(hwSerial->hasRxError()) { - debugE_P(PSTR("Serial RX error")); - meterState.setLastError(METER_ERROR_RX); - } - if(hwSerial->hasOverrun()) { - rxerr(2); - } - #endif - } else if(swSerial != NULL) { - if(swSerial->overflow()) { - rxerr(2); - } - } - // Only do normal stuff if we're not booted as AP - if (WiFi.getMode() != WIFI_AP) { - if (WiFi.status() != WL_CONNECTED) { - wifiConnected = false; - Debug.stop(); - WiFi_connect(); + if (!setupMode) { + if (ch != NULL && !ch->isConnected()) { + if(networkConnected) { + Debug.stop(); + MDNS.end(); + if(mqttHandler != NULL) { + mqttHandler->disconnect(); + } + } + networkConnected = false; + connectToNetwork(); } else { - wifiReconnectCount = 0; - if(!wifiConnected) { - WiFi_post_connect(); + if(!networkConnected) { + postConnect(); } if(config.isNtpChanged()) { handleNtpChange(); @@ -533,15 +541,49 @@ void loop() { #endif if (mqttEnabled || config.isMqttChanged()) { - if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) { + if(mqttHandler == NULL || !mqttHandler->connected() || config.isMqttChanged()) { MQTT_connect(); config.ackMqttChange(); } - } else if(mqtt != NULL && mqtt->connected()) { - mqttClient->stop(); - mqtt->disconnect(); + } else if(mqttHandler != NULL) { + mqttHandler->disconnect(); } + #if defined(ENERGY_SPEEDOMETER_PASS) + if(sysConfig.energyspeedometer == 7) { + if(!meterState.getMeterId().isEmpty()) { + if(energySpeedometer == NULL) { + uint16_t chipId; + #if defined(ESP32) + chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF; + #else + chipId = ESP.getChipId(); + #endif + strcpy(energySpeedometerConfig.clientId, (String("ams") + String(chipId, HEX)).c_str()); + energySpeedometer = new JsonMqttHandler(energySpeedometerConfig, &Debug, (char*) commonBuffer, &hw); + energySpeedometer->setCaVerification(false); + } + if(!energySpeedometer->connected()) { + lwmqtt_err_t err = energySpeedometer->lastError(); + if(err > 0) + debugE_P(PSTR("Energyspeedometer connector reporting error (%d)"), err); + energySpeedometer->connect(); + energySpeedometer->publishSystem(&hw, eapi, &ea); + } + energySpeedometer->loop(); + delay(10); + } + } else if(energySpeedometer != NULL) { + if(energySpeedometer->connected()) { + energySpeedometer->disconnect(); + energySpeedometer->loop(); + } else { + delete energySpeedometer; + energySpeedometer = NULL; + } + } + #endif + try { handlePriceApi(now); } catch(const std::exception& e) { @@ -554,14 +596,30 @@ void loop() { debugW_P(PSTR("Used %dms to handle web"), millis()-start); } } - if(mqtt != NULL) { + if(mqttHandler != NULL) { start = millis(); - mqtt->loop(); + mqttHandler->loop(); delay(10); // Needed to preserve power. After adding this, the voltage is super smooth on a HAN powered device end = millis(); if(end - start > 1000) { debugW_P(PSTR("Used %dms to handle mqtt"), millis()-start); } + + #if defined(ESP32) + if(config.isCloudChanged()) { + CloudConfig cc; + if(config.getCloudConfig(cc) && cc.enabled) { + if(cloud == NULL) { + cloud = new CloudConnector(&Debug); + } + cloud->setup(cc, &hw); + } + config.ackCloudConfig(); + } + if(cloud != NULL) { + cloud->update(meterState, ea); + } + #endif } /* if(now - lastVoltageCheck > 500) { @@ -570,6 +628,26 @@ void loop() { } */ } else { + if(WiFi.smartConfigDone()) { + debugI_P(PSTR("Smart config DONE!")); + + NetworkConfig network; + config.getNetworkConfig(network); + strcpy(network.ssid, WiFi.SSID().c_str()); + strcpy(network.psk, WiFi.psk().c_str()); + network.mode = 1; + network.mdns = true; + config.setNetworkConfig(network); + + SystemConfig sys; + config.getSystemConfig(sys); + sys.userConfigured = true; + sys.dataCollectionConsent = 0; + config.setSystemConfig(sys); + config.save(); + + ESP.restart(); + } if(dnsServer != NULL) { dnsServer->processNextRequest(); } @@ -583,13 +661,47 @@ void loop() { } if(config.isMeterChanged()) { + MeterConfig meterConfig; config.getMeterConfig(meterConfig); - setupHanPort(gpioConfig, meterConfig.baud, meterConfig.parity, meterConfig.invert); - config.ackMeterChanged(); - if(gcmParser != NULL) { - delete gcmParser; - gcmParser = NULL; + if(meterConfig.source = METER_SOURCE_SERIAL) { + switch(meterConfig.parser) { + case METER_PARSER_PASSIVE: + if(kamstrupMc != NULL) { + delete(kamstrupMc); + kamstrupMc = NULL; + } + if(passiveMc == NULL) { + passiveMc = new PassiveMeterCommunicator(&Debug); + } + passiveMc->configure(meterConfig, tz); + hwSerial = passiveMc->getHwSerial(); + mc = passiveMc; + break; + case METER_PARSER_KAMSTRUP: + if(passiveMc != NULL) { + delete(passiveMc); + passiveMc = NULL; + } + if(kamstrupMc == NULL) { + kamstrupMc = new KamstrupPullCommunicator(&Debug); + } + kamstrupMc->configure(meterConfig, tz); + hwSerial = kamstrupMc->getHwSerial(); + mc = kamstrupMc; + break; + default: + debugE_P(PSTR("Unknown meter parser selected: %d"), meterConfig.parser); + } + #if defined(ESP32) + if(hwSerial != NULL) { + hwSerial->onReceiveError(rxerr); + } + #endif + } else { + debugE_P(PSTR("Unknown meter source selected: %d"), meterConfig.source); } + ws.setMeterConfig(meterConfig.distributionSystem, meterConfig.mainFuse, meterConfig.productionCapacity); + config.ackMeterChanged(); } if(config.isEnergyAccountingChanged()) { @@ -604,6 +716,7 @@ void loop() { } handleTemperature(now); handleSystem(now); + hw.setBootSuccessful(); } else { end = millis(); if(end - start > 1000) { @@ -617,12 +730,6 @@ void loop() { debugE_P(PSTR("Exception in readHanPort (%s)"), e.what()); meterState.setLastError(METER_ERROR_EXCEPTION); } - try { - handleAutodetect(now); - } catch(const std::exception& e) { - debugE_P(PSTR("Exception in meter autodetect (%s)"), e.what()); - meterState.setLastError(METER_ERROR_AUTODETECT); - } delay(10); // Needed for auto modem sleep start = millis(); @@ -687,11 +794,23 @@ void handleNtpChange() { } void handleSystem(unsigned long now) { + if(config.isSystemConfigChanged()) { + config.getSystemConfig(sysConfig); + config.ackSystemConfigChanged(); + } + unsigned long start, end; if(now - lastSysupdate > 60000) { start = millis(); - if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { - mqttHandler->publishSystem(&hw, eapi, &ea); + if(WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED) { + if(mqttHandler != NULL) { + mqttHandler->publishSystem(&hw, eapi, &ea); + } + #if defined(ENERGY_SPEEDOMETER_PASS) + if(energySpeedometer != NULL) { + energySpeedometer->publishSystem(&hw, eapi, &ea); + } + #endif } lastSysupdate = now; end = millis(); @@ -710,25 +829,27 @@ void handleSystem(unsigned long now) { #endif } - // After one hour, adjust buffer size to match the largest payload - if(!maxDetectPayloadDetectDone && now > 3600000) { - if(maxDetectedPayloadSize * 1.5 > meterConfig.bufferSize * 64) { - int bufferSize = min((double) 64, ceil((maxDetectedPayloadSize * 1.5) / 64)); - #if defined(ESP8266) - if(gpioConfig.hanPin != 3 && gpioConfig.hanPin != 113) { - bufferSize = min(bufferSize, 2); - } else { - bufferSize = min(bufferSize, 8); - } - #endif - if(bufferSize != meterConfig.bufferSize) { - debugI_P(PSTR("Increasing RX buffer to %d bytes"), bufferSize * 64); - meterConfig.bufferSize = bufferSize; - config.setMeterConfig(meterConfig); + handleVoltageCheck(); +} + +bool handleVoltageCheck() { + if(sysConfig.boardType == 7 && maxVcc > 2.8) { // Pow-U + float vcc = hw.getVcc(); + if(vcc > 3.4 || vcc < 2.8) { + maxVcc = 0; + } else if(vcc > maxVcc) { + debugD_P(PSTR("Setting new max Vcc to %.2f"), vcc); + maxVcc = vcc; + } else if(WiFi.getMode() != WIFI_OFF) { + float diff = min(maxVcc, (float) 3.3)-vcc; + if(diff > 0.4) { + debugW_P(PSTR("Vcc dropped to %.2f, disconnecting WiFi for 5 seconds to preserve power"), vcc); + ch->disconnect(5000); + return false; } } - maxDetectPayloadDetectDone = true; } + return true; } void handleTemperature(unsigned long now) { @@ -738,7 +859,7 @@ void handleTemperature(unsigned long now) { if(hw.updateTemperatures()) { lastTemperatureRead = now; - if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { + if(mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED) { mqttHandler->publishTemperatures(&config, &hw); } } @@ -753,7 +874,7 @@ void handlePriceApi(unsigned long now) { unsigned long start, end; if(eapi != NULL && ntpEnabled) { start = millis(); - if(eapi->loop() && mqtt != NULL && mqttHandler != NULL && mqtt->connected()) { + if(eapi->loop() && mqttHandler != NULL) { end = millis(); if(end - start > 1000) { debugW_P(PSTR("Used %dms to update prices"), millis()-start); @@ -793,27 +914,6 @@ void handlePriceApi(unsigned long now) { } } -void handleAutodetect(unsigned long now) { - if(meterState.getListType() == 0) { - if(now - meterAutodetectLastChange > 20000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) { - meterAutodetect = true; - meterAutoIndex++; // Default is to try the first one in setup() - debugI_P(PSTR("Meter serial autodetect, swapping to: %d, %d, %s"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); - if(meterAutoIndex >= 4) meterAutoIndex = 0; - setupHanPort(gpioConfig, bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex]); - meterAutodetectLastChange = now; - } - } else if(meterAutodetect) { - debugI_P(PSTR("Meter serial autodetected, saving: %d, %d, %s"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); - meterAutodetect = false; - meterConfig.baud = bauds[meterAutoIndex]; - meterConfig.parity = parities[meterAutoIndex]; - meterConfig.invert = inverts[meterAutoIndex]; - config.setMeterConfig(meterConfig); - setupHanPort(gpioConfig, meterConfig.baud, meterConfig.parity, meterConfig.invert); - } -} - void handleButton(unsigned long now) { if(gpioConfig.apPin != 0xFF) { if (digitalRead(gpioConfig.apPin) == LOW) { @@ -824,7 +924,8 @@ void handleButton(unsigned long now) { if ((now - buttonTimer > longPressTime) && (longPressActive == false)) { longPressActive = true; - swapWifiMode(); + debugD_P(PSTR("Button was held, triggering setup mode")); + toggleSetupMode(); } } else { if (buttonActive == true) { @@ -840,229 +941,6 @@ void handleButton(unsigned long now) { } } -bool handleVoltageCheck() { - if(sysConfig.boardType == 7 && maxVcc > 2.8) { // Pow-U - float vcc = hw.getVcc(); - if(vcc > 3.4 || vcc < 2.8) { - maxVcc = 0; - } else if(vcc > maxVcc) { - debugD_P(PSTR("Setting new max Vcc to %.2f"), vcc); - maxVcc = vcc; - } else if(WiFi.getMode() != WIFI_OFF) { - float diff = min(maxVcc, (float) 3.3)-vcc; - if(diff > 0.4) { - debugW_P(PSTR("Vcc dropped to %.2f, disconnecting WiFi for 5 seconds to preserve power"), vcc); - WiFi_disconnect(2000); - return false; - } - } - } - return true; -} - -void rxerr(int err) { - if(err == 0) return; - switch(err) { - case 2: - debugE_P(PSTR("Serial buffer overflow")); - rxBufferErrors++; - if(rxBufferErrors > 3 && meterConfig.bufferSize < 64) { - meterConfig.bufferSize += 2; - debugI_P(PSTR("Increasing RX buffer to %d bytes"), meterConfig.bufferSize * 64); - config.setMeterConfig(meterConfig); - rxBufferErrors = 0; - } - break; - case 3: - debugE_P(PSTR("Serial FIFO overflow")); - break; - case 4: - debugW_P(PSTR("Serial frame error")); - break; - case 5: - debugW_P(PSTR("Serial parity error")); - break; - } - // Do not include serial break - if(err > 1) meterState.setLastError(90+err); -} - -void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, bool invert) { - uint8_t pin = gpioConfig.hanPin; - - if(Debug.isActive(RemoteDebug::INFO)) Debug.printf_P(PSTR("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n"), pin, baud, parityOrdinal); - - if(baud == 0) { - baud = bauds[meterAutoIndex]; - parityOrdinal = parities[meterAutoIndex]; - invert = inverts[meterAutoIndex]; - } - if(parityOrdinal == 0) { - parityOrdinal = 3; // 8N1 - } - - switch(sysConfig.boardType) { - case 8: // HAN mosquito: has inverting level shifter - invert = !invert; - break; - } - - if(pin == 3 || pin == 113) { - #if ARDUINO_USB_CDC_ON_BOOT - hwSerial = &Serial0; - #else - hwSerial = &Serial; - #endif - } - - #if defined(ESP32) - if(pin == 9) { - hwSerial = &Serial1; - } - #if defined(CONFIG_IDF_TARGET_ESP32) - if(pin == 16) { - hwSerial = &Serial2; - } - #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) - hwSerial = &Serial1; - #endif - #endif - - if(pin == 0) { - debugE_P(PSTR("Invalid GPIO configured for HAN")); - return; - } - - if(meterConfig.bufferSize < 1) meterConfig.bufferSize = 1; - - if(hwSerial != NULL) { - debugD_P(PSTR("Hardware serial")); - Serial.flush(); - #if defined(ESP8266) - SerialConfig serialConfig; - #elif defined(ESP32) - uint32_t serialConfig; - #endif - switch(parityOrdinal) { - case 2: - serialConfig = SERIAL_7N1; - break; - case 3: - serialConfig = SERIAL_8N1; - break; - case 10: - serialConfig = SERIAL_7E1; - break; - default: - serialConfig = SERIAL_8E1; - break; - } - if(meterConfig.bufferSize < 4) meterConfig.bufferSize = 4; // 64 bytes (1) is default for software serial, 256 bytes (4) for hardware - - hwSerial->setRxBufferSize(64 * meterConfig.bufferSize); - #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) - hwSerial->begin(baud, serialConfig, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, invert); - uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - #elif defined(ESP32) - hwSerial->begin(baud, serialConfig, -1, -1, invert); - #else - hwSerial->begin(baud, serialConfig, SERIAL_FULL, 1, invert); - #endif - - #if defined(ESP8266) - if(pin == 3) { - debugI_P(PSTR("Switching UART0 to pin 1 & 3")); - Serial.pins(1,3); - } else if(pin == 113) { - debugI_P(PSTR("Switching UART0 to pin 15 & 13")); - Serial.pins(15,13); - } - #endif - - // Prevent pullup on TX pin if not uart0 - #if defined(CONFIG_IDF_TARGET_ESP32S2) - pinMode(17, INPUT); - #elif defined(CONFIG_IDF_TARGET_ESP32C3) - pinMode(7, INPUT); - #elif defined(ESP32) - if(pin == 9) { - pinMode(10, INPUT); - } else if(pin == 16) { - pinMode(17, INPUT); - } - #elif defined(ESP8266) - if(pin == 113) { - pinMode(15, INPUT); - } - #endif - - #if defined(ESP32) - hwSerial->onReceiveError(rxerr); - #endif - hanSerial = hwSerial; - if(swSerial != NULL) { - swSerial->end(); - delete swSerial; - swSerial = NULL; - } - } else { - debugD_P(PSTR("Software serial")); - Serial.flush(); - - if(swSerial == NULL) { - swSerial = new SoftwareSerial(pin, -1, invert); - } else { - swSerial->end(); - } - - SoftwareSerialConfig serialConfig; - switch(parityOrdinal) { - case 2: - serialConfig = SWSERIAL_7N1; - break; - case 3: - serialConfig = SWSERIAL_8N1; - break; - case 10: - serialConfig = SWSERIAL_7E1; - break; - default: - serialConfig = SWSERIAL_8E1; - break; - } - - #if defined(ESP8266) - if(meterConfig.bufferSize > 2) meterConfig.bufferSize = 2; - #endif - swSerial->begin(baud, serialConfig, pin, -1, invert, meterConfig.bufferSize * 64); - hanSerial = swSerial; - - Serial.end(); - Serial.begin(115200); - hwSerial = NULL; - } - - // The library automatically sets the pullup in Serial.begin() - if(!gpioConfig.hanPinPullup) { - debugI_P(PSTR("HAN pin pullup disabled")); - pinMode(gpioConfig.hanPin, INPUT); - } - - hanSerial->setTimeout(250); - - // Empty buffer before starting - while (hanSerial->available() > 0) { - hanSerial->read(); - } - #if defined(ESP8266) - if(hwSerial != NULL) { - hwSerial->hasOverrun(); - } else if(swSerial != NULL) { - swSerial->overflow(); - } - #endif -} - void errorBlink() { if(lastError == 3) lastError = 0; @@ -1078,14 +956,14 @@ void errorBlink() { } break; case 1: - if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) { + if(mqttHandler != NULL && mqttHandler->lastError() != 0) { debugW_P(PSTR("MQTT connection not available, double blink")); hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice return; } break; case 2: - if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) { + if(WiFi.getMode() == WIFI_STA && WiFi.status() != WL_CONNECTED) { debugW_P(PSTR("WiFi not connected, tripe blink")); hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times return; @@ -1095,22 +973,61 @@ void errorBlink() { } } -void swapWifiMode() { +void connectToNetwork() { + if(!handleVoltageCheck()) { + debugW_P(PSTR("Voltage is not high enough to reconnect")); + return; + } + NetworkConfig network; + if(config.getNetworkConfig(network)) { + if(network.mode == 0 || network.mode > 3) network.mode = NETWORK_MODE_WIFI_CLIENT; + if(ch != NULL && ch->getMode() != network.mode) { + delete ch; + ch = NULL; + } + switch(network.mode) { + case NETWORK_MODE_WIFI_CLIENT: + if(ch == NULL) { + ch = new WiFiClientConnectionHandler(&Debug); + } + break; + case NETWORK_MODE_WIFI_AP: + if(ch == NULL) { + ch = new WiFiAccessPointConnectionHandler(&Debug); + } + break; + case NETWORK_MODE_ETH_CLIENT: + if(ch == NULL) { + ch = new EthernetConnectionHandler(&Debug); + } + break; + default: + setupMode = false; + toggleSetupMode(); + } + ch->connect(network, sysConfig); + } else { + setupMode = false; + toggleSetupMode(); + } +} + +void toggleSetupMode() { if(!hw.ledOn(LED_YELLOW)) { hw.ledOn(LED_INTERNAL); } - WiFiMode_t mode = WiFi.getMode(); if(dnsServer != NULL) { dnsServer->stop(); } + WiFi.stopSmartConfig(); WiFi.disconnect(true); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_OFF); delay(10); yield(); - if (mode != WIFI_AP || !config.hasConfig()) { - if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Swapping to AP mode")); + if (!setupMode || !config.hasConfig()) { + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Entering setup mode")); //wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, 0); // Disable default gw @@ -1124,8 +1041,9 @@ void swapWifiMode() { }); */ + WiFi.mode(WIFI_AP_STA); + WiFi.beginSmartConfig(); WiFi.softAP(PSTR("AMS2MQTT")); - WiFi.mode(WIFI_AP); if(dnsServer == NULL) { dnsServer = new DNSServer(); @@ -1136,13 +1054,15 @@ void swapWifiMode() { Debug.setSerialEnabled(true); Debug.begin(F("192.168.4.1"), 23, RemoteDebug::VERBOSE); #endif + setupMode = true; } else { - if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Swapping to STA mode")); + if(Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Exiting setup mode")); if(dnsServer != NULL) { delete dnsServer; dnsServer = NULL; } - WiFi_connect(); + connectToNetwork(); + setupMode = false; } delay(500); if(!hw.ledOff(LED_YELLOW)) { @@ -1150,140 +1070,20 @@ void swapWifiMode() { } } -int len = 0; -bool serialInit = false; bool readHanPort() { - unsigned long start, end; - if(!hanSerial->available()) { + if(mc == NULL) return false; + if(!mc->loop()) { + meterState.setLastError(mc->getLastError()); return false; } - - // Before reading, empty serial buffer to increase chance of getting first byte of a data transfer - if(!serialInit) { - hanSerial->readBytes(hanBuffer, BUF_SIZE_HAN); - serialInit = true; - return false; + if(mc->isConfigChanged()) { + MeterConfig meterConfig; + mc->getCurrentConfig(meterConfig); + config.setMeterConfig(meterConfig); } + meterState.setLastError(mc->getLastError()); - DataParserContext ctx = {0,0,0,0}; - strcpy_P((char*) ctx.system_title, PSTR("")); - int pos = DATA_PARSE_INCOMPLETE; - // For each byte received, check if we have a complete frame we can handle - start = millis(); - while(hanSerial->available() && pos == DATA_PARSE_INCOMPLETE) { - // If buffer was overflowed, reset - if(len >= BUF_SIZE_HAN) { - hanSerial->readBytes(hanBuffer, BUF_SIZE_HAN); - len = 0; - debugI_P(PSTR("Buffer overflow, resetting")); - return false; - } - hanBuffer[len++] = hanSerial->read(); - ctx.length = len; - pos = unwrapData((uint8_t *) hanBuffer, ctx); - if(ctx.type > 0 && pos >= 0) { - if(ctx.type == DATA_TAG_DLMS) { - debugD_P(PSTR("Received valid DLMS at %d"), pos); - } else if(ctx.type == DATA_TAG_DSMR) { - debugD_P(PSTR("Received valid DSMR at %d"), pos); - } else { - // TODO: Move this so that payload is sent to MQTT - debugE_P(PSTR("Unknown tag %02X at pos %d"), ctx.type, pos); - len = 0; - return false; - } - } - yield(); - } - end = millis(); - if(end-start > 1000) { - debugW_P(PSTR("Used %dms to unwrap HAN data"), end-start); - } - - if(pos == DATA_PARSE_INCOMPLETE) { - return false; - } else if(pos == DATA_PARSE_UNKNOWN_DATA) { - debugW_P(PSTR("Unknown data received")); - meterState.setLastError(pos); - len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); - if(Debug.isActive(RemoteDebug::VERBOSE)) { - debugV_P(PSTR(" payload:")); - debugPrint(hanBuffer, 0, len); - } - len = 0; - return false; - } - - if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) { - len = 0; - return false; - } else if(pos < 0) { - meterState.setLastError(pos); - printHanReadError(pos); - len += hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); - if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { - mqtt->publish(topic.c_str(), toHex(hanBuffer+pos, len)); - mqtt->loop(); - delay(10); - } - while(hanSerial->available()) hanSerial->read(); // Make sure it is all empty, in case we overflowed buffer above - len = 0; - return false; - } - - // Data is valid, clear the rest of the buffer to avoid tainted parsing - for(int i = pos+ctx.length; ipublish(topic.c_str(), toHex((byte*) payload, ctx.length)); - mqtt->loop(); - delay(10); - } - - debugV_P(PSTR("Using application data:")); - if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length); - - // Rudimentary detector for L&G proprietary format, this is terrible code... Fix later - if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) { - debugV_P(PSTR("LNG")); - LNG lngData = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug); - if(lngData.getListType() >= 3) { - data = new AmsData(); - data->apply(meterState); - data->apply(lngData); - } - } else if(payload[0] == CosemTypeStructure && - payload[2] == CosemTypeLongUnsigned && - payload[5] == CosemTypeLongUnsigned && - payload[8] == CosemTypeLongUnsigned && - payload[11] == CosemTypeLongUnsigned && - payload[14] == CosemTypeLongUnsigned && - payload[17] == CosemTypeLongUnsigned - ) { - debugV_P(PSTR("LNG2")); - LNG2 lngData = LNG2(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug); - if(lngData.getListType() >= 3) { - data = new AmsData(); - data->apply(meterState); - data->apply(lngData); - } - } else { - debugV_P(PSTR("DLMS")); - // TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats - data = new IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx, meterState); - } - } else if(ctx.type == DATA_TAG_DSMR) { - data = new IEC6205621(payload, tz); - } - len = 0; + AmsData* data = mc->getData(meterState); if(data != NULL) { if(data->getListType() > 0) { @@ -1296,11 +1096,10 @@ bool readHanPort() { } void handleDataSuccess(AmsData* data) { - if(rxBufferErrors > 0) rxBufferErrors--; if(!hw.ledBlink(LED_GREEN, 1)) hw.ledBlink(LED_INTERNAL, 1); - if(mqttEnabled && mqttHandler != NULL && mqtt != NULL) { + if(mqttHandler != NULL) { #if defined(ESP32) esp_task_wdt_reset(); #elif defined(ESP8266) @@ -1308,10 +1107,14 @@ void handleDataSuccess(AmsData* data) { #endif yield(); if(mqttHandler->publish(data, &meterState, &ea, eapi)) { - mqtt->loop(); delay(10); } } + #if defined(ENERGY_SPEEDOMETER_PASS) + if(energySpeedometer != NULL && energySpeedometer->publish(&meterState, &meterState, &ea, eapi)) { + delay(10); + } + #endif time_t now = time(nullptr); if(now < FirmwareVersion::BuildEpoch && data->getListType() >= 3) { @@ -1329,6 +1132,7 @@ void handleDataSuccess(AmsData* data) { } meterState.apply(*data); + rtp.update(meterState); bool saveData = false; if(!ds.isHappy() && now > FirmwareVersion::BuildEpoch) { // Must use "isHappy()" in case day state gets reset and lastTimestamp is "now" @@ -1338,6 +1142,9 @@ void handleDataSuccess(AmsData* data) { if(tm.Minute == 0 && data->getListType() >= 3) { debugV_P(PSTR(" using actual data")); saveData = ds.update(data); + #if defined(ESP32) + if(saveData && cloud != NULL) cloud->forceUpdate(); + #endif } else if(tm.Minute == 1 && meterState.getListType() >= 3) { debugV_P(PSTR(" using estimated data")); saveData = ds.update(&meterState); @@ -1358,285 +1165,35 @@ void handleDataSuccess(AmsData* data) { } } -void printHanReadError(int pos) { - if(Debug.isActive(RemoteDebug::WARNING)) { - switch(pos) { - case DATA_PARSE_BOUNDRY_FLAG_MISSING: - debugW_P(PSTR("Boundry flag missing")); - break; - case DATA_PARSE_HEADER_CHECKSUM_ERROR: - debugW_P(PSTR("Header checksum error")); - break; - case DATA_PARSE_FOOTER_CHECKSUM_ERROR: - debugW_P(PSTR("Frame checksum error")); - break; - case DATA_PARSE_INCOMPLETE: - debugW_P(PSTR("Received frame is incomplete")); - break; - case GCM_AUTH_FAILED: - debugW_P(PSTR("Decrypt authentication failed")); - break; - case GCM_ENCRYPTION_KEY_FAILED: - debugW_P(PSTR("Setting decryption key failed")); - break; - case GCM_DECRYPT_FAILED: - debugW_P(PSTR("Decryption failed")); - break; - case MBUS_FRAME_LENGTH_NOT_EQUAL: - debugW_P(PSTR("Frame length mismatch")); - break; - case DATA_PARSE_INTERMEDIATE_SEGMENT: - debugI_P(PSTR("Intermediate segment received")); - break; - case DATA_PARSE_UNKNOWN_DATA: - debugW_P(PSTR("Unknown data format %02X"), hanBuffer[0]); - break; - default: - debugW_P(PSTR("Unspecified error while reading data: %d"), pos); - } +void postConnect() { + networkConnected = true; + + NetworkConfig network; + ch->getCurrentConfig(network); + if(ch->isConfigChanged()) { + config.setNetworkConfig(network); } -} - -void debugPrint(byte *buffer, int start, int length) { - for (int i = start; i < start + length; i++) { - if (buffer[i] < 0x10) - Debug.print(F("0")); - Debug.print(buffer[i], HEX); - Debug.print(F(" ")); - if ((i - start + 1) % 16 == 0) - Debug.println(F("")); - else if ((i - start + 1) % 4 == 0) - Debug.print(F(" ")); - - yield(); // Let other get some resources too + WebConfig web; + if(config.getWebConfig(web) && web.security > 0) { + Debug.setPassword(web.password); } - Debug.println(F("")); -} - -unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT; -unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT; - -void WiFi_disconnect(unsigned long timeout) { - if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Not connected to WiFi, closing resources")); - if(mqtt != NULL) { - mqtt->disconnect(); - mqtt->loop(); - delay(10); - yield(); - delete mqtt; - mqtt = NULL; - ws.setMqtt(NULL); - } - - if(mqttClient != NULL) { - mqttClient->stop(); - delete mqttClient; - mqttClient = NULL; - if(mqttSecureClient != NULL) { - mqttSecureClient = NULL; - } - } - - #if defined(ESP8266) - WiFiClient::stopAll(); - #endif - - MDNS.end(); - WiFi.disconnect(true); - WiFi.softAPdisconnect(true); - WiFi.enableAP(false); - WiFi.mode(WIFI_OFF); - yield(); - wifiTimeout = timeout; -} - -void WiFi_connect() { - if(millis() - lastWifiRetry < wifiTimeout) { - delay(50); - return; - } - lastWifiRetry = millis(); - - /* - if(!handleVoltageCheck()) { - debugW_P(PSTR("Voltage is not high enough to reconnect")); - return; - } - */ - - if (WiFi.status() != WL_CONNECTED) { - WiFiConfig wifi; - if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) { - swapWifiMode(); - return; - } - - if(WiFi.getMode() != WIFI_OFF) { - if(wifiReconnectCount > 3 && wifi.autoreboot) { - if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Unable to connect to WiFi, rebooting because auto reboot is enabled")); - ESP.restart(); - return; - } - WiFi_disconnect(5000); - return; - } - - wifiTimeout = WIFI_CONNECTION_TIMEOUT; - - if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Connecting to WiFi network: %s"), wifi.ssid); - - wifiReconnectCount++; - - #if defined(ESP32) - if(strlen(wifi.hostname) > 0) { - WiFi.setHostname(wifi.hostname); - } - #endif - WiFi.mode(WIFI_STA); - - if(strlen(wifi.ip) > 0) { - IPAddress ip, gw, sn(255,255,255,0), dns1, dns2; - ip.fromString(wifi.ip); - gw.fromString(wifi.gateway); - sn.fromString(wifi.subnet); - if(strlen(wifi.dns1) > 0) { - dns1.fromString(wifi.dns1); - } else if(strlen(wifi.gateway) > 0) { - dns1.fromString(wifi.gateway); // If no DNS, set gateway by default - } - if(strlen(wifi.dns2) > 0) { - dns2.fromString(wifi.dns2); - } else if(dns1.toString().isEmpty()) { - dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured - } - if(!WiFi.config(ip, gw, sn, dns1, dns2)) { - debugE_P(PSTR("Static IP configuration is invalid, not using")); - } - } - #if defined(ESP8266) - if(strlen(wifi.hostname) > 0) { - WiFi.hostname(wifi.hostname); - } - //wifi_set_phy_mode(PHY_MODE_11N); - if(!wifi.use11b) { - wifi_set_user_sup_rate(RATE_11G6M, RATE_11G54M); - wifi_set_user_rate_limit(RC_LIMIT_11G, 0x00, RATE_11G_G54M, RATE_11G_G6M); - wifi_set_user_rate_limit(RC_LIMIT_11N, 0x00, RATE_11N_MCS7S, RATE_11N_MCS0); - wifi_set_user_limit_rate_mask(LIMIT_RATE_MASK_ALL); - } - #endif - #if defined(ESP32) - WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); - WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); - #endif - WiFi.setAutoReconnect(true); - if(WiFi.begin(wifi.ssid, wifi.psk)) { - if(wifi.sleep <= 2) { - switch(wifi.sleep) { - case 0: - WiFi.setSleep(WIFI_PS_NONE); - break; - case 1: - WiFi.setSleep(WIFI_PS_MIN_MODEM); - break; - case 2: - WiFi.setSleep(WIFI_PS_MAX_MODEM); - break; - } - } - yield(); - } else { - if (Debug.isActive(RemoteDebug::ERROR)) debugI_P(PSTR("Unable to start WiFi")); - } - } -} - -void WiFi_post_connect() { - wifiConnected = true; - - WiFiConfig wifi; - if(config.getWiFiConfig(wifi)) { - #if defined(ESP32) - if(sysConfig.dataCollectionConsent == 0 && wifi.use11b) { - // If first boot and phyMode is better than 11b, disable 11b for BUS powered devices - switch(sysConfig.boardType) { - case 2: // spenceme - case 3: // Pow-K UART0 - case 4: // Pow-U UART0 - case 5: // Pow-K+ - case 6: // Pow-P1 - case 7: // Pow-U+ - case 8: // dbeinder: HAN mosquito - wifi_phy_mode_t phyMode; - if(esp_wifi_sta_get_negotiated_phymode(&phyMode) == ESP_OK) { - if(phyMode > WIFI_PHY_MODE_11B) { - debugI_P(PSTR("WiFi supports better rates than 802.11b, disabling")) - wifi.use11b = false; - config.setWiFiConfig(wifi); - return; - } - } - break; - } - } - - if(wifi.power >= 195) - WiFi.setTxPower(WIFI_POWER_19_5dBm); - else if(wifi.power >= 190) - WiFi.setTxPower(WIFI_POWER_19dBm); - else if(wifi.power >= 185) - WiFi.setTxPower(WIFI_POWER_18_5dBm); - else if(wifi.power >= 170) - WiFi.setTxPower(WIFI_POWER_17dBm); - else if(wifi.power >= 150) - WiFi.setTxPower(WIFI_POWER_15dBm); - else if(wifi.power >= 130) - WiFi.setTxPower(WIFI_POWER_13dBm); - else if(wifi.power >= 110) - WiFi.setTxPower(WIFI_POWER_11dBm); - else if(wifi.power >= 85) - WiFi.setTxPower(WIFI_POWER_8_5dBm); - else if(wifi.power >= 70) - WiFi.setTxPower(WIFI_POWER_7dBm); - else if(wifi.power >= 50) - WiFi.setTxPower(WIFI_POWER_5dBm); - else if(wifi.power >= 20) - WiFi.setTxPower(WIFI_POWER_2dBm); - else - WiFi.setTxPower(WIFI_POWER_MINUS_1dBm); - #elif defined(ESP8266) - WiFi.setOutputPower(wifi.power / 10.0); - #endif - - - WebConfig web; - if(config.getWebConfig(web) && web.security > 0) { - Debug.setPassword(web.password); - } - DebugConfig debug; - if(config.getDebugConfig(debug)) { - Debug.begin(wifi.hostname, debug.serial || debug.telnet ? (uint8_t) debug.level : RemoteDebug::WARNING); // I don't know why, but ESP8266 stops working after a while if ERROR level is set - if(!debug.telnet) { - Debug.stop(); - } - } else { + DebugConfig debug; + if(config.getDebugConfig(debug)) { + Debug.begin(network.hostname, debug.serial || debug.telnet ? (uint8_t) debug.level : RemoteDebug::WARNING); // I don't know why, but ESP8266 stops working after a while if ERROR level is set + if(!debug.telnet) { Debug.stop(); } - if(Debug.isActive(RemoteDebug::INFO)) { - debugI_P(PSTR("Successfully connected to WiFi!")); - debugI_P(PSTR("IP: %s"), WiFi.localIP().toString().c_str()); - debugI_P(PSTR("GW: %s"), WiFi.gatewayIP().toString().c_str()); - debugI_P(PSTR("DNS: %s"), WiFi.dnsIP().toString().c_str()); - } - mdnsEnabled = false; - if(strlen(wifi.hostname) > 0 && wifi.mdns) { - debugD_P(PSTR("mDNS is enabled, using host: %s"), wifi.hostname); - if(MDNS.begin(wifi.hostname)) { - mdnsEnabled = true; - MDNS.addService(F("http"), F("tcp"), 80); - } else { - debugE_P(PSTR("Failed to set up mDNS!")); - } + } else { + Debug.stop(); + } + mdnsEnabled = false; + if(strlen(network.hostname) > 0 && network.mdns) { + debugD_P(PSTR("mDNS is enabled, using host: %s"), network.hostname); + if(MDNS.begin(network.hostname)) { + mdnsEnabled = true; + MDNS.addService(F("http"), F("tcp"), 80); + } else { + debugE_P(PSTR("Failed to set up mDNS!")); } } @@ -1647,321 +1204,60 @@ void WiFi_post_connect() { } } -void mqttMessageReceived(String &topic, String &payload) { - debugI_P(PSTR("Received message for topic %s"), topic.c_str() ); - //if(meterConfig.source == METER_SOURCE_MQTT) { - //DataParserContext ctx = {static_cast(payload.length()/2)}; - //fromHex(hanBuffer, payload, ctx.length); - //uint16_t pos = unwrapData(hanBuffer, ctx); - // TODO: Run through DLMS/DMSR parser and apply AmsData - //} -} - -int16_t unwrapData(uint8_t *buf, DataParserContext &context) { - int16_t ret = 0; - bool doRet = false; - uint16_t end = BUF_SIZE_HAN; - uint8_t tag = (*buf); - uint8_t lastTag = DATA_TAG_NONE; - while(tag != DATA_TAG_NONE) { - int16_t curLen = context.length; - int8_t res = 0; - switch(tag) { - case DATA_TAG_HDLC: - if(hdlcParser == NULL) hdlcParser = new HDLCParser(); - res = hdlcParser->parse(buf, context); - break; - case DATA_TAG_MBUS: - if(mbusParser == NULL) mbusParser = new MBUSParser(); - res = mbusParser->parse(buf, context); - break; - case DATA_TAG_GBT: - if(gbtParser == NULL) gbtParser = new GBTParser(); - res = gbtParser->parse(buf, context); - break; - case DATA_TAG_GCM: - if(gcmParser == NULL) gcmParser = new GCMParser(meterConfig.encryptionKey, meterConfig.authenticationKey); - res = gcmParser->parse(buf, context); - break; - case DATA_TAG_LLC: - if(llcParser == NULL) llcParser = new LLCParser(); - res = llcParser->parse(buf, context); - break; - case DATA_TAG_DLMS: - if(dlmsParser == NULL) dlmsParser = new DLMSParser(); - res = dlmsParser->parse(buf, context); - if(res >= 0) doRet = true; - break; - case DATA_TAG_DSMR: - if(dsmrParser == NULL) dsmrParser = new DSMRParser(); - res = dsmrParser->parse(buf, context, lastTag != DATA_TAG_NONE); - if(res >= 0) doRet = true; - break; - default: - debugE_P(PSTR("Ended up in default case while unwrapping...(tag %02X)"), tag); - return DATA_PARSE_UNKNOWN_DATA; - } - lastTag = tag; - if(res == DATA_PARSE_INCOMPLETE) { - return res; - } - if(context.length > end) return false; - if(Debug.isActive(RemoteDebug::VERBOSE)) { - switch(tag) { - case DATA_TAG_HDLC: - debugV_P(PSTR("HDLC frame:")); - // If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT - if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { - mqtt->publish(topic.c_str(), toHex(buf, curLen)); - mqtt->loop(); - delay(10); - } - break; - case DATA_TAG_MBUS: - debugV_P(PSTR("MBUS frame:")); - // If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT - if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { - mqtt->publish(topic.c_str(), toHex(buf, curLen)); - mqtt->loop(); - delay(10); - } - break; - case DATA_TAG_GBT: - debugV_P(PSTR("GBT frame:")); - break; - case DATA_TAG_GCM: - debugV_P(PSTR("GCM frame:")); - break; - case DATA_TAG_LLC: - debugV_P(PSTR("LLC frame:")); - break; - case DATA_TAG_DLMS: - debugV_P(PSTR("DLMS frame:")); - break; - case DATA_TAG_DSMR: - debugV_P(PSTR("DSMR frame:")); - if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) { - mqtt->publish(topic.c_str(), (char*) buf); - mqtt->loop(); - delay(10); - } - break; - } - debugPrint(buf, 0, curLen); - } - if(res == DATA_PARSE_FINAL_SEGMENT) { - if(tag == DATA_TAG_MBUS) { - res = mbusParser->write(buf, context); - } - } - - if(res < 0) { - return res; - } - buf += res; - end -= res; - ret += res; - - // If we are ready to return, do that - if(doRet) { - context.type = tag; - return ret; - } - - // Use start byte of new buffer position as tag for next round in loop - tag = (*buf); - } - debugE_P(PSTR("Got to end of unwrap method...")); - return DATA_PARSE_UNKNOWN_DATA; -} unsigned long lastMqttRetry = -10000; void MQTT_connect() { + if(millis() - lastMqttRetry < (config.isMqttChanged() ? 5000 : 30000)) { + yield(); + return; + } + lastMqttRetry = millis(); + MqttConfig mqttConfig; if(!config.getMqttConfig(mqttConfig) || strlen(mqttConfig.host) == 0) { if(Debug.isActive(RemoteDebug::WARNING)) debugW_P(PSTR("No MQTT config")); - mqttEnabled = false; ws.setMqttEnabled(false); + mqttEnabled = false; return; } - if(mqtt != NULL) { - if(millis() - lastMqttRetry < (mqtt->lastError() == 0 || config.isMqttChanged() ? 5000 : 30000)) { - yield(); - return; - } - lastMqttRetry = millis(); - - if(Debug.isActive(RemoteDebug::INFO)) { - debugD_P(PSTR("Disconnecting MQTT before connecting")); - } - - mqtt->disconnect(); - if(config.isMqttChanged()) { - if(mqttSecureClient != NULL) { - mqttSecureClient->stop(); - delete mqttSecureClient; - mqttSecureClient = NULL; - } else { - mqttClient->stop(); - } - mqttClient = NULL; - } - yield(); - } else { - mqtt = new MQTTClient(256); - mqtt->dropOverflow(true); - ws.setMqtt(mqtt); - } - mqttEnabled = true; ws.setMqttEnabled(true); - topic = String(mqttConfig.publishTopic); - if(mqttHandler != NULL) { + if(mqttHandler != NULL && mqttHandler->getFormat() != mqttConfig.payloadFormat) { delete mqttHandler; mqttHandler = NULL; } - switch(mqttConfig.payloadFormat) { - case 0: - mqttHandler = new JsonMqttHandler(mqtt, (char*) commonBuffer, mqttConfig.clientId, mqttConfig.publishTopic, &hw); - break; - case 1: - case 2: - mqttHandler = new RawMqttHandler(mqtt, (char*) commonBuffer, mqttConfig.publishTopic, mqttConfig.payloadFormat == 2); - break; - case 3: - DomoticzConfig domo; - config.getDomoticzConfig(domo); - mqttHandler = new DomoticzMqttHandler(mqtt, (char*) commonBuffer, domo); - break; - case 4: - HomeAssistantConfig haconf; - config.getHomeAssistantConfig(haconf); - mqttHandler = new HomeAssistantMqttHandler(mqtt, (char*) commonBuffer, mqttConfig.clientId, mqttConfig.publishTopic, sysConfig.boardType, haconf, &hw); - break; - } - - time_t epoch = time(nullptr); - if(mqttConfig.ssl) { - if(epoch < FirmwareVersion::BuildEpoch) { - debugI_P(PSTR("NTP not ready for MQTT SSL")); - return; - } - debugI_P(PSTR("MQTT SSL is configured (%dkb free heap)"), ESP.getFreeHeap()); - if(mqttSecureClient == NULL) { - mqttSecureClient = new WiFiClientSecure(); - #if defined(ESP8266) - mqttSecureClient->setBufferSizes(512, 512); - debugD_P(PSTR("ESP8266 firmware does not have enough memory...")); - return; - #endif - - if(LittleFS.begin()) { - File file; - - if(LittleFS.exists(FILE_MQTT_CA)) { - debugI_P(PSTR("Found MQTT CA file (%dkb free heap)"), ESP.getFreeHeap()); - file = LittleFS.open(FILE_MQTT_CA, (char*) "r"); - #if defined(ESP8266) - BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file); - mqttSecureClient->setTrustAnchors(serverTrustedCA); - #elif defined(ESP32) - if(mqttSecureClient->loadCACert(file, file.size())) { - debugI_P(PSTR("CA accepted")); - } else { - debugW_P(PSTR("CA was rejected")); - delete mqttSecureClient; - mqttSecureClient = NULL; - return; - } - #endif - file.close(); - - if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) { - #if defined(ESP8266) - debugI_P(PSTR("Found MQTT certificate file (%dkb free heap)"), ESP.getFreeHeap()); - file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); - BearSSL::X509List *serverCertList = new BearSSL::X509List(file); - file.close(); - - debugI_P(PSTR("Found MQTT key file (%dkb free heap)"), ESP.getFreeHeap()); - file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); - BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file); - file.close(); - - debugD_P(PSTR("Setting client certificates (%dkb free heap)"), ESP.getFreeHeap()); - mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey); - #elif defined(ESP32) - debugI_P(PSTR("Found MQTT certificate file (%dkb free heap)"), ESP.getFreeHeap()); - file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); - mqttSecureClient->loadCertificate(file, file.size()); - file.close(); - - debugI_P(PSTR("Found MQTT key file (%dkb free heap)"), ESP.getFreeHeap()); - file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); - mqttSecureClient->loadPrivateKey(file, file.size()); - file.close(); - #endif - } - } else { - debugI_P(PSTR("No CA, disabling certificate validation")); - mqttSecureClient->setInsecure(); - } - mqttClient = mqttSecureClient; - - LittleFS.end(); - debugD_P(PSTR("MQTT SSL setup complete (%dkb free heap)"), ESP.getFreeHeap()); - } + if(mqttHandler == NULL) { + switch(mqttConfig.payloadFormat) { + case 0: + mqttHandler = new JsonMqttHandler(mqttConfig, &Debug, (char*) commonBuffer, &hw); + break; + case 1: + case 2: + mqttHandler = new RawMqttHandler(mqttConfig, &Debug, (char*) commonBuffer); + break; + case 3: + DomoticzConfig domo; + config.getDomoticzConfig(domo); + mqttHandler = new DomoticzMqttHandler(mqttConfig, &Debug, (char*) commonBuffer, domo); + break; + case 4: + HomeAssistantConfig haconf; + config.getHomeAssistantConfig(haconf); + mqttHandler = new HomeAssistantMqttHandler(mqttConfig, &Debug, (char*) commonBuffer, sysConfig.boardType, haconf, &hw); + break; + case 255: + mqttHandler = new PassthroughMqttHandler(mqttConfig, &Debug, (char*) commonBuffer); + break; } } - - if(mqttClient == NULL) { - debugI_P(PSTR("No SSL, using client without SSL support")); - mqttClient = new WiFiClient(); + ws.setMqttHandler(mqttHandler); + + if(mqttHandler != NULL) { + mqttHandler->connect(); + mqttHandler->publishSystem(&hw, eapi, &ea); } - - if(Debug.isActive(RemoteDebug::INFO)) { - debugI_P(PSTR("Connecting to MQTT %s:%d"), mqttConfig.host, mqttConfig.port); - } - - mqtt->begin(mqttConfig.host, mqttConfig.port, *mqttClient); - - #if defined(ESP8266) - if(mqttSecureClient) { - time_t epoch = time(nullptr); - debugD_P(PSTR("Setting NTP time %lu for secure MQTT connection"), epoch); - mqttSecureClient->setX509Time(epoch); - } - #endif - - // Connect to a unsecure or secure MQTT server - if ((strlen(mqttConfig.username) == 0 && mqtt->connect(mqttConfig.clientId)) || - (strlen(mqttConfig.username) > 0 && mqtt->connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) { - if (Debug.isActive(RemoteDebug::INFO)) debugI_P(PSTR("Successfully connected to MQTT!")); - - if(mqttHandler != NULL) { - mqttHandler->publishSystem(&hw, eapi, &ea); - } - - // Subscribe to the chosen MQTT topic, if set in configuration - if (strlen(mqttConfig.subscribeTopic) > 0) { - mqtt->onMessage(mqttMessageReceived); - mqtt->subscribe(String(mqttConfig.subscribeTopic) + "/#"); - debugI_P(PSTR(" Subscribing to [%s]\n"), mqttConfig.subscribeTopic); - } - } else { - if (Debug.isActive(RemoteDebug::ERROR)) { - debugE_P(PSTR("Failed to connect to MQTT: %d"), mqtt->lastError()); - #if defined(ESP8266) - if(mqttSecureClient) { - mqttSecureClient->getLastSSLError((char*) commonBuffer, BUF_SIZE_COMMON); - Debug.println((char*) commonBuffer); - } - #endif - } - } - yield(); } void configFileParse() { @@ -1975,7 +1271,7 @@ void configFileParse() { File file = LittleFS.open(FILE_CFG, (char*) "r"); bool lSys = false; - bool lWiFi = false; + bool lNetwork = false; bool lMqtt = false; bool lWeb = false; bool lMeter = false; @@ -1991,7 +1287,7 @@ void configFileParse() { ds.load(); SystemConfig sys; - WiFiConfig wifi; + NetworkConfig network; MqttConfig mqtt; WebConfig web; MeterConfig meter; @@ -2017,36 +1313,39 @@ void configFileParse() { if(strncmp_P(buf, PSTR("boardType "), 10) == 0) { if(!lSys) { config.getSystemConfig(sys); lSys = true; }; sys.boardType = String(buf+10).toInt(); + } else if(strncmp_P(buf, PSTR("netmode "), 8) == 0) { + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + network.mode = String(buf+5).toInt(); } else if(strncmp_P(buf, PSTR("ssid "), 5) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.ssid, buf+5); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.ssid, buf+5); } else if(strncmp_P(buf, PSTR("psk "), 4) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.psk, buf+4); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.psk, buf+4); } else if(strncmp_P(buf, PSTR("ip "), 3) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.ip, buf+3); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.ip, buf+3); } else if(strncmp_P(buf, PSTR("gateway "), 8) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.gateway, buf+8); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.gateway, buf+8); } else if(strncmp_P(buf, PSTR("subnet "), 7) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.subnet, buf+7); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.subnet, buf+7); } else if(strncmp_P(buf, PSTR("dns1 "), 5) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.dns1, buf+5); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.dns1, buf+5); } else if(strncmp_P(buf, PSTR("dns2 "), 5) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.dns2, buf+5); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.dns2, buf+5); } else if(strncmp_P(buf, PSTR("hostname "), 9) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - strcpy(wifi.hostname, buf+9); + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + strcpy(network.hostname, buf+9); } else if(strncmp_P(buf, PSTR("use11b "), 7) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - wifi.use11b = String(buf+7).toInt() == 1; + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + network.use11b = String(buf+7).toInt() == 1; } else if(strncmp_P(buf, PSTR("mdns "), 5) == 0) { - if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; - wifi.mdns = String(buf+5).toInt() == 1;; + if(!lNetwork) { config.getNetworkConfig(network); lNetwork = true; }; + network.mdns = String(buf+5).toInt() == 1;; } else if(strncmp_P(buf, PSTR("mqttHost "), 9) == 0) { if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; strcpy(mqtt.host, buf+9); @@ -2108,11 +1407,11 @@ void configFileParse() { if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; fromHex(meter.authenticationKey, String(buf+23), 16); } else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) { - if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; - gpio.hanPin = String(buf+11).toInt(); + if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; + meter.rxPin = String(buf+11).toInt(); } else if(strncmp_P(buf, PSTR("gpioHanPinPullup "), 17) == 0) { - if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; - gpio.hanPinPullup = String(buf+17).toInt() == 1; + if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; + meter.rxPinPullup = String(buf+17).toInt() == 1; } else if(strncmp_P(buf, PSTR("gpioApPin "), 10) == 0) { if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; gpio.apPin = String(buf+10).toInt(); @@ -2433,7 +1732,7 @@ void configFileParse() { debugI_P(PSTR("Saving configuration now...")); Serial.flush(); if(lSys) config.setSystemConfig(sys); - if(lWiFi) config.setWiFiConfig(wifi); + if(lNetwork) config.setNetworkConfig(network); if(lMqtt) config.setMqttConfig(mqtt); if(lWeb) config.setWebConfig(web); if(lMeter) config.setMeterConfig(meter); diff --git a/src/AmsToMqttBridge.h b/src/AmsToMqttBridge.h deleted file mode 100644 index 34f41b7b..00000000 --- a/src/AmsToMqttBridge.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _AMSTOMQTTBRIDGE_H -#define _AMSTOMQTTBRIDGE_H - -#define WIFI_CONNECTION_TIMEOUT 30000 - -#define INVALID_BUTTON_PIN 0xFFFFFFFF - -#define MAX_PEM_SIZE 4096 - -#define METER_SOURCE_NONE 0 -#define METER_SOURCE_SERIAL 1 -#define METER_SOURCE_MQTT 2 -#define METER_SOURCE_ESPNOW 3 - -#define METER_ERROR_NO_DATA 90 -#define METER_ERROR_BREAK 91 -#define METER_ERROR_BUFFER 92 -#define METER_ERROR_FIFO 93 -#define METER_ERROR_FRAME 94 -#define METER_ERROR_PARITY 95 -#define METER_ERROR_RX 96 -#define METER_ERROR_EXCEPTION 98 -#define METER_ERROR_AUTODETECT 99 - -#include - -#if defined(ESP8266) -#include -#include -#elif defined(ESP32) -#include -#include -#include -#include "Update.h" -#endif - -#include "LittleFS.h" - -#endif diff --git a/src/ConnectionHandler.h b/src/ConnectionHandler.h new file mode 100644 index 00000000..331c82a4 --- /dev/null +++ b/src/ConnectionHandler.h @@ -0,0 +1,41 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _CONNECTIONHANDLER_H +#define _CONNECTIONHANDLER_H + +#include "AmsConfiguration.h" +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif + +#define NETWORK_MODE_WIFI_CLIENT 1 +#define NETWORK_MODE_WIFI_AP 2 +#define NETWORK_MODE_ETH_CLIENT 3 + +class ConnectionHandler { +public: + virtual ~ConnectionHandler() {}; + virtual bool connect(NetworkConfig config, SystemConfig sys); + virtual void disconnect(unsigned long reconnectDelay); + virtual bool isConnected(); + virtual bool isConfigChanged(); + virtual void getCurrentConfig(NetworkConfig& networkConfig); + #if defined(ESP32) + virtual void eventHandler(WiFiEvent_t event, WiFiEventInfo_t info); + #endif + + uint8_t getMode() { + return this->mode; + } + +protected: + uint8_t mode; +}; + +#endif diff --git a/src/EthernetConnectionHandler.cpp b/src/EthernetConnectionHandler.cpp new file mode 100644 index 00000000..96b25eb3 --- /dev/null +++ b/src/EthernetConnectionHandler.cpp @@ -0,0 +1,148 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "EthernetConnectionHandler.h" + +#if defined(ESP32) +#include +#endif + +EthernetConnectionHandler::EthernetConnectionHandler(RemoteDebug* debugger) { + this->debugger = debugger; + this->mode = NETWORK_MODE_ETH_CLIENT; +} + +bool EthernetConnectionHandler::connect(NetworkConfig config, SystemConfig sys) { + if(lastRetry > 0 && (millis() - lastRetry) < timeout) { + delay(50); + return false; + } + lastRetry = millis(); + + #if defined(ESP32) + if (!connected) { + eth_phy_type_t ethType = ETH_PHY_LAN8720; + eth_clock_mode_t ethClkMode = ETH_CLOCK_GPIO0_IN; + uint8_t ethAddr = 0; + int8_t ethPowerPin = -1; + uint8_t ethEnablePin = 0; + uint8_t ethMdc = 0; + uint8_t ethMdio = 0; + + if(sys.boardType == 241) { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("LilyGO T-ETH-POE\n")); + ethType = ETH_PHY_LAN8720; + ethEnablePin = -1; + ethAddr = 0; + ethClkMode = ETH_CLOCK_GPIO17_OUT; + ethPowerPin = 5; + ethMdc = 23; + ethMdio = 18; + } else if(sys.boardType == 242) { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("M5 PoESP32\n")); + ethType = ETH_PHY_IP101; + ethEnablePin = -1; + ethAddr = 1; + ethClkMode = ETH_CLOCK_GPIO0_IN; + ethPowerPin = 5; + ethMdc = 23; + ethMdio = 18; + } else if(sys.boardType == 243) { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("WT32-ETH01\n")); + ethType = ETH_PHY_LAN8720; + ethEnablePin = -1; + ethAddr = 1; + ethClkMode = ETH_CLOCK_GPIO17_OUT; + ethPowerPin = 16; + ethMdc = 23; + ethMdio = 18; + } else { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Board type %d incompatible with ETH\n"), sys.boardType); + return false; + } + + if(ethEnablePin > 0) { + pinMode(ethEnablePin, OUTPUT); + digitalWrite(ethEnablePin, 1); + } + + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Connecting to Ethernet\n")); + + #if defined(ESP32) + if(strlen(config.hostname) > 0) { + ETH.setHostname(config.hostname); + } + #endif + + if(strlen(config.ip) > 0) { + IPAddress ip, gw, sn(255,255,255,0), dns1, dns2; + ip.fromString(config.ip); + gw.fromString(config.gateway); + sn.fromString(config.subnet); + if(strlen(config.dns1) > 0) { + dns1.fromString(config.dns1); + } else if(strlen(config.gateway) > 0) { + dns1.fromString(config.gateway); // If no DNS, set gateway by default + } + if(strlen(config.dns2) > 0) { + dns2.fromString(config.dns2); + } else if(dns1.toString().isEmpty()) { + dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured + } + if(!ETH.config(ip, gw, sn, dns1, dns2)) { + debugger->printf_P(PSTR("Static IP configuration is invalid, not using\n")); + } + } + + if (!ETH.begin(ethAddr, ethPowerPin, ethMdc, ethMdio, ethType, ethClkMode)) { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Unable to start Ethernet\n")); + } + } + #endif + return false; +} + +void EthernetConnectionHandler::disconnect(unsigned long reconnectDelay) { + // TODO +} + +bool EthernetConnectionHandler::isConnected() { + return connected; +} + +#if defined(ESP32) +void EthernetConnectionHandler::eventHandler(WiFiEvent_t event, WiFiEventInfo_t info) { + switch(event) { + case ARDUINO_EVENT_ETH_CONNECTED: + connected = true; + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Successfully connected to Ethernet!\n")); + } + break; + case ARDUINO_EVENT_ETH_GOT_IP: + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("IP: %s\n"), ETH.localIP().toString().c_str()); + debugger->printf_P(PSTR("GW: %s\n"), ETH.gatewayIP().toString().c_str()); + debugger->printf_P(PSTR("DNS: %s\n"), ETH.dnsIP().toString().c_str()); + } + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + connected = false; + if(debugger->isActive(RemoteDebug::WARNING)) { + debugger->printf_P(PSTR("Ethernet was disconnected!\n")); + } + break; + } +} +#endif + +bool EthernetConnectionHandler::isConfigChanged() { + return configChanged; +} + +void EthernetConnectionHandler::getCurrentConfig(NetworkConfig& networkConfig) { + networkConfig = this->config; +} \ No newline at end of file diff --git a/src/EthernetConnectionHandler.h b/src/EthernetConnectionHandler.h new file mode 100644 index 00000000..a02ced40 --- /dev/null +++ b/src/EthernetConnectionHandler.h @@ -0,0 +1,40 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _ETHERNETCONNECTIONHANDLER_H +#define _ETHERNETCONNECTIONHANDLER_H + +#include "ConnectionHandler.h" +#include +#include "RemoteDebug.h" + +#define CONNECTION_TIMEOUT 30000 + +class EthernetConnectionHandler : public ConnectionHandler { +public: + EthernetConnectionHandler(RemoteDebug* debugger); + + bool connect(NetworkConfig config, SystemConfig sys); + void disconnect(unsigned long reconnectDelay); + bool isConnected(); + bool isConfigChanged(); + void getCurrentConfig(NetworkConfig& networkConfig); + + #if defined(ESP32) + void eventHandler(WiFiEvent_t event, WiFiEventInfo_t info); + #endif + +private: + RemoteDebug* debugger; + NetworkConfig config; + + bool connected = false; + bool configChanged = false; + unsigned long timeout = CONNECTION_TIMEOUT; + unsigned long lastRetry = 0; +}; + +#endif diff --git a/src/IEC6205621.cpp b/src/IEC6205621.cpp index 0d0c7851..5d77f634 100644 --- a/src/IEC6205621.cpp +++ b/src/IEC6205621.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "IEC6205621.h" #include "Uptime.h" diff --git a/src/IEC6205621.h b/src/IEC6205621.h index 5ee1d7f7..8551016d 100644 --- a/src/IEC6205621.h +++ b/src/IEC6205621.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _IEC62056_21_H #define _IEC62056_21_H diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index 5dc8f03f..84a860dc 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "IEC6205675.h" #include "lwip/def.h" #include "Timezone.h" diff --git a/src/IEC6205675.h b/src/IEC6205675.h index dba6c333..53d3822b 100644 --- a/src/IEC6205675.h +++ b/src/IEC6205675.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _IEC62056_7_5_H #define _IEC62056_7_5_H diff --git a/src/KamstrupPullCommunicator.cpp b/src/KamstrupPullCommunicator.cpp new file mode 100644 index 00000000..32d9840e --- /dev/null +++ b/src/KamstrupPullCommunicator.cpp @@ -0,0 +1,784 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "KamstrupPullCommunicator.h" +#include "Uptime.h" +#include "Cosem.h" + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) +#include +#endif + +void KamstrupPullCommunicator::configure(MeterConfig& meterConfig, Timezone* tz) { + this->meterConfig = meterConfig; + this->configChanged = false; + this->tz = tz; + setupHanPort(meterConfig.baud, meterConfig.parity, meterConfig.invert); +} + +bool KamstrupPullCommunicator::loop() { + uint64_t now = millis64(); + if(PassiveMeterCommunicator::loop() || now-lastLoop > 5000) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("State: %d\n"), state); + lastLoop = now; + switch(state) { + case STATE_DISCONNECTED: + sendConnectMessage(); + lastMessageTime = now; + break; + + case STATE_CONNECTING: + if(!checkForConnectConfirmed() && now-lastMessageTime > 10000) { + state = STATE_DISCONNECTED; + lastLoop = 0; + } + break; + + case STATE_CONNECTED_NOT_ASSOCIATED: + sendAssociateMessage(); + lastMessageTime = now; + break; + + case STATE_CONNECTED_ASSOCIATING: + if(!checkForAssociationConfirmed() && now-lastMessageTime > 10000) { + state = STATE_CONNECTION_BROKEN; // TODO: Use state: Broken + lastLoop = 0; + } + break; + + case STATE_CONNECTED_ASSOCIATED: + if(dataAvailable) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Data is available: %lu\n"), ctx.length); + return true; + } else { + lastMessageTime = now; + requestData(); + } + break; + + case STATE_DISCONNECT: + case STATE_CONNECTION_BROKEN: + sendDisconnectMessage(); + lastMessageTime = now; + break; + + case STATE_DISCONNECTING: + if(!checkForDisconnectMessage() && now-lastMessageTime > 10000) { + state = STATE_DISCONNECTED; + lastLoop = 0; + } + break; + + default: + state = STATE_DISCONNECTED; + } + } + return false; +} + +void KamstrupPullCommunicator::setupHanPort(uint32_t baud, uint8_t parityOrdinal, bool invert) { + uint8_t rxPin = meterConfig.rxPin; + uint8_t txPin = meterConfig.txPin; + + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(setupHanPort) Setting up HAN on pin %d/%d with baud %d and parity %d\n"), rxPin, txPin, baud, parityOrdinal); + + if(rxPin == 3 || rxPin == 113) { + #if ARDUINO_USB_CDC_ON_BOOT + hwSerial = &Serial0; + #else + hwSerial = &Serial; + #endif + } + + #if defined(ESP32) + if(rxPin == 9) { + hwSerial = &Serial1; + } + #if defined(CONFIG_IDF_TARGET_ESP32) + if(rxPin == 16) { + hwSerial = &Serial2; + } + #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + hwSerial = &Serial1; + #endif + #endif + + if(rxPin == 0) { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Invalid GPIO configured for HAN RX\n")); + return; + } + if(txPin == 0) { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Invalid GPIO configured for HAN TX\n")); + return; + } + + if(meterConfig.bufferSize < 1) meterConfig.bufferSize = 1; + + if(hwSerial != NULL) { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Hardware serial\n")); + Serial.flush(); + #if defined(ESP8266) + SerialConfig serialConfig; + #elif defined(ESP32) + uint32_t serialConfig; + #endif + switch(parityOrdinal) { + case 2: + serialConfig = SERIAL_7N1; + break; + case 3: + serialConfig = SERIAL_8N1; + break; + case 10: + serialConfig = SERIAL_7E1; + break; + default: + serialConfig = SERIAL_8E1; + break; + } + if(meterConfig.bufferSize < 4) meterConfig.bufferSize = 4; // 64 bytes (1) is default for software serial, 256 bytes (4) for hardware + + hwSerial->setRxBufferSize(64 * meterConfig.bufferSize); + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + hwSerial->begin(baud, serialConfig, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, invert); + uart_set_pin(UART_NUM_1, txPin == 0xFF ? UART_PIN_NO_CHANGE : txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + #elif defined(ESP32) + hwSerial->begin(baud, serialConfig, -1, -1, invert); + #else + hwSerial->begin(baud, serialConfig, SERIAL_FULL, 1, invert); + #endif + + #if defined(ESP8266) + if(rxPin == 3) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Switching UART0 to pin 1 & 3\n")); + Serial.pins(1,3); + } else if(rxPin == 113) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Switching UART0 to pin 15 & 13\n")); + Serial.pins(15,13); + } + #endif + + // Prevent pullup on TX pin if not uart0 + #if defined(CONFIG_IDF_TARGET_ESP32S2) + if(txPin != 17) pinMode(17, INPUT); + #elif defined(CONFIG_IDF_TARGET_ESP32C3) + if(txPin != 7) pinMode(7, INPUT); + #elif defined(ESP32) + if(rxPin == 9) { + if(txPin != 10) pinMode(10, INPUT); + } else if(rxPin == 16) { + if(txPin != 17) pinMode(17, INPUT); + } + #elif defined(ESP8266) + if(rxPin == 113) { + if(txPin != 15) pinMode(15, INPUT); + } + #endif + + hanSerial = hwSerial; + if(swSerial != NULL) { + swSerial->end(); + delete swSerial; + swSerial = NULL; + } + } else { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Software serial\n")); + Serial.flush(); + + if(swSerial == NULL) { + swSerial = new SoftwareSerial(rxPin, txPin == 0xFF ? -1 : txPin, invert); + } else { + swSerial->end(); + } + + SoftwareSerialConfig serialConfig; + switch(parityOrdinal) { + case 2: + serialConfig = SWSERIAL_7N1; + break; + case 3: + serialConfig = SWSERIAL_8N1; + break; + case 10: + serialConfig = SWSERIAL_7E1; + break; + default: + serialConfig = SWSERIAL_8E1; + break; + } + + swSerial->begin(baud, serialConfig, rxPin, txPin == 0xFF ? -1 : txPin, invert, meterConfig.bufferSize * 64); + hanSerial = swSerial; + + Serial.end(); + Serial.begin(115200); + hwSerial = NULL; + } + + // The library automatically sets the pullup in Serial.begin() + if(!meterConfig.rxPinPullup) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("HAN pin pullup disabled\n")); + pinMode(meterConfig.rxPin, INPUT); + } + + hanSerial->setTimeout(250); + + // Empty buffer before starting + while (hanSerial->available() > 0) { + hanSerial->read(); + } + #if defined(ESP8266) + if(hwSerial != NULL) { + hwSerial->hasOverrun(); + } else if(swSerial != NULL) { + swSerial->overflow(); + } + #endif +} + +// 7E A0 15 21 03 52 5D 8A E6 E7 00 C4 01 81 00 06 00 BC 61 4F E4 36 7E +AmsData* KamstrupPullCommunicator::getData(AmsData& meterState) { + if(!dataAvailable) return NULL; + if(ctx.length > BUF_SIZE_HAN) { + debugger->printf_P(PSTR("Invalid context length %lu\n"), ctx.length); + dataAvailable = false; + return NULL; + } + + if(hanBuffer[5] == 0x51) { + if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Request was denied\n")); + len = 0; + dataAvailable = false; + state = STATE_CONNECTION_BROKEN; + return NULL; + } + + byte* payload = ((byte *) (hanBuffer)) + pos; + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Received data from Kamstrup meter:\n")); + debugPrint(payload, 0, min(ctx.length, (uint16_t) BUF_SIZE_HAN)); + } + + if(hanBuffer[11] == DATA_TAG_RES) { + if(obisPosition == 1) { // Meter model string + debugger->printf_P(PSTR("RECEIVED Meter model\n")); + } else { // All other uint32 + uint32_t value = ntohl(*((uint32_t*) (hanBuffer + 16))); + debugger->printf_P(PSTR("RECEIVED DATA FOR position %d, value: %lu\n"), obisPosition, value); + meterState.apply(currentObis, value / 1.0); + } + len = 0; + dataAvailable = false; + return NULL; + } else { + return PassiveMeterCommunicator::getData(meterState); + } +} + +void KamstrupPullCommunicator::sendConnectMessage() { + uint8_t i = 3; // Leave 3 bytes for header + hanBuffer[i++] = serverSap; // Destination address + hanBuffer[i++] = clientSap; // Source address + hanBuffer[i++] = 0x93; // Control + i += 2; // Leave 2 bytes for header checksum + hanBuffer[i++] = 0x81; // Format identifier + hanBuffer[i++] = 0x80; // Format group + uint8_t glPos = i++; // Position where we should write group length + uint8_t glLen = 0; // Actual group length + + ConnectParameter2b txMax = { 0x5, 0x2, htons(0x200) }; + memcpy(hanBuffer+i, &txMax, txMax.length+2); + i += txMax.length+2; + glLen += txMax.length+2; + + ConnectParameter2b rxMax = { 0x6, 0x2, htons(0x200) }; + memcpy(hanBuffer+i, &rxMax, rxMax.length+2); + i += rxMax.length+2; + glLen += rxMax.length+2; + + ConnectParameter4b txWin = { 0x7, 0x4, htonl(0x1) }; + memcpy(hanBuffer+i, &txWin, txWin.length+2); + i += txWin.length+2; + glLen += txWin.length+2; + + ConnectParameter4b rxWin = { 0x8, 0x4, htonl(0x1) }; + memcpy(hanBuffer+i, &rxWin, rxWin.length+2); + i += rxWin.length+2; + glLen += rxWin.length+2; + + hanBuffer[glPos] = glLen; + + HDLCHeader head = { HDLC_FLAG, htons(0xA000 | (i+1)) }; + memcpy(hanBuffer, &head, 3); + + HDLC3CtrlHcs ch = { 0x93, htons(crc16_x25(hanBuffer+1, 5)) }; + memcpy(hanBuffer+5, &ch, 3); + + HDLCFooter foot = { htons(crc16_x25(hanBuffer+1, i-1)), HDLC_FLAG }; + memcpy(hanBuffer+i, &foot, 3); + i += 3; + + for(int x = i; xwrite(hanBuffer, i); + hanSerial->flush(); + + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Sending data to Kamstrup meter:\n")); + debugPrint(hanBuffer, 0, i); + } + state = STATE_CONNECTING; + len = 0; + dataAvailable = false; +} + +bool KamstrupPullCommunicator::checkForConnectConfirmed() { + if(!dataAvailable) return false; + if(ctx.length > BUF_SIZE_HAN) { + debugger->printf_P(PSTR("Invalid context length\n")); + dataAvailable = false; + return NULL; + } + + byte* payload = ((byte *) (hanBuffer)) + pos; + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Received data from Kamstrup meter:\n")); + debugPrint(payload, 0, min(ctx.length, (uint16_t) BUF_SIZE_HAN)); + } + + len = 0; + dataAvailable = false; + lastMessageTime = 0; + + // 7E A0 20 21 03 73 73 98 81 80 14 05 02 02 00 06 02 02 00 07 04 00 00 00 01 08 04 00 00 00 01 6F EF 7E + // 7E A0 20 21 03 73 73 98 81 80 14 05 02 02 00 06 02 00 80 07 04 00 00 00 01 08 04 00 00 00 01 19 D4 7E + if(payload[0] == 0x81 && payload[1] == 0x80) { + state = STATE_CONNECTED_NOT_ASSOCIATED; + return true; + } else { + state = STATE_CONNECTION_BROKEN; + return false; + } +} + + +// TA: Tag +// LE: Legth +// RA: Response allowed +// PQ: Proposed QoS +// PV: Proposed DLMS version +// CO: Conformance +// AT: Application tag +// LC: Length of content field +// LU: Number of unused bits in the final octet +// MP: Max PDU size +// DK: Dedicated key, use (0x01), length (0xXX) and data +// AC: encoding of the tag of the xDLMS APDU CHOICE (InitiateRequest) +// FF: Fixed +// BE: Ber Object Identifier, 0x06=Object, 0x80=Context, 0x20=Constructed, 0x12=Calling auth, 0x40=Application, 0x04=String +// AN: Application context name tag +// NR: Name referencing, 1d=LN unciphered, 2d=unciphered, 3d=LN ciphered, 4d=cihered +// CA: Calling-AP-title +// CU: Calling Authentication +// SR: Sender requirements + + +// No authentication + +// 7E A0 2B 03 21 10 FB AF +// E6 E6 00 + +// TA LE AN LE BO LE FF FF FF FF FF FF NR +// 60 1D A1 09 06 07 60 85 74 05 08 01 01 + +// CA LE OS LE AC DK RA PQ PV AT AT LC LU CO CO CO MP MP +// BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 00 18 1D FF FF + +// 5F AF 7E + + +// With authentication + +// 7E A0 41 21 25 10 52 3B +// E6 E6 00 + +// BE LE AN LE +// 60 33 A1 09 + +// 06=CALLING_AP_TITLE +// BE LE FF FF FF FF FF FF NR +// 06 07 60 85 74 05 08 01 01 + +// 8A=SENDER_ACSE_REQUIREMENTS (BE 0x80 + 0x0A) +// BE LE FF FF +// 8A 02 07 80 + +// 8B=MECHANISM_NAME (BE 0x80 + 0x0B) +// BE LE FF FF FF FF FF FF NR +// 8B 07 60 85 74 05 08 02 01 + +// AC=CALLING_AUTHENTICATION_VALUE (BE 0x80 + BE 0x20 + 0x0C) +// BE LE BE LE -- Password -- +// AC 07 80 05 31 32 33 34 35 + +// BE=USER_INFORMATION (BE 0x80 + BE 0x20 + 0x1E) +// CA LE BE LE AC DK RA PQ PV AT AT LC LU CO CO CO MP MP +// BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 00 FE 1F FF FF + +// 0C FF 7E + +void KamstrupPullCommunicator::sendAssociateMessage() { + bool usePsk = !passkey.isEmpty(); + + uint8_t i = 3; // Leave 3 bytes for header + hanBuffer[i++] = serverSap; // Destination address + hanBuffer[i++] = clientSap; // Source address + hanBuffer[i++] = 0x10; // Control + i += 2; // Leave 2 bytes for header checksum + hanBuffer[i++] = 0xE6; // LLC dst + hanBuffer[i++] = 0xE6; // LLC src + hanBuffer[i++] = 0x00; // LLC control + + hanBuffer[i++] = DATA_TAG_AARQ; + uint8_t aarqLenIdx = i++; // length placeholder + hanBuffer[i++] = 0xA1; + hanBuffer[i++] = 0x09; // Length + hanBuffer[i++] = 0x06; // CALLING_AP_TITLE + hanBuffer[i++] = 0x07; // Length + hanBuffer[i++] = 0x60; // Fixed data + hanBuffer[i++] = 0x85; // Fixed data + hanBuffer[i++] = 0x74; // Fixed data + hanBuffer[i++] = 0x05; // Fixed data + hanBuffer[i++] = 0x08; // Fixed data + hanBuffer[i++] = 0x01; // Fixed data + hanBuffer[i++] = 0x01; // Name referencing, 1d=LN unciphered, 2d=unciphered, 3d=LN ciphered, 4d=cihered + + if(usePsk) { + hanBuffer[i++] = 0x8A; // SENDER_ACSE_REQUIREMENTS (BE 0x80 + 0x0A) + hanBuffer[i++] = 0x02; // Length + hanBuffer[i++] = 0x07; // Data + hanBuffer[i++] = 0x80; // Data + + hanBuffer[i++] = 0x8B; // MECHANISM_NAME (BE 0x80 + 0x0B) + hanBuffer[i++] = 0x07; // Length + hanBuffer[i++] = 0x60; // Fixed data + hanBuffer[i++] = 0x85; // Fixed data + hanBuffer[i++] = 0x74; // Fixed data + hanBuffer[i++] = 0x05; // Fixed data + hanBuffer[i++] = 0x08; // Fixed data + hanBuffer[i++] = 0x02; // Fixed data + hanBuffer[i++] = 0x01; // Name referencing, 1d=LN unciphered, 2d=unciphered, 3d=LN ciphered, 4d=cihered + + hanBuffer[i++] = 0xAC; // CALLING_AUTHENTICATION_VALUE (BE 0x80 + BE 0x20 + 0x0C) + hanBuffer[i++] = passkey.length() + 2; // Length + hanBuffer[i++] = 0x80; // Ber Context + hanBuffer[i++] = passkey.length(); // Length + + const char* key = passkey.c_str(); + for(uint8_t x = 0; x < passkey.length(); x++) { + hanBuffer[i++] = key[x]; + } + } + + hanBuffer[i++] = 0xBE; // USER_INFORMATION (BE 0x80 + BE 0x20 + 0x1E) + hanBuffer[i++] = 0x10; // Length + hanBuffer[i++] = 0x04; // CALLED_AP_INVOCATION_ID + hanBuffer[i++] = 0x0E; // Length + hanBuffer[i++] = 0x01; // encoding of the tag of the xDLMS APDU CHOICE (InitiateRequest) + hanBuffer[i++] = 0x00; // Dedicated key, use (0x01), length (0xXX) and data + hanBuffer[i++] = 0x00; // Response allowed + hanBuffer[i++] = 0x00; // Proposed QoS + hanBuffer[i++] = 0x06; // Proposed DLMS version + hanBuffer[i++] = 0x5F; // + hanBuffer[i++] = 0x1F; // + hanBuffer[i++] = 0x04; // Length + hanBuffer[i++] = 0x00; // Number of unused bits + hanBuffer[i++] = 0x00; // Conformance + if(usePsk) { + hanBuffer[i++] = 0xFE; // Conformance + hanBuffer[i++] = 0x1F; // Conformance + } else { + hanBuffer[i++] = 0x18; // Conformance + hanBuffer[i++] = 0x1D; // Conformance + } + hanBuffer[i++] = 0xFF; // Max PDU size + hanBuffer[i++] = 0xFF; // Max PDU size + hanBuffer[aarqLenIdx] = i-aarqLenIdx-1; + + HDLCHeader head = { HDLC_FLAG, htons(0xA000 | (i+1)) }; + memcpy(hanBuffer, &head, 3); + + HDLC3CtrlHcs ch = { 0x10, htons(crc16_x25(hanBuffer+1, 5)) }; + memcpy(hanBuffer+5, &ch, 3); + + HDLCFooter foot = { htons(crc16_x25(hanBuffer+1, i-1)), HDLC_FLAG }; + memcpy(hanBuffer+i, &foot, 3); + i += 3; + + for(int x = i; xwrite(hanBuffer, i); + hanSerial->flush(); + + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Sending data to Kamstrup meter:\n")); + debugPrint(hanBuffer, 0, i); + } + state = STATE_CONNECTED_ASSOCIATING; + len = 0; + dataAvailable = false; +} + +bool KamstrupPullCommunicator::checkForAssociationConfirmed() { + if(!dataAvailable) return false; + if(ctx.length > BUF_SIZE_HAN) { + debugger->printf_P(PSTR("Invalid context length\n")); + dataAvailable = false; + return NULL; + } + + byte* payload = ((byte *) (hanBuffer)) + pos; + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Received data from Kamstrup meter:\n")); + debugPrint(payload, 0, ctx.length); + } + len = 0; + dataAvailable = false; + lastMessageTime = 0; + + if(payload[0] == DATA_TAG_AARE) { + state = STATE_CONNECTED_ASSOCIATED; + return true; + } else { + state = STATE_CONNECTION_BROKEN; + return false; + } + + return false; +} + +// 7E A0 19 03 21 32 6F D8 E6 E6 00 C0 01 81 00 01 01 01 00 00 01 FF 02 00 A8 E3 7E +// 7E A0 19 21 25 32 8C 09 E6 E6 00 C0 01 81 00 01 01 01 60 01 01 FF 02 00 5D 6F 7E +// 7E A0 19 21 25 32 8C 09 E6 E6 00 C0 01 C1 00 03 01 01 20 07 00 FF 02 00 38 36 7E + +// 7E A0 4C 21 25 32 CD B2 E6 E6 00 C0 01 81 00 +// 07 - Class +// 01 01 63 01 00 FF - OBIS +// 02 - Attribute number 2 +// 01 01 - Array 1 +// 02 04 - Struct 4 +// 02 04 - Struct 4 +// 12 00 08 - uint16 +// 09 06 00 01 01 00 00 FF - OBIS +// 0F 02 - int8 +// 12 00 00 - uint16 +// 09 0C 07 DD 0A 19 FF 00 00 00 00 80 00 80 - from date +// 09 0C 07 DD 0A 1A FF 00 00 00 00 80 00 80 - to date +// 01 00 - Empty array +// 2F 84 7E +bool KamstrupPullCommunicator::requestData() { + bool usePsk = !passkey.isEmpty(); + + uint8_t i = 3; // Leave 3 bytes for header + hanBuffer[i++] = serverSap; // Destination address + hanBuffer[i++] = clientSap; // Source address + hanBuffer[i++] = 0x32; // Control + i += 2; // Leave 2 bytes for header checksum + hanBuffer[i++] = 0xE6; // LLC dst + hanBuffer[i++] = 0xE6; // LLC src + hanBuffer[i++] = 0x00; // LLC control + + hanBuffer[i++] = 0xC0; // Get Request + hanBuffer[i++] = 0x01; // Type, 01 = Normal + hanBuffer[i++] = 0x81; // Invoke ID and priority + hanBuffer[i++] = 0x00; + hanBuffer[i++] = ++obisPosition < 3 ? 0x01 : 0x03; // Class ID + + OBIS_t obis = {1,1,OBIS_NULL,OBIS_RANGE_NA}; + switch(obisPosition) { + case 1: obis.code = OBIS_METER_MODEL; break; + case 2: obis.code = OBIS_METER_ID; break; + + case 3: obis.code = OBIS_ACTIVE_IMPORT; break; + case 4: obis.code = OBIS_REACTIVE_IMPORT; break; + case 5: obis.code = OBIS_ACTIVE_EXPORT; break; + case 6: obis.code = OBIS_REACTIVE_EXPORT; break; + default: + obisPosition = 0; return false; + } + memcpy(hanBuffer+i, &obis, sizeof(obis)); + i += sizeof(obis); + currentObis = obis.code; + + hanBuffer[i++] = 0x02; // Attribute number + hanBuffer[i++] = 0x00; + + HDLCHeader head = { HDLC_FLAG, htons(0xA000 | (i+1)) }; + memcpy(hanBuffer, &head, 3); + + HDLC3CtrlHcs ch = { 0x32, htons(crc16_x25(hanBuffer+1, 5)) }; + memcpy(hanBuffer+5, &ch, 3); + + HDLCFooter foot = { htons(crc16_x25(hanBuffer+1, i-1)), HDLC_FLAG }; + memcpy(hanBuffer+i, &foot, 3); + i += 3; + + for(int x = i; xwrite(hanBuffer, i); + hanSerial->flush(); + + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Sending data to Kamstrup meter:\n")); + debugPrint(hanBuffer, 0, i); + } + + len = 0; + dataAvailable = false; + + return true; +} + +//7E A0 07 03 21 53 03 C7 7E +void KamstrupPullCommunicator::sendDisconnectMessage() { + uint8_t i = 3; // Leave 3 bytes for header + hanBuffer[i++] = serverSap; // Destination address + hanBuffer[i++] = clientSap; // Source address + hanBuffer[i++] = 0x53; // Control + + HDLCHeader head = { HDLC_FLAG, htons(0xA000 | (i+1)) }; + memcpy(hanBuffer, &head, 3); + + HDLCFooter foot = { htons(crc16_x25(hanBuffer+1, i-1)), HDLC_FLAG }; + memcpy(hanBuffer+i, &foot, 3); + i += 3; + + for(int x = i; xwrite(hanBuffer, i); + hanSerial->flush(); + + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Sending data to Kamstrup meter:\n")); + debugPrint(hanBuffer, 0, i); + } + state = STATE_DISCONNECTING; + len = 0; + dataAvailable = false; +} + +// 7E A0 07 21 03 73 01 40 7E +bool KamstrupPullCommunicator::checkForDisconnectMessage() { + if(!dataAvailable) return false; + if(ctx.length > BUF_SIZE_HAN) { + debugger->printf_P(PSTR("Invalid context length\n")); + dataAvailable = false; + return NULL; + } + + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("Received data from Kamstrup meter:\n")); + debugPrint(hanBuffer, 0, ctx.length); + } + for(int i = 0; ihasRxError()) { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial RX error\n")); + lastError = 96; + } + if(hwSerial->hasOverrun()) { + rxerr(2); + } + #endif + } else if(swSerial != NULL) { + if(swSerial->overflow()) { + rxerr(2); + } + } + return lastError; +} + +bool KamstrupPullCommunicator::isConfigChanged() { + return configChanged; +} + +void KamstrupPullCommunicator::getCurrentConfig(MeterConfig& meterConfig) { + meterConfig = this->meterConfig; +} + +void KamstrupPullCommunicator::rxerr(int err) { + if(err == 0) return; + switch(err) { + case 2: + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial buffer overflow\n")); + rxBufferErrors++; + if(rxBufferErrors > 3 && meterConfig.bufferSize < 64) { + meterConfig.bufferSize += 2; + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Increasing RX buffer to %d bytes\n"), meterConfig.bufferSize * 64); + configChanged = true; + rxBufferErrors = 0; + } + break; + case 3: + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial FIFO overflow\n")); + break; + case 4: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Serial frame error\n")); + break; + case 5: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Serial parity error\n")); + break; + } + // Do not include serial break + if(err > 1) lastError = 90+err; +} + +void KamstrupPullCommunicator::debugPrint(byte *buffer, int start, int length) { + for (int i = start; i < start + length; i++) { + if (buffer[i] < 0x10) + debugger->print(F("0")); + debugger->print(buffer[i], HEX); + debugger->print(F(" ")); + if ((i - start + 1) % 16 == 0) + debugger->println(F("")); + else if ((i - start + 1) % 4 == 0) + debugger->print(F(" ")); + + yield(); // Let other get some resources too + } + debugger->println(F("")); +} diff --git a/src/KamstrupPullCommunicator.h b/src/KamstrupPullCommunicator.h new file mode 100644 index 00000000..eab3288a --- /dev/null +++ b/src/KamstrupPullCommunicator.h @@ -0,0 +1,80 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _KAMSTRUPPULLCOMMUNICATOR_H +#define _KAMSTRUPPULLCOMMUNICATOR_H + +#include "PassiveMeterCommunicator.h" +#include "RemoteDebug.h" +#include "AmsConfiguration.h" +#include "DataParsers.h" +#include "SoftwareSerial.h" +#include "Timezone.h" +#include "PassthroughMqttHandler.h" +#include "HdlcParser.h" +#include "crc.h" +#include "OBIScodes.h" + +#define BUF_SIZE_HAN (1280) + +#define STATE_DISCONNECTED 0 +#define STATE_CONNECTING 1 +#define STATE_CONNECTED_NOT_ASSOCIATED 2 +#define STATE_CONNECTED_ASSOCIATING 3 +#define STATE_CONNECTED_ASSOCIATED 4 +#define STATE_CONNECTION_BROKEN 7 +#define STATE_DISCONNECT 8 +#define STATE_DISCONNECTING 9 + +struct ConnectParameter2b { + uint8_t type; + uint8_t length; + uint16_t data; +} __attribute__((packed)); + +struct ConnectParameter4b { + uint8_t type; + uint8_t length; + uint32_t data; +} __attribute__((packed)); + +class KamstrupPullCommunicator : public PassiveMeterCommunicator { +public: + KamstrupPullCommunicator(RemoteDebug* debugger) : PassiveMeterCommunicator(debugger) {}; + void configure(MeterConfig&, Timezone*); + bool loop(); + AmsData* getData(AmsData& meterState); + int getLastError(); + bool isConfigChanged(); + void getCurrentConfig(MeterConfig& meterConfig); + void setPassthroughMqttHandler(PassthroughMqttHandler*); + + HardwareSerial* getHwSerial(); + void rxerr(int err); + +private: + uint8_t state = STATE_DISCONNECTED; + uint64_t lastLoop = 0; + uint64_t lastMessageTime = 0; + String passkey = "12345"; + uint8_t clientSap = 0x25; + uint8_t serverSap = 0x21; + uint8_t obisPosition = 2; + OBIS_code_t currentObis = OBIS_NULL; + + void setupHanPort(uint32_t baud, uint8_t parityOrdinal, bool invert); + void sendConnectMessage(); + bool checkForConnectConfirmed(); + void sendAssociateMessage(); + bool checkForAssociationConfirmed(); + bool requestData(); + void sendDisconnectMessage(); + bool checkForDisconnectMessage(); + + void debugPrint(byte *buffer, int start, int length); +}; + +#endif diff --git a/src/LNG.cpp b/src/LNG.cpp index faa153ea..92a7216e 100644 --- a/src/LNG.cpp +++ b/src/LNG.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "LNG.h" #include "lwip/def.h" #include "ntohll.h" diff --git a/src/LNG.h b/src/LNG.h index 0b994a18..07806f6d 100644 --- a/src/LNG.h +++ b/src/LNG.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _LNG_H #define _LNG_H diff --git a/src/LNG2.cpp b/src/LNG2.cpp index 7640954c..b4ae6159 100644 --- a/src/LNG2.cpp +++ b/src/LNG2.cpp @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #include "LNG2.h" #include "Uptime.h" diff --git a/src/LNG2.h b/src/LNG2.h index 6f8aa174..23158a40 100644 --- a/src/LNG2.h +++ b/src/LNG2.h @@ -1,3 +1,9 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + #ifndef _LNG2_H #define _LNG2_H diff --git a/src/MeterCommunicator.h b/src/MeterCommunicator.h new file mode 100644 index 00000000..73c39197 --- /dev/null +++ b/src/MeterCommunicator.h @@ -0,0 +1,26 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _METERCOMMUNICATOR_H +#define _METERCOMMUNICATOR_H + +#include +#include "RemoteDebug.h" +#include "AmsData.h" +#include "AmsConfiguration.h" + +class MeterCommunicator { +public: + virtual ~MeterCommunicator() {}; + virtual void configure(MeterConfig&, Timezone*); + virtual bool loop(); + virtual AmsData* getData(AmsData& meterState); + virtual int getLastError(); + virtual bool isConfigChanged(); + virtual void getCurrentConfig(MeterConfig& meterConfig); +}; + +#endif diff --git a/src/PassiveMeterCommunicator.cpp b/src/PassiveMeterCommunicator.cpp new file mode 100644 index 00000000..92f2f916 --- /dev/null +++ b/src/PassiveMeterCommunicator.cpp @@ -0,0 +1,682 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "PassiveMeterCommunicator.h" +#include "IEC6205675.h" +#include "IEC6205621.h" +#include "LNG.h" +#include "LNG2.h" + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) +#include +#endif + +PassiveMeterCommunicator::PassiveMeterCommunicator(RemoteDebug* debugger) { + this->debugger = debugger; + bauds[0] = 2400; + parities[0] = 11; + inverts[0] = false; + + bauds[1] = 2400; + parities[1] = 3; + inverts[1] = false; + + bauds[2] = 115200; + parities[2] = 3; + inverts[2] = false; + + bauds[3] = 2400; + parities[3] = 11; + inverts[3] = true; + + bauds[4] = 2400; + parities[4] = 3; + inverts[4] = true; + + bauds[5] = 115200; + parities[5] = 3; + inverts[5] = true; +} + +void PassiveMeterCommunicator::configure(MeterConfig& meterConfig, Timezone* tz) { + this->meterConfig = meterConfig; + this->configChanged = false; + this->tz = tz; + setupHanPort(meterConfig.baud, meterConfig.parity, meterConfig.invert); + if(gcmParser != NULL) { + delete gcmParser; + gcmParser = NULL; + } +} + +bool PassiveMeterCommunicator::loop() { + unsigned long start, end; + if(!hanSerial->available()) { + return false; + } + + // Before reading, empty serial buffer to increase chance of getting first byte of a data transfer + if(!serialInit) { + hanSerial->readBytes(hanBuffer, BUF_SIZE_HAN); + serialInit = true; + return false; + } + + unsigned long now = millis(); + if(autodetect) handleAutodetect(now); + + dataAvailable = false; + ctx = {0,0,0,0}; + strcpy_P((char*) ctx.system_title, PSTR("")); + pos = DATA_PARSE_INCOMPLETE; + // For each byte received, check if we have a complete frame we can handle + start = millis(); + while(hanSerial->available() && pos == DATA_PARSE_INCOMPLETE) { + // If buffer was overflowed, reset + if(len >= BUF_SIZE_HAN) { + hanSerial->readBytes(hanBuffer, BUF_SIZE_HAN); + len = 0; + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Buffer overflow, resetting\n")); + return false; + } + hanBuffer[len++] = hanSerial->read(); + ctx.length = len; + pos = unwrapData((uint8_t *) hanBuffer, ctx); + if(ctx.type > 0 && pos >= 0) { + switch(ctx.type) { + case DATA_TAG_DLMS: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid DLMS at %d\n"), pos); + break; + case DATA_TAG_DSMR: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid DSMR at %d\n"), pos); + break; + case DATA_TAG_SNRM: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid SNMR at %d\n"), pos); + break; + case DATA_TAG_AARE: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid AARE at %d\n"), pos); + break; + case DATA_TAG_RES: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid Get Response at %d\n"), pos); + break; + case DATA_TAG_HDLC: + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received valid HDLC at %d\n"), pos); + break; + default: + // TODO: Move this so that payload is sent to MQTT + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Unknown tag %02X at pos %d\n"), ctx.type, pos); + len = 0; + return false; + } + } + yield(); + } + end = millis(); + if(end-start > 1000) { + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Used %dms to unwrap HAN data\n"), end-start); + } + + if(pos == DATA_PARSE_INCOMPLETE) { + return false; + } else if(pos == DATA_PARSE_UNKNOWN_DATA) { + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Unknown data received\n")); + lastError = pos; + len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); + if(debugger->isActive(RemoteDebug::VERBOSE)) { + debugger->printf_P(PSTR(" payload:\n")); + debugPrint(hanBuffer, 0, len); + } + len = 0; + return false; + } + if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) { + len = 0; + return false; + } else if(pos < 0) { + lastError = pos; + printHanReadError(pos); + len += hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); + if(pt != NULL) { + pt->publishBytes(hanBuffer+pos, len); + } + while(hanSerial->available()) hanSerial->read(); // Make sure it is all empty, in case we overflowed buffer above + len = 0; + return false; + } + + if(ctx.type == 0) { + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Ended up with context type %d, return code %d and length: %lu/%lu\n"), ctx.type, pos, ctx.length, len); + lastError = pos; + len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); + if(debugger->isActive(RemoteDebug::VERBOSE)) { + debugger->printf_P(PSTR(" payload:\n")); + debugPrint(hanBuffer, 0, len); + } + len = 0; + return false; + } + + // Data is valid, clear the rest of the buffer to avoid tainted parsing + for(int i = pos+ctx.length; i 3600000) { + if(maxDetectedPayloadSize * 1.5 > meterConfig.bufferSize * 64) { + int bufferSize = min((double) 64, ceil((maxDetectedPayloadSize * 1.5) / 64)); + #if defined(ESP8266) + if(meterConfig.rxPin != 3 && meterConfig.rxPin != 113) { + bufferSize = min(bufferSize, 2); + } else { + bufferSize = min(bufferSize, 8); + } + #endif + if(bufferSize != meterConfig.bufferSize) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Increasing RX buffer to %d bytes\n"), meterConfig.bufferSize * 64); + meterConfig.bufferSize = bufferSize; + configChanged = true; + } + } + maxDetectPayloadDetectDone = true; + } + + return true; +} + +AmsData* PassiveMeterCommunicator::getData(AmsData& meterState) { + if(!dataAvailable) return NULL; + if(ctx.length > BUF_SIZE_HAN) { + debugger->printf_P(PSTR("Invalid context length\n")); + dataAvailable = false; + return NULL; + } + + AmsData* data = NULL; + char* payload = ((char *) (hanBuffer)) + pos; + if(maxDetectedPayloadSize < pos) maxDetectedPayloadSize = pos; + if(ctx.type == DATA_TAG_DLMS) { + if(pt != NULL) { + pt->publishBytes((uint8_t*) payload, ctx.length); + } + + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("Using application data:\n")); + if(debugger->isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length); + + // Rudimentary detector for L&G proprietary format, this is terrible code... Fix later + if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) { + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("LNG\n")); + LNG lngData = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, debugger); + if(lngData.getListType() >= 3) { + data = new AmsData(); + data->apply(meterState); + data->apply(lngData); + } + } else if(payload[0] == CosemTypeStructure && + payload[2] == CosemTypeLongUnsigned && + payload[5] == CosemTypeLongUnsigned && + payload[8] == CosemTypeLongUnsigned && + payload[11] == CosemTypeLongUnsigned && + payload[14] == CosemTypeLongUnsigned && + payload[17] == CosemTypeLongUnsigned + ) { + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("LNG2\n")); + LNG2 lngData = LNG2(payload, meterState.getMeterType(), &meterConfig, ctx, debugger); + if(lngData.getListType() >= 3) { + data = new AmsData(); + data->apply(meterState); + data->apply(lngData); + } + } else { + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("DLMS\n")); + // TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats + data = new IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx, meterState); + } + } else if(ctx.type == DATA_TAG_DSMR) { + data = new IEC6205621(payload, tz); + } + len = 0; + if(data != NULL) { + if(data->getListType() > 0) { + validDataReceived = true; + if(rxBufferErrors > 0) rxBufferErrors--; + } + } + dataAvailable = false; + return data; +} + +int PassiveMeterCommunicator::getLastError() { + if(hwSerial != NULL) { + #if defined ESP8266 + if(hwSerial->hasRxError()) { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial RX error\n")); + lastError = 96; + } + if(hwSerial->hasOverrun()) { + rxerr(2); + } + #endif + } else if(swSerial != NULL) { + if(swSerial->overflow()) { + rxerr(2); + } + } + return lastError; +} + +bool PassiveMeterCommunicator::isConfigChanged() { + return configChanged; +} + +void PassiveMeterCommunicator::getCurrentConfig(MeterConfig& meterConfig) { + meterConfig = this->meterConfig; +} + + +int16_t PassiveMeterCommunicator::unwrapData(uint8_t *buf, DataParserContext &context) { + int16_t ret = 0; + bool doRet = false; + uint16_t end = BUF_SIZE_HAN; + uint8_t tag = (*buf); + uint8_t lastTag = DATA_TAG_NONE; + while(tag != DATA_TAG_NONE) { + int16_t curLen = context.length; + int8_t res = 0; + switch(tag) { + case DATA_TAG_HDLC: + if(hdlcParser == NULL) hdlcParser = new HDLCParser(); + res = hdlcParser->parse(buf, context); + if(context.length < 3) doRet = true; + break; + case DATA_TAG_MBUS: + if(mbusParser == NULL) mbusParser = new MBUSParser(); + res = mbusParser->parse(buf, context); + break; + case DATA_TAG_GBT: + if(gbtParser == NULL) gbtParser = new GBTParser(); + res = gbtParser->parse(buf, context); + break; + case DATA_TAG_GCM: + if(gcmParser == NULL) gcmParser = new GCMParser(meterConfig.encryptionKey, meterConfig.authenticationKey); + res = gcmParser->parse(buf, context); + break; + case DATA_TAG_LLC: + if(llcParser == NULL) llcParser = new LLCParser(); + res = llcParser->parse(buf, context); + break; + case DATA_TAG_DLMS: + if(dlmsParser == NULL) dlmsParser = new DLMSParser(); + res = dlmsParser->parse(buf, context); + if(res >= 0) doRet = true; + break; + case DATA_TAG_DSMR: + if(dsmrParser == NULL) dsmrParser = new DSMRParser(); + res = dsmrParser->parse(buf, context, lastTag != DATA_TAG_NONE); + if(res >= 0) doRet = true; + break; + case DATA_TAG_SNRM: + case DATA_TAG_AARE: + case DATA_TAG_RES: + res = DATA_PARSE_OK; + doRet = true; + break; + default: + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Ended up in default case while unwrapping...(tag %02X)\n"), tag); + return DATA_PARSE_UNKNOWN_DATA; + } + lastTag = tag; + if(res == DATA_PARSE_INCOMPLETE) { + return res; + } + if(context.length > end) { + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("Context length %lu > %lu:\n"), context.length, end); + context.type = 0; + context.length = 0; + return false; + } + switch(tag) { + case DATA_TAG_HDLC: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("HDLC frame:\n")); + if(pt != NULL) { + pt->publishBytes(buf, curLen); + } + break; + case DATA_TAG_MBUS: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("MBUS frame:\n")); + if(pt != NULL) { + pt->publishBytes(buf, curLen); + } + break; + case DATA_TAG_GBT: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("GBT frame:\n")); + break; + case DATA_TAG_GCM: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("GCM frame:\n")); + break; + case DATA_TAG_LLC: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("LLC frame:\n")); + break; + case DATA_TAG_DLMS: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("DLMS frame:\n")); + break; + case DATA_TAG_DSMR: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("DSMR frame:\n")); + if(pt != NULL) { + pt->publishString((char*) buf); + } + break; + case DATA_TAG_SNRM: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("SNMR frame:\n")); + break; + case DATA_TAG_AARE: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("AARE frame:\n")); + break; + case DATA_TAG_RES: + if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("RES frame:\n")); + break; + } + if(debugger->isActive(RemoteDebug::VERBOSE)) debugPrint(buf, 0, curLen); + if(res == DATA_PARSE_FINAL_SEGMENT) { + if(tag == DATA_TAG_MBUS) { + res = mbusParser->write(buf, context); + } + } + + if(res < 0) { + return res; + } + buf += res; + end -= res; + ret += res; + + // If we are ready to return, do that + if(doRet) { + context.type = tag; + return ret; + } + + // Use start byte of new buffer position as tag for next round in loop + tag = (*buf); + } + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Got to end of unwrap method...\n")); + return DATA_PARSE_UNKNOWN_DATA; +} + +void PassiveMeterCommunicator::debugPrint(byte *buffer, int start, int length) { + for (int i = start; i < start + length; i++) { + if (buffer[i] < 0x10) + debugger->print(F("0")); + debugger->print(buffer[i], HEX); + debugger->print(F(" ")); + if ((i - start + 1) % 16 == 0) + debugger->println(F("")); + else if ((i - start + 1) % 4 == 0) + debugger->print(F(" ")); + + yield(); // Let other get some resources too + } + debugger->println(F("")); +} + +void PassiveMeterCommunicator::printHanReadError(int pos) { + if(debugger->isActive(RemoteDebug::WARNING)) { + switch(pos) { + case DATA_PARSE_BOUNDRY_FLAG_MISSING: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Boundry flag missing\n")); + break; + case DATA_PARSE_HEADER_CHECKSUM_ERROR: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Header checksum error\n")); + break; + case DATA_PARSE_FOOTER_CHECKSUM_ERROR: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Frame checksum error\n")); + break; + case DATA_PARSE_INCOMPLETE: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Received frame is incomplete\n")); + break; + case GCM_AUTH_FAILED: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Decrypt authentication failed\n")); + break; + case GCM_ENCRYPTION_KEY_FAILED: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Setting decryption key failed\n")); + break; + case GCM_DECRYPT_FAILED: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Decryption failed\n")); + break; + case MBUS_FRAME_LENGTH_NOT_EQUAL: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Frame length mismatch\n")); + break; + case DATA_PARSE_INTERMEDIATE_SEGMENT: + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Intermediate segment received\n")); + break; + case DATA_PARSE_UNKNOWN_DATA: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Unknown data format %02X\n"), hanBuffer[0]); + break; + default: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Unspecified error while reading data: %d\n"), pos); + } + } +} + +void PassiveMeterCommunicator::setupHanPort(uint32_t baud, uint8_t parityOrdinal, bool invert) { + uint8_t pin = meterConfig.rxPin; + + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n"), pin, baud, parityOrdinal); + + if(baud == 0) { + baud = bauds[meterAutoIndex]; + parityOrdinal = parities[meterAutoIndex]; + invert = inverts[meterAutoIndex]; + } + if(parityOrdinal == 0) { + parityOrdinal = 3; // 8N1 + } + + if(pin == 3 || pin == 113) { + #if ARDUINO_USB_CDC_ON_BOOT + hwSerial = &Serial0; + #else + hwSerial = &Serial; + #endif + } + + #if defined(ESP32) + if(pin == 9) { + hwSerial = &Serial1; + } + #if defined(CONFIG_IDF_TARGET_ESP32) + if(pin == 16) { + hwSerial = &Serial2; + } + #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + hwSerial = &Serial1; + #endif + #endif + + if(pin == 0) { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Invalid GPIO configured for HAN\n")); + return; + } + + if(meterConfig.bufferSize < 1) meterConfig.bufferSize = 1; + + if(hwSerial != NULL) { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Hardware serial\n")); + Serial.flush(); + #if defined(ESP8266) + SerialConfig serialConfig; + #elif defined(ESP32) + uint32_t serialConfig; + #endif + switch(parityOrdinal) { + case 2: + serialConfig = SERIAL_7N1; + break; + case 3: + serialConfig = SERIAL_8N1; + break; + case 10: + serialConfig = SERIAL_7E1; + break; + default: + serialConfig = SERIAL_8E1; + break; + } + if(meterConfig.bufferSize < 4) meterConfig.bufferSize = 4; // 64 bytes (1) is default for software serial, 256 bytes (4) for hardware + + hwSerial->setRxBufferSize(64 * meterConfig.bufferSize); + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + hwSerial->begin(baud, serialConfig, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, invert); + uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + #elif defined(ESP32) + hwSerial->begin(baud, serialConfig, -1, -1, invert); + #else + hwSerial->begin(baud, serialConfig, SERIAL_FULL, 1, invert); + #endif + + #if defined(ESP8266) + if(pin == 3) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Switching UART0 to pin 1 & 3\n")); + Serial.pins(1,3); + } else if(pin == 113) { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Switching UART0 to pin 15 & 13\n")); + Serial.pins(15,13); + } + #endif + + // Prevent pullup on TX pin if not uart0 + #if defined(CONFIG_IDF_TARGET_ESP32S2) + pinMode(17, INPUT); + #elif defined(CONFIG_IDF_TARGET_ESP32C3) + pinMode(7, INPUT); + #elif defined(ESP32) + if(pin == 9) { + pinMode(10, INPUT); + } else if(pin == 16) { + pinMode(17, INPUT); + } + #elif defined(ESP8266) + if(pin == 113) { + pinMode(15, INPUT); + } + #endif + + hanSerial = hwSerial; + if(swSerial != NULL) { + swSerial->end(); + delete swSerial; + swSerial = NULL; + } + } else { + if (debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Software serial\n")); + Serial.flush(); + + if(swSerial == NULL) { + swSerial = new SoftwareSerial(pin, -1, invert); + } else { + swSerial->end(); + } + + SoftwareSerialConfig serialConfig; + switch(parityOrdinal) { + case 2: + serialConfig = SWSERIAL_7N1; + break; + case 3: + serialConfig = SWSERIAL_8N1; + break; + case 10: + serialConfig = SWSERIAL_7E1; + break; + default: + serialConfig = SWSERIAL_8E1; + break; + } + + swSerial->begin(baud, serialConfig, pin, -1, invert, meterConfig.bufferSize * 64); + hanSerial = swSerial; + + Serial.end(); + Serial.begin(115200); + hwSerial = NULL; + } + + // The library automatically sets the pullup in Serial.begin() + if(!meterConfig.rxPinPullup) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("HAN pin pullup disabled\n")); + pinMode(meterConfig.rxPin, INPUT); + } + + hanSerial->setTimeout(250); + + // Empty buffer before starting + while (hanSerial->available() > 0) { + hanSerial->read(); + } + #if defined(ESP8266) + if(hwSerial != NULL) { + hwSerial->hasOverrun(); + } else if(swSerial != NULL) { + swSerial->overflow(); + } + #endif +} + +HardwareSerial* PassiveMeterCommunicator::getHwSerial() { + return hwSerial; +} + +void PassiveMeterCommunicator::rxerr(int err) { + if(err == 0) return; + switch(err) { + case 2: + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial buffer overflow\n")); + rxBufferErrors++; + if(rxBufferErrors > 3 && meterConfig.bufferSize < 64) { + meterConfig.bufferSize += 2; + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Increasing RX buffer to %d bytes\n"), meterConfig.bufferSize * 64); + configChanged = true; + rxBufferErrors = 0; + } + break; + case 3: + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Serial FIFO overflow\n")); + break; + case 4: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Serial frame error\n")); + break; + case 5: + if (debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("Serial parity error\n")); + break; + } + // Do not include serial break + if(err > 1) lastError = 90+err; +} + +void PassiveMeterCommunicator::handleAutodetect(unsigned long now) { + if(!autodetect) return; + + if(!validDataReceived) { + if(now - meterAutodetectLastChange > 20000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) { + autodetect = true; + meterAutoIndex++; // Default is to try the first one in setup() + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Meter serial autodetect, swapping to: %d, %d, %s\n"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); + if(meterAutoIndex >= 6) meterAutoIndex = 0; + setupHanPort(bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex]); + meterAutodetectLastChange = now; + } + } else if(autodetect) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Meter serial autodetected, saving: %d, %d, %s\n"), bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false"); + autodetect = false; + meterConfig.baud = bauds[meterAutoIndex]; + meterConfig.parity = parities[meterAutoIndex]; + meterConfig.invert = inverts[meterAutoIndex]; + configChanged = true; + setupHanPort(meterConfig.baud, meterConfig.parity, meterConfig.invert); + } +} diff --git a/src/PassiveMeterCommunicator.h b/src/PassiveMeterCommunicator.h new file mode 100644 index 00000000..53ebf31d --- /dev/null +++ b/src/PassiveMeterCommunicator.h @@ -0,0 +1,79 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _PASSIVEMETERCOMMUNICATOR_H +#define _PASSIVEMETERCOMMUNICATOR_H + +#include "MeterCommunicator.h" +#include "RemoteDebug.h" +#include "AmsConfiguration.h" +#include "DataParsers.h" +#include "SoftwareSerial.h" +#include "Timezone.h" +#include "PassthroughMqttHandler.h" + +#define BUF_SIZE_HAN (1280) + +class PassiveMeterCommunicator : public MeterCommunicator { +public: + PassiveMeterCommunicator(RemoteDebug* debugger); + void configure(MeterConfig&, Timezone*); + bool loop(); + AmsData* getData(AmsData& meterState); + int getLastError(); + bool isConfigChanged(); + void getCurrentConfig(MeterConfig& meterConfig); + void setPassthroughMqttHandler(PassthroughMqttHandler*); + + HardwareSerial* getHwSerial(); + void rxerr(int err); + +protected: + RemoteDebug* debugger = NULL; + MeterConfig meterConfig; + bool configChanged = false; + Timezone* tz; + + PassthroughMqttHandler* pt = NULL; + + uint8_t hanBuffer[BUF_SIZE_HAN]; + Stream *hanSerial; + SoftwareSerial *swSerial = NULL; + HardwareSerial *hwSerial = NULL; + uint8_t rxBufferErrors = 0; + + bool autodetect = false, validDataReceived = false; + unsigned long meterAutodetectLastChange = 0; + uint8_t meterAutoIndex = 0; + uint32_t bauds[6]; + uint8_t parities[6]; + bool inverts[6]; + + bool dataAvailable = false; + int len = 0; + int pos = DATA_PARSE_INCOMPLETE; + int lastError = DATA_PARSE_OK; + bool serialInit = false; + bool maxDetectPayloadDetectDone = false; + uint8_t maxDetectedPayloadSize = 64; + DataParserContext ctx = {0,0,0,0}; + + HDLCParser *hdlcParser = NULL; + MBUSParser *mbusParser = NULL; + GBTParser *gbtParser = NULL; + GCMParser *gcmParser = NULL; + LLCParser *llcParser = NULL; + DLMSParser *dlmsParser = NULL; + DSMRParser *dsmrParser = NULL; + + void setupHanPort(uint32_t baud, uint8_t parityOrdinal, bool invert); + int16_t unwrapData(uint8_t *buf, DataParserContext &context); + void debugPrint(byte *buffer, int start, int length); + void printHanReadError(int pos); + void handleAutodetect(unsigned long now); +}; + +#endif diff --git a/src/PassthroughMqttHandler.cpp b/src/PassthroughMqttHandler.cpp new file mode 100644 index 00000000..e4f23046 --- /dev/null +++ b/src/PassthroughMqttHandler.cpp @@ -0,0 +1,42 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "PassthroughMqttHandler.h" +#include "hexutils.h" + +bool PassthroughMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { + return false; +} + +bool PassthroughMqttHandler::publishTemperatures(AmsConfiguration*, HwTools*) { + return false; +} + +bool PassthroughMqttHandler::publishPrices(EntsoeApi*) { + return false; +} + +bool PassthroughMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { + return false; +} + +bool PassthroughMqttHandler::publishBytes(uint8_t* buf, uint16_t len) { + mqtt.publish(topic.c_str(), toHex(buf, len)); + bool ret = mqtt.loop(); + delay(10); + return ret; +} + +bool PassthroughMqttHandler::publishString(char* str) { + mqtt.publish(topic.c_str(), str); + bool ret = mqtt.loop(); + delay(10); + return ret; +} + +uint8_t PassthroughMqttHandler::getFormat() { + return 255; +} \ No newline at end of file diff --git a/src/PassthroughMqttHandler.h b/src/PassthroughMqttHandler.h new file mode 100644 index 00000000..b3b72f53 --- /dev/null +++ b/src/PassthroughMqttHandler.h @@ -0,0 +1,28 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _PASSTHROUGHMQTTHANDLER_H +#define _PASSTHROUGHMQTTHANDLER_H + +#include "AmsMqttHandler.h" + +class PassthroughMqttHandler : public AmsMqttHandler { +public: + PassthroughMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf) : AmsMqttHandler(mqttConfig, debugger, buf) { + this->topic = String(mqttConfig.publishTopic); + }; + bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); + bool publishTemperatures(AmsConfiguration*, HwTools*); + bool publishPrices(EntsoeApi*); + bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); + bool publishBytes(uint8_t* buf, uint16_t len); + bool publishString(char* str); + +private: + String topic; + uint8_t getFormat(); +}; +#endif diff --git a/src/WiFiAccessPointConnectionHandler.cpp b/src/WiFiAccessPointConnectionHandler.cpp new file mode 100644 index 00000000..3b500abe --- /dev/null +++ b/src/WiFiAccessPointConnectionHandler.cpp @@ -0,0 +1,72 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "WiFiAccessPointConnectionHandler.h" + +WiFiAccessPointConnectionHandler::WiFiAccessPointConnectionHandler(RemoteDebug* debugger) { + this->debugger = debugger; + this->mode = NETWORK_MODE_WIFI_AP; +} + +bool WiFiAccessPointConnectionHandler::connect(NetworkConfig config, SystemConfig sys) { + //wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, 0); // Disable default gw + + WiFi.mode(WIFI_AP); + WiFi.softAP(config.ssid, config.psk); + + dnsServer.setErrorReplyCode(DNSReplyCode::NoError); + dnsServer.start(53, PSTR("*"), WiFi.softAPIP()); + connected = true; + + return true; +} + +void WiFiAccessPointConnectionHandler::disconnect(unsigned long reconnectDelay) { + WiFi.disconnect(true); + WiFi.softAPdisconnect(true); + WiFi.enableAP(false); + WiFi.mode(WIFI_OFF); + yield(); +} + +bool WiFiAccessPointConnectionHandler::isConnected() { + return connected; +} + +#if defined(ESP32) +void WiFiAccessPointConnectionHandler::eventHandler(WiFiEvent_t event, WiFiEventInfo_t info) { + uint8_t mac[6]; + IPAddress stationIP; + switch(event) { + case ARDUINO_EVENT_WIFI_AP_START: + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("WiFi access point started with SSID %s\n"), config.ssid); + break; + case ARDUINO_EVENT_WIFI_AP_STOP: + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("WiFi access point stopped!\n")); + break; + case ARDUINO_EVENT_WIFI_AP_STACONNECTED: + memcpy(mac, info.wifi_ap_staconnected.mac, 6); + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Client connected to AP, client MAC: %02x:%02x:%02x:%02x:%02x:%02x\n"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + break; + case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: + memcpy(mac, info.wifi_ap_staconnected.mac, 6); + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Client disconnected from AP, client MAC: %02x:%02x:%02x:%02x:%02x:%02x\n"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + break; + case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: + stationIP = info.wifi_ap_staipassigned.ip.addr; + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Client was assigned IP %s\n"), stationIP.toString().c_str()); + break; + } +} +#endif + +bool WiFiAccessPointConnectionHandler::isConfigChanged() { + return configChanged; +} + +void WiFiAccessPointConnectionHandler::getCurrentConfig(NetworkConfig& networkConfig) { + networkConfig = this->config; +} \ No newline at end of file diff --git a/src/WiFiAccessPointConnectionHandler.h b/src/WiFiAccessPointConnectionHandler.h new file mode 100644 index 00000000..1e3c235c --- /dev/null +++ b/src/WiFiAccessPointConnectionHandler.h @@ -0,0 +1,39 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _WIFIACCESSPOINTCONNECTIONHANDLER_H +#define _WIFIACCESSPOINTCONNECTIONHANDLER_H + +#include "ConnectionHandler.h" +#include +#include "RemoteDebug.h" +#include + +class WiFiAccessPointConnectionHandler : public ConnectionHandler { +public: + WiFiAccessPointConnectionHandler(RemoteDebug* debugger); + + bool connect(NetworkConfig config, SystemConfig sys); + void disconnect(unsigned long reconnectDelay); + bool isConnected(); + bool isConfigChanged(); + void getCurrentConfig(NetworkConfig& networkConfig); + + #if defined(ESP32) + void eventHandler(WiFiEvent_t event, WiFiEventInfo_t info); + #endif + +private: + RemoteDebug* debugger; + NetworkConfig config; + + DNSServer dnsServer; + + bool connected = false; + bool configChanged = false; +}; + +#endif diff --git a/src/WiFiClientConnectionHandler.cpp b/src/WiFiClientConnectionHandler.cpp new file mode 100644 index 00000000..e0068342 --- /dev/null +++ b/src/WiFiClientConnectionHandler.cpp @@ -0,0 +1,224 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#include "WiFiClientConnectionHandler.h" +#if defined(ESP32) +#include +#endif + +WiFiClientConnectionHandler::WiFiClientConnectionHandler(RemoteDebug* debugger) { + this->debugger = debugger; + this->mode = NETWORK_MODE_WIFI_CLIENT; +} + +bool WiFiClientConnectionHandler::connect(NetworkConfig config, SystemConfig sys) { + if(lastRetry > 0 && (millis() - lastRetry) < timeout) { + delay(50); + return false; + } + lastRetry = millis(); + + if (WiFi.status() != WL_CONNECTED) { + if(config.mode != this->mode || strlen(config.ssid) == 0) { + return false; + } + + if(WiFi.getMode() != WIFI_OFF) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Not connected to WiFi, closing resources\n")); + + disconnect(RECONNECT_TIMEOUT); + return false; + } + timeout = CONNECTION_TIMEOUT; + + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Connecting to WiFi network: %s\n"), config.ssid); + switch(sys.boardType) { + case 2: // spenceme + case 3: // Pow-K UART0 + case 4: // Pow-U UART0 + case 5: // Pow-K+ + case 6: // Pow-P1 + case 7: // Pow-U+ + case 8: // dbeinder: HAN mosquito + busPowered = true; + break; + default: + busPowered = false; + } + firstConnect = sys.dataCollectionConsent == 0; + + #if defined(ESP32) + if(strlen(config.hostname) > 0) { + WiFi.setHostname(config.hostname); + } + #endif + WiFi.mode(WIFI_STA); + + if(strlen(config.ip) > 0) { + IPAddress ip, gw, sn(255,255,255,0), dns1, dns2; + ip.fromString(config.ip); + gw.fromString(config.gateway); + sn.fromString(config.subnet); + if(strlen(config.dns1) > 0) { + dns1.fromString(config.dns1); + } else if(strlen(config.gateway) > 0) { + dns1.fromString(config.gateway); // If no DNS, set gateway by default + } + if(strlen(config.dns2) > 0) { + dns2.fromString(config.dns2); + } else if(dns1.toString().isEmpty()) { + dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured + } + if(!WiFi.config(ip, gw, sn, dns1, dns2)) { + debugger->printf_P(PSTR("Static IP configuration is invalid, not using\n")); + } + } + #if defined(ESP8266) + if(strlen(config.hostname) > 0) { + WiFi.hostname(config.hostname); + } + //wifi_set_phy_mode(PHY_MODE_11N); + if(!config.use11b) { + wifi_set_user_sup_rate(RATE_11G6M, RATE_11G54M); + wifi_set_user_rate_limit(RC_LIMIT_11G, 0x00, RATE_11G_G54M, RATE_11G_G6M); + wifi_set_user_rate_limit(RC_LIMIT_11N, 0x00, RATE_11N_MCS7S, RATE_11N_MCS0); + wifi_set_user_limit_rate_mask(LIMIT_RATE_MASK_ALL); + } + #endif + #if defined(ESP32) + WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); + WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); + #endif + WiFi.setAutoReconnect(true); + if(WiFi.begin(config.ssid, config.psk)) { + if(config.sleep <= 2) { + switch(config.sleep) { + case 0: + WiFi.setSleep(WIFI_PS_NONE); + break; + case 1: + WiFi.setSleep(WIFI_PS_MIN_MODEM); + break; + case 2: + WiFi.setSleep(WIFI_PS_MAX_MODEM); + break; + } + } + yield(); + } else { + if (debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Unable to start WiFi\n")); + } + this->config = config; + return true; + } + return false; +} + +void WiFiClientConnectionHandler::disconnect(unsigned long reconnectDelay) { + if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Disconnecting!\n")); + #if defined(ESP8266) + WiFiClient::stopAll(); + #endif + + WiFi.disconnect(true); + WiFi.softAPdisconnect(true); + WiFi.enableAP(false); + WiFi.mode(WIFI_OFF); + yield(); + timeout = reconnectDelay; +} + +bool WiFiClientConnectionHandler::isConnected() { + return WiFi.status() == WL_CONNECTED; +} + +#if defined(ESP32) +void WiFiClientConnectionHandler::eventHandler(WiFiEvent_t event, WiFiEventInfo_t info) { + switch(event) { + case ARDUINO_EVENT_WIFI_READY: + if (!config.use11b) { + esp_wifi_config_11b_rate(WIFI_IF_AP, true); + esp_wifi_config_11b_rate(WIFI_IF_STA, true); + } + break; + case ARDUINO_EVENT_WIFI_STA_GOT_IP: { + if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Successfully connected to WiFi!\n")); + if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf_P(PSTR("IP: %s\n"), WiFi.localIP().toString().c_str()); + debugger->printf_P(PSTR("GW: %s\n"), WiFi.gatewayIP().toString().c_str()); + debugger->printf_P(PSTR("DNS: %s\n"), WiFi.dnsIP().toString().c_str()); + } + #if defined(ESP32) + if(firstConnect && config.use11b) { + // If first boot and phyMode is better than 11b, disable 11b for BUS powered devices + if(busPowered) { + wifi_phy_mode_t phyMode; + if(esp_wifi_sta_get_negotiated_phymode(&phyMode) == ESP_OK) { + if(phyMode > WIFI_PHY_MODE_11B) { + if (debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("WiFi supports better rates than 802.11b, disabling\n")); + config.use11b = false; + configChanged = true; + return; + } + } + } + } + + if(config.power >= 195) + WiFi.setTxPower(WIFI_POWER_19_5dBm); + else if(config.power >= 190) + WiFi.setTxPower(WIFI_POWER_19dBm); + else if(config.power >= 185) + WiFi.setTxPower(WIFI_POWER_18_5dBm); + else if(config.power >= 170) + WiFi.setTxPower(WIFI_POWER_17dBm); + else if(config.power >= 150) + WiFi.setTxPower(WIFI_POWER_15dBm); + else if(config.power >= 130) + WiFi.setTxPower(WIFI_POWER_13dBm); + else if(config.power >= 110) + WiFi.setTxPower(WIFI_POWER_11dBm); + else if(config.power >= 85) + WiFi.setTxPower(WIFI_POWER_8_5dBm); + else if(config.power >= 70) + WiFi.setTxPower(WIFI_POWER_7dBm); + else if(config.power >= 50) + WiFi.setTxPower(WIFI_POWER_5dBm); + else if(config.power >= 20) + WiFi.setTxPower(WIFI_POWER_2dBm); + else + WiFi.setTxPower(WIFI_POWER_MINUS_1dBm); + #elif defined(ESP8266) + WiFi.setOutputPower(config.power / 10.0); + #endif + } + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: { + wifi_err_reason_t reason = (wifi_err_reason_t) info.wifi_sta_disconnected.reason; + const char* descr = WiFi.disconnectReasonName(reason); + switch(reason) { + case WIFI_REASON_ASSOC_LEAVE: + break; + default: + if(strlen(descr) > 0) { + if(debugger->isActive(RemoteDebug::WARNING)) { + debugger->printf_P(PSTR("WiFi disconnected, reason %s\n"), descr); + } + disconnect(RECONNECT_TIMEOUT); + } + } + break; + } + } +} +#endif + +bool WiFiClientConnectionHandler::isConfigChanged() { + return configChanged; +} + +void WiFiClientConnectionHandler::getCurrentConfig(NetworkConfig& networkConfig) { + networkConfig = this->config; +} \ No newline at end of file diff --git a/src/WiFiClientConnectionHandler.h b/src/WiFiClientConnectionHandler.h new file mode 100644 index 00000000..db9e0017 --- /dev/null +++ b/src/WiFiClientConnectionHandler.h @@ -0,0 +1,42 @@ +/** + * @copyright Utilitech AS 2023 + * License: Fair Source + * + */ + +#ifndef _WIFICLIENTCONNECTIONHANDLER_H +#define _WIFICLIENTCONNECTIONHANDLER_H + +#include "ConnectionHandler.h" +#include +#include "RemoteDebug.h" + +#define CONNECTION_TIMEOUT 30000 +#define RECONNECT_TIMEOUT 5000 + +class WiFiClientConnectionHandler : public ConnectionHandler { +public: + WiFiClientConnectionHandler(RemoteDebug* debugger); + + bool connect(NetworkConfig config, SystemConfig sys); + void disconnect(unsigned long reconnectDelay); + bool isConnected(); + bool isConfigChanged(); + void getCurrentConfig(NetworkConfig& networkConfig); + + #if defined(ESP32) + void eventHandler(WiFiEvent_t event, WiFiEventInfo_t info); + #endif + +private: + RemoteDebug* debugger; + NetworkConfig config; + bool busPowered = false; + bool firstConnect = true; + bool configChanged = false; + + unsigned long timeout = CONNECTION_TIMEOUT; + unsigned long lastRetry = 0; +}; + +#endif