merging master

This commit is contained in:
MalteSchm 2023-03-26 11:25:08 +02:00
commit a4767827b4
32 changed files with 636 additions and 519 deletions

View File

@ -18,6 +18,10 @@ This project is still under development and adds following features:
[![OpenDTU Build](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml) [![OpenDTU Build](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml)
[![cpplint](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml) [![cpplint](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml)
## !! IMPORTANT UPGRADE NOTES !!
If you are upgrading from a version before 15.03.2023 you have to upgrade the partition table of the ESP32. Please follow the [this](docs/UpgradePartition.md) documentation!
## Background ## Background
This project was started from [this](https://www.mikrocontroller.net/topic/525778) discussion (Mikrocontroller.net). This project was started from [this](https://www.mikrocontroller.net/topic/525778) discussion (Mikrocontroller.net).
It was the goal to replace the original Hoymiles DTU (Telemetry Gateway) with their cloud access. With a lot of reverse engineering the Hoymiles protocol was decrypted and analyzed. It was the goal to replace the original Hoymiles DTU (Telemetry Gateway) with their cloud access. With a lot of reverse engineering the Hoymiles protocol was decrypted and analyzed.
@ -235,6 +239,7 @@ Firmware version seems to play not a significant role and cannot be read from th
## Breaking changes ## Breaking changes
Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | grep BREAKING` Generated using: `git log --date=short --pretty=format:"* %h%x09%ad%x09%s" | grep BREAKING`
``` ```
* 318136d 2023-03-15 BREAKING CHANGE: Updated partition table: Make sure you have a configuration backup and completly reflash the device!
* 3b7aef6 2023-02-13 BREAKING CHANGE: Web API! * 3b7aef6 2023-02-13 BREAKING CHANGE: Web API!
* d4c838a 2023-02-06 BREAKING CHANGE: Prometheus API! * d4c838a 2023-02-06 BREAKING CHANGE: Prometheus API!
* daf847e 2022-11-14 BREAKING CHANGE: Removed deprecated config parsing method * daf847e 2022-11-14 BREAKING CHANGE: Removed deprecated config parsing method

24
docs/UpgradePartition.md Normal file
View File

@ -0,0 +1,24 @@
# Upgrade Partition
To be able to install further updates you have to update the partition table of the ESP32. Doing so will **erase** all configuration data. Over The Air update using the web interface is **NOT** possible!
**So make sure you export a backup of your configuration files before continuing.**
There are several possibilities to update the partition table:
- Using Visual Studio Code or PlatformIO CLI
If you have already used Visual Studio Code or the `platformio` command you can use it again to install the latest version. The partition table is upgraded automatically.
- Any kind of flash interface
If you like to use any kind of flash interface like `esptool.py`, Espressif Flash Download Tool, ESP_Flasher or esptool-js you have to make sure to upload **ALL** provided .bin files. It is important to enter the correct target addresses.
| Address | File |
| ---------| ---------------------- |
| 0x1000 | bootloader.bin |
| 0x8000 | partitions.bin |
| 0xe000 | boot_app0.bin |
| 0x10000 | opendtu-*.bin |
After upgrading the ESP32 will open the intergrated access point (AP) again. Just connect to it using the default password ("openDTU42"). If you are connected, just visit http://192.168.4.1 and enter the "Configuration Management". Recover the previously backuped config files.

View File

@ -101,6 +101,7 @@ struct CONFIG_T {
bool PowerLimiter_Enabled; bool PowerLimiter_Enabled;
bool PowerLimiter_SolarPassTroughEnabled; bool PowerLimiter_SolarPassTroughEnabled;
uint8_t PowerLimiter_BatteryDrainStategy;
uint32_t PowerLimiter_Interval; uint32_t PowerLimiter_Interval;
char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1]; char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1]; char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];
@ -108,10 +109,10 @@ struct CONFIG_T {
bool PowerLimiter_IsInverterBehindPowerMeter; bool PowerLimiter_IsInverterBehindPowerMeter;
uint8_t PowerLimiter_InverterId; uint8_t PowerLimiter_InverterId;
uint8_t PowerLimiter_InverterChannelId; uint8_t PowerLimiter_InverterChannelId;
uint32_t PowerLimiter_TargetPowerConsumption; int32_t PowerLimiter_TargetPowerConsumption;
uint32_t PowerLimiter_TargetPowerConsumptionHysteresis; int32_t PowerLimiter_TargetPowerConsumptionHysteresis;
uint32_t PowerLimiter_LowerPowerLimit; int32_t PowerLimiter_LowerPowerLimit;
uint32_t PowerLimiter_UpperPowerLimit; int32_t PowerLimiter_UpperPowerLimit;
uint32_t PowerLimiter_BatterySocStartThreshold; uint32_t PowerLimiter_BatterySocStartThreshold;
uint32_t PowerLimiter_BatterySocStopThreshold; uint32_t PowerLimiter_BatterySocStopThreshold;
float PowerLimiter_VoltageStartThreshold; float PowerLimiter_VoltageStartThreshold;
@ -128,7 +129,7 @@ struct CONFIG_T {
bool Display_PowerSafe; bool Display_PowerSafe;
bool Display_ScreenSaver; bool Display_ScreenSaver;
bool Display_ShowLogo; uint8_t Display_Rotation;
uint8_t Display_Contrast; uint8_t Display_Contrast;
}; };

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "defaults.h"
#include <U8g2lib.h> #include <U8g2lib.h>
enum DisplayType_t { enum DisplayType_t {
@ -17,25 +18,29 @@ public:
void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset); void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset);
void loop(); void loop();
void setContrast(uint8_t contrast);
void setOrientation(uint8_t rotation = DISPLAY_ROTATION);
void setStartupDisplay();
bool enablePowerSafe = true; bool enablePowerSafe = true;
bool enableScreensaver = true; bool enableScreensaver = true;
bool showLogo = true;
uint8_t contrast = 60;
private: private:
void printText(const char* text, uint8_t line); void printText(const char* text, uint8_t line);
void calcLineHeights();
void setFont(uint8_t line);
U8G2* _display; U8G2* _display;
DisplayType_t _display_type = DisplayType_t::None; DisplayType_t _display_type = DisplayType_t::None;
uint8_t _mExtra; uint8_t _mExtra;
uint16_t _dispY = 0;
uint16_t _period = 1000; uint16_t _period = 1000;
uint16_t _interval = 60000; // interval at which to power save (milliseconds) uint16_t _interval = 60000; // interval at which to power save (milliseconds)
uint32_t _lastDisplayUpdate = 0; uint32_t _lastDisplayUpdate = 0;
uint32_t _previousMillis = 0; uint32_t _previousMillis = 0;
char _fmtText[32]; char _fmtText[32];
bool _isLarge = false;
uint8_t _lineOffsets[5];
}; };
extern DisplayGraphicClass Display; extern DisplayGraphicClass Display;

View File

@ -2,8 +2,8 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <stdint.h>
#include <ETH.h> #include <ETH.h>
#include <stdint.h>
#define PINMAPPING_FILENAME "/pin_mapping.json" #define PINMAPPING_FILENAME "/pin_mapping.json"

View File

@ -14,20 +14,25 @@ typedef enum {
STATE_NORMAL_OPERATION STATE_NORMAL_OPERATION
} plStates; } plStates;
typedef enum {
EMPTY_WHEN_FULL= 0,
EMPTY_AT_NIGTH
} batDrainStrategy;
class PowerLimiterClass { class PowerLimiterClass {
public: public:
void init(); void init();
void loop(); void loop();
plStates getPowerLimiterState(); plStates getPowerLimiterState();
uint16_t getLastRequestedPowewrLimit(); int32_t getLastRequestedPowewrLimit();
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total); void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
private: private:
uint32_t _lastCommandSent; uint32_t _lastCommandSent;
uint32_t _lastLoop; uint32_t _lastLoop;
uint32_t _lastPowerMeterUpdate; uint32_t _lastPowerMeterUpdate;
uint16_t _lastRequestedPowerLimit; int32_t _lastRequestedPowerLimit;
plStates _plState = STATE_DISCOVER; plStates _plState = STATE_DISCOVER;
float _powerMeter1Power; float _powerMeter1Power;
@ -36,8 +41,8 @@ private:
bool canUseDirectSolarPower(); bool canUseDirectSolarPower();
int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool consumeSolarPowerOnly); int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool consumeSolarPowerOnly);
void setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, uint32_t newPowerLimit); void setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit);
uint16_t getDirectSolarPower(); int32_t getDirectSolarPower();
float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter); float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter);
bool isStartThresholdReached(std::shared_ptr<InverterAbstract> inverter); bool isStartThresholdReached(std::shared_ptr<InverterAbstract> inverter);
bool isStopThresholdReached(std::shared_ptr<InverterAbstract> inverter); bool isStopThresholdReached(std::shared_ptr<InverterAbstract> inverter);

View File

@ -15,6 +15,8 @@ private:
void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* channelName = NULL); void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* channelName = NULL);
void addPanelInfo(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel);
AsyncWebServer* _server; AsyncWebServer* _server;
enum { enum {

View File

@ -85,7 +85,7 @@
#define DISPLAY_POWERSAFE true #define DISPLAY_POWERSAFE true
#define DISPLAY_SCREENSAVER true #define DISPLAY_SCREENSAVER true
#define DISPLAY_SHOWLOGO true #define DISPLAY_ROTATION 2
#define DISPLAY_CONTRAST 60 #define DISPLAY_CONTRAST 60
#define VEDIRECT_ENABLED false #define VEDIRECT_ENABLED false
@ -94,6 +94,7 @@
#define POWERLIMITER_ENABLED false #define POWERLIMITER_ENABLED false
#define POWERLIMITER_SOLAR_PASSTROUGH_ENABLED true #define POWERLIMITER_SOLAR_PASSTROUGH_ENABLED true
#define POWERLIMITER_BATTERY_DRAIN_STRATEGY 0
#define POWERLIMITER_INTERVAL 10 #define POWERLIMITER_INTERVAL 10
#define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true #define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true
#define POWERLIMITER_INVERTER_ID 0 #define POWERLIMITER_INVERTER_ID 0

View File

@ -33,16 +33,16 @@ typedef struct {
uint8_t ERR; // error code uint8_t ERR; // error code
uint32_t OR; // off reason uint32_t OR; // off reason
uint8_t MPPT; // state of MPP tracker uint8_t MPPT; // state of MPP tracker
uint16_t HSDS; // day sequence number 1...365 uint32_t HSDS; // day sequence number 1...365
double V; // battery voltage in V double V; // battery voltage in V
double I; // battery current in A double I; // battery current in A
double VPV; // panel voltage in V double VPV; // panel voltage in V
uint16_t PPV; // panel power in W int32_t PPV; // panel power in W
double H19; // yield total kWh double H19; // yield total kWh
double H20; // yield today kWh double H20; // yield today kWh
uint16_t H21; // maximum power today W int32_t H21; // maximum power today W
double H22; // yield yesterday kWh double H22; // yield yesterday kWh
uint16_t H23; // maximum power yesterday W int32_t H23; // maximum power yesterday W
} veStruct; } veStruct;
class VeDirectFrameHandler { class VeDirectFrameHandler {

View File

@ -1,6 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000, nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000, otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x180000, app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x190000,0x180000, app1, app, ota_1, 0x1F0000, 0x1E0000,
spiffs, data, spiffs, ,0x50000 spiffs, data, spiffs, 0x3D0000, 0x30000,
1 # Name, Type, SubType, Offset, Size, Flags # Name Type SubType Offset Size Flags
2 nvs, data, nvs, 0x9000, 0x5000, nvs data nvs 0x9000 0x5000
3 otadata, data, ota, 0xe000, 0x2000, otadata data ota 0xe000 0x2000
4 app0, app, ota_0, 0x10000, 0x180000, app0 app ota_0 0x10000 0x1E0000
5 app1, app, ota_1, 0x190000,0x180000, app1 app ota_1 0x1F0000 0x1E0000
6 spiffs, data, spiffs, ,0x50000 spiffs data spiffs 0x3D0000 0x30000

View File

@ -23,8 +23,8 @@ build_flags =
lib_deps = lib_deps =
https://github.com/yubox-node-org/ESPAsyncWebServer https://github.com/yubox-node-org/ESPAsyncWebServer
bblanchon/ArduinoJson @ ^6.20.1 bblanchon/ArduinoJson @ ^6.21.0
https://github.com/bertmelis/espMqttClient.git#v1.3.3 https://github.com/bertmelis/espMqttClient.git#v1.4.1
nrf24/RF24 @ ^1.4.5 nrf24/RF24 @ ^1.4.5
olikraus/U8g2 @ ^2.34.13 olikraus/U8g2 @ ^2.34.13
buelowp/sunset @ ^1.1.7 buelowp/sunset @ ^1.1.7

View File

@ -88,7 +88,7 @@ bool ConfigurationClass::write()
JsonObject display = device.createNestedObject("display"); JsonObject display = device.createNestedObject("display");
display["powersafe"] = config.Display_PowerSafe; display["powersafe"] = config.Display_PowerSafe;
display["screensaver"] = config.Display_ScreenSaver; display["screensaver"] = config.Display_ScreenSaver;
display["showlogo"] = config.Display_ShowLogo; display["rotation"] = config.Display_Rotation;
display["contrast"] = config.Display_Contrast; display["contrast"] = config.Display_Contrast;
JsonArray inverters = doc.createNestedArray("inverters"); JsonArray inverters = doc.createNestedArray("inverters");
@ -118,6 +118,7 @@ bool ConfigurationClass::write()
JsonObject powerlimiter = doc.createNestedObject("powerlimiter"); JsonObject powerlimiter = doc.createNestedObject("powerlimiter");
powerlimiter["enabled"] = config.PowerLimiter_Enabled; powerlimiter["enabled"] = config.PowerLimiter_Enabled;
powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled; powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled;
powerlimiter["battery_drain_strategy"] = config.PowerLimiter_BatteryDrainStategy;
powerlimiter["interval"] = config.PowerLimiter_Interval; powerlimiter["interval"] = config.PowerLimiter_Interval;
powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1; powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1;
powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2; powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2;
@ -256,7 +257,7 @@ bool ConfigurationClass::read()
JsonObject display = device["display"]; JsonObject display = device["display"];
config.Display_PowerSafe = display["powersafe"] | DISPLAY_POWERSAFE; config.Display_PowerSafe = display["powersafe"] | DISPLAY_POWERSAFE;
config.Display_ScreenSaver = display["screensaver"] | DISPLAY_SCREENSAVER; config.Display_ScreenSaver = display["screensaver"] | DISPLAY_SCREENSAVER;
config.Display_ShowLogo = display["showlogo"] | DISPLAY_SHOWLOGO; config.Display_Rotation = display["rotation"] | DISPLAY_ROTATION;
config.Display_Contrast = display["contrast"] | DISPLAY_CONTRAST; config.Display_Contrast = display["contrast"] | DISPLAY_CONTRAST;
JsonArray inverters = doc["inverters"]; JsonArray inverters = doc["inverters"];
@ -286,6 +287,7 @@ bool ConfigurationClass::read()
JsonObject powerlimiter = doc["powerlimiter"]; JsonObject powerlimiter = doc["powerlimiter"];
config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_ENABLED; config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_ENABLED;
config.PowerLimiter_SolarPassTroughEnabled = powerlimiter["solar_passtrough_enabled"] | POWERLIMITER_SOLAR_PASSTROUGH_ENABLED; config.PowerLimiter_SolarPassTroughEnabled = powerlimiter["solar_passtrough_enabled"] | POWERLIMITER_SOLAR_PASSTROUGH_ENABLED;
config.PowerLimiter_BatteryDrainStategy = powerlimiter["battery_drain_strategy"] | POWERLIMITER_BATTERY_DRAIN_STRATEGY;
config.PowerLimiter_Interval = POWERLIMITER_INTERVAL; config.PowerLimiter_Interval = POWERLIMITER_INTERVAL;
strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, powerlimiter["mqtt_topic_powermeter_1"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter1)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, powerlimiter["mqtt_topic_powermeter_1"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter1));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, powerlimiter["mqtt_topic_powermeter_2"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter2)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, powerlimiter["mqtt_topic_powermeter_2"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter2));

View File

@ -5,31 +5,6 @@
#include <map> #include <map>
#include <time.h> #include <time.h>
static uint8_t bmp_logo[] PROGMEM = {
B00000000, B00000000, // ................
B11101100, B00110111, // ..##.######.##..
B11101100, B00110111, // ..##.######.##..
B11100000, B00000111, // .....######.....
B11010000, B00001011, // ....#.####.#....
B10011000, B00011001, // ...##..##..##...
B10000000, B00000001, // .......##.......
B00000000, B00000000, // ................
B01111000, B00011110, // ...####..####...
B11111100, B00111111, // ..############..
B01111100, B00111110, // ..#####..#####..
B00000000, B00000000, // ................
B11111100, B00111111, // ..############..
B11111110, B01111111, // .##############.
B01111110, B01111110, // .######..######.
B00000000, B00000000 // ................
};
static uint8_t bmp_arrow[] PROGMEM = {
B00000000, B00011100, B00011100, B00001110, B00001110, B11111110, B01111111,
B01110000, B01110000, B00110000, B00111000, B00011000, B01111111, B00111111,
B00011110, B00001110, B00000110, B00000000, B00000000, B00000000, B00000000
};
std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>> display_types = { std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>> display_types = {
{ DisplayType_t::PCD8544, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_PCD8544_84X48_F_4W_HW_SPI(U8G2_R0, cs, data, reset); } }, { DisplayType_t::PCD8544, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_PCD8544_84X48_F_4W_HW_SPI(U8G2_R0, cs, data, reset); } },
{ DisplayType_t::SSD1306, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } }, { DisplayType_t::SSD1306, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } },
@ -52,56 +27,83 @@ void DisplayGraphicClass::init(DisplayType_t type, uint8_t data, uint8_t clk, ui
auto constructor = display_types[_display_type]; auto constructor = display_types[_display_type];
_display = constructor(reset, clk, data, cs); _display = constructor(reset, clk, data, cs);
_display->begin(); _display->begin();
setContrast(DISPLAY_CONTRAST);
}
}
void DisplayGraphicClass::calcLineHeights()
{
uint8_t yOff = 0;
for (uint8_t i = 0; i < 4; i++) {
setFont(i);
yOff += (_display->getMaxCharHeight());
_lineOffsets[i] = yOff;
}
}
void DisplayGraphicClass::setFont(uint8_t line)
{
switch (line) {
case 0:
_display->setFont((_isLarge) ? u8g2_font_ncenB14_tr : u8g2_font_logisoso16_tr);
break;
case 3:
_display->setFont(u8g2_font_5x8_tr);
break;
default:
_display->setFont((_isLarge) ? u8g2_font_ncenB10_tr : u8g2_font_5x8_tr);
break;
} }
} }
void DisplayGraphicClass::printText(const char* text, uint8_t line) void DisplayGraphicClass::printText(const char* text, uint8_t line)
{ {
// get the width and height of the display uint8_t dispX;
uint16_t maxWidth = _display->getWidth(); if (!_isLarge) {
uint16_t maxHeight = _display->getHeight(); dispX = (line == 0) ? 5 : 0;
// pxMovement +x (0 - 6 px)
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
// set the font size based on the display size
switch (line) {
case 1:
if (maxWidth > 120 && maxHeight > 60) {
_display->setFont(u8g2_font_ncenB14_tr); // large display
} else {
_display->setFont(u8g2_font_logisoso16_tr); // small display
}
break;
case 4:
if (maxWidth > 120 && maxHeight > 60) {
_display->setFont(u8g2_font_5x8_tr); // large display
} else {
_display->setFont(u8g2_font_5x8_tr); // small display
}
break;
default:
if (maxWidth > 120 && maxHeight > 60) {
_display->setFont(u8g2_font_ncenB10_tr); // large display
} else {
_display->setFont(u8g2_font_5x8_tr); // small display
}
break;
}
// get the font height, to calculate the textheight
_dispY += (_display->getMaxCharHeight()) + 1;
// calculate the starting position of the text
uint16_t dispX;
if (line == 1) {
dispX = 20 + ex;
} else { } else {
dispX = 5 + ex; dispX = (line == 0) ? 20 : 5;
}
setFont(line);
dispX += enableScreensaver ? (_mExtra % 7) : 0;
_display->drawStr(dispX, _lineOffsets[line], text);
}
void DisplayGraphicClass::setOrientation(uint8_t rotation)
{
if (_display_type == DisplayType_t::None) {
return;
} }
// draw the Text, on the calculated pos switch (rotation) {
_display->drawStr(dispX, _dispY, text); case 0:
_display->setDisplayRotation(U8G2_R0);
break;
case 1:
_display->setDisplayRotation(U8G2_R1);
break;
case 2:
_display->setDisplayRotation(U8G2_R2);
break;
case 3:
_display->setDisplayRotation(U8G2_R3);
break;
}
_isLarge = (_display->getWidth() > 100);
calcLineHeights();
}
void DisplayGraphicClass::setStartupDisplay()
{
if (_display_type == DisplayType_t::None) {
return;
}
_display->clearBuffer();
printText("OpenDTU!", 0);
_display->sendBuffer();
} }
void DisplayGraphicClass::loop() void DisplayGraphicClass::loop()
@ -136,20 +138,6 @@ void DisplayGraphicClass::loop()
_display->clearBuffer(); _display->clearBuffer();
// set Contrast of the Display to raise the lifetime
_display->setContrast(contrast);
//=====> Logo and Lighting ==========
// pxMovement +x (0 - 6 px)
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
if (isprod > 0) {
_display->drawXBMP(5 + ex, 1, 8, 17, bmp_arrow);
if (showLogo) {
_display->drawXBMP(_display->getWidth() - 24 + ex, 2, 16, 16, bmp_logo);
}
}
//<=======================
//=====> Actual Production ========== //=====> Actual Production ==========
if ((totalPower > 0) && (isprod > 0)) { if ((totalPower > 0) && (isprod > 0)) {
_display->setPowerSave(false); _display->setPowerSave(false);
@ -158,14 +146,14 @@ void DisplayGraphicClass::loop()
} else { } else {
snprintf(_fmtText, sizeof(_fmtText), "%3.0f W", totalPower); snprintf(_fmtText, sizeof(_fmtText), "%3.0f W", totalPower);
} }
printText(_fmtText, 1); printText(_fmtText, 0);
_previousMillis = millis(); _previousMillis = millis();
} }
//<======================= //<=======================
//=====> Offline =========== //=====> Offline ===========
else { else {
printText("offline", 1); printText("offline", 0);
// check if it's time to enter power saving mode // check if it's time to enter power saving mode
if (millis() - _previousMillis >= (_interval * 2)) { if (millis() - _previousMillis >= (_interval * 2)) {
_display->setPowerSave(enablePowerSafe); _display->setPowerSave(enablePowerSafe);
@ -175,27 +163,34 @@ void DisplayGraphicClass::loop()
//=====> Today & Total Production ======= //=====> Today & Total Production =======
snprintf(_fmtText, sizeof(_fmtText), "today: %4.0f Wh", totalYieldDay); snprintf(_fmtText, sizeof(_fmtText), "today: %4.0f Wh", totalYieldDay);
printText(_fmtText, 2); printText(_fmtText, 1);
snprintf(_fmtText, sizeof(_fmtText), "total: %.1f kWh", totalYieldTotal); snprintf(_fmtText, sizeof(_fmtText), "total: %.1f kWh", totalYieldTotal);
printText(_fmtText, 3); printText(_fmtText, 2);
//<======================= //<=======================
//=====> IP or Date-Time ======== //=====> IP or Date-Time ========
if (!(_mExtra % 10) && NetworkSettings.localIP()) { if (!(_mExtra % 10) && NetworkSettings.localIP()) {
printText(NetworkSettings.localIP().toString().c_str(), 4); printText(NetworkSettings.localIP().toString().c_str(), 3);
} else { } else {
// Get current time // Get current time
time_t now = time(nullptr); time_t now = time(nullptr);
strftime(_fmtText, sizeof(_fmtText), "%a %d.%m.%Y %H:%M", localtime(&now)); strftime(_fmtText, sizeof(_fmtText), "%a %d.%m.%Y %H:%M", localtime(&now));
printText(_fmtText, 4); printText(_fmtText, 3);
} }
_display->sendBuffer(); _display->sendBuffer();
_dispY = 0;
_mExtra++; _mExtra++;
_lastDisplayUpdate = millis(); _lastDisplayUpdate = millis();
} }
} }
void DisplayGraphicClass::setContrast(uint8_t contrast)
{
if (_display_type == DisplayType_t::None) {
return;
}
_display->setContrast(contrast * 2.55f);
}
DisplayGraphicClass Display; DisplayGraphicClass Display;

View File

@ -126,7 +126,9 @@ void MqttHandleInverterClass::publishField(std::shared_ptr<InverterAbstract> inv
return; return;
} }
MqttSettings.publish(topic, String(inv->Statistics()->getChannelFieldValue(type, channel, fieldId))); MqttSettings.publish(topic, String(
inv->Statistics()->getChannelFieldValue(type, channel, fieldId),
static_cast<unsigned int>(inv->Statistics()->getChannelFieldDigits(type, channel, fieldId))));
} }
String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId) String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)

View File

@ -117,13 +117,7 @@ void PowerLimiterClass::loop()
if (inverter->isProducing()) { if (inverter->isProducing()) {
MessageOutput.printf("[PowerLimiterClass::loop] DC voltage: %.2f Corrected DC voltage: %.2f...\r\n", MessageOutput.printf("[PowerLimiterClass::loop] DC voltage: %.2f Corrected DC voltage: %.2f...\r\n",
dcVoltage, correctedDcVoltage); dcVoltage, correctedDcVoltage);
MessageOutput.println("[PowerLimiterClass::loop] Stopping inverter..."); setNewPowerLimit(inverter, -1);
inverter->sendPowerControlRequest(Hoymiles.getRadio(), false);
uint16_t newPowerLimit = (uint16_t)config.PowerLimiter_LowerPowerLimit;
inverter->sendActivePowerControlRequest(Hoymiles.getRadio(), newPowerLimit, PowerLimitControlType::AbsolutNonPersistent);
_lastRequestedPowerLimit = newPowerLimit;
_lastCommandSent = millis();
return; return;
} }
@ -131,54 +125,54 @@ void PowerLimiterClass::loop()
if (isStopThresholdReached(inverter)) if (isStopThresholdReached(inverter))
return; return;
// check for possible state changes // check for possible state changes
if (isStartThresholdReached(inverter) && calcPowerLimit(inverter, false) >= config.PowerLimiter_LowerPowerLimit) { if (canUseDirectSolarPower()) {
_plState = STATE_NORMAL_OPERATION;
}
else if (canUseDirectSolarPower() && calcPowerLimit(inverter, true) >= config.PowerLimiter_LowerPowerLimit) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY; _plState = STATE_CONSUME_SOLAR_POWER_ONLY;
} }
if (isStartThresholdReached(inverter)) {
// inverter on on state change _plState = STATE_NORMAL_OPERATION;
if (_plState != STATE_OFF) {
// DC voltage high enough, start the inverter
MessageOutput.println("[PowerLimiterClass::loop] Starting up inverter...");
inverter->sendPowerControlRequest(Hoymiles.getRadio(), true);
_lastCommandSent = millis();
return;
} }
else return;
return;
break; break;
case STATE_CONSUME_SOLAR_POWER_ONLY: { case STATE_CONSUME_SOLAR_POWER_ONLY: {
int32_t newPowerLimit = calcPowerLimit(inverter, true); int32_t newPowerLimit = calcPowerLimit(inverter, true);
if (!inverter->isProducing() if (isStopThresholdReached(inverter)) {
|| isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
_plState = STATE_OFF; _plState = STATE_OFF;
break; break;
} }
else if (!canUseDirectSolarPower() || isStartThresholdReached(inverter)) { if (isStartThresholdReached(inverter)) {
_plState = STATE_NORMAL_OPERATION; _plState = STATE_NORMAL_OPERATION;
break; break;
} }
if (!canUseDirectSolarPower()) {
if (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGTH)
_plState = STATE_NORMAL_OPERATION;
else
_plState = STATE_OFF;
break;
}
setNewPowerLimit(inverter, newPowerLimit); setNewPowerLimit(inverter, newPowerLimit);
return; return;
break; break;
} }
case STATE_NORMAL_OPERATION: { case STATE_NORMAL_OPERATION: {
int32_t newPowerLimit = calcPowerLimit(inverter, false); int32_t newPowerLimit = calcPowerLimit(inverter, false);
if (!inverter->isProducing() if (isStopThresholdReached(inverter)) {
|| isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
_plState = STATE_OFF; _plState = STATE_OFF;
break; break;
} }
// check if grid power consumption is within the upper an lower threshold of the target consumption if (canUseDirectSolarPower() && (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGTH)) {
else if (newPowerLimit >= (config.PowerLimiter_TargetPowerConsumption - config.PowerLimiter_TargetPowerConsumptionHysteresis) && _plState = STATE_CONSUME_SOLAR_POWER_ONLY;
newPowerLimit <= (config.PowerLimiter_TargetPowerConsumption + config.PowerLimiter_TargetPowerConsumptionHysteresis)) { break;
return;
} }
setNewPowerLimit(inverter, newPowerLimit);
// check if grid power consumption is not within the upper and lower threshold of the target consumption
if (newPowerLimit >= (config.PowerLimiter_TargetPowerConsumption - config.PowerLimiter_TargetPowerConsumptionHysteresis) &&
newPowerLimit <= (config.PowerLimiter_TargetPowerConsumption + config.PowerLimiter_TargetPowerConsumptionHysteresis)) {
return;
}
setNewPowerLimit(inverter, newPowerLimit);;
return; return;
break; break;
} }
@ -190,7 +184,7 @@ plStates PowerLimiterClass::getPowerLimiterState() {
return _plState; return _plState;
} }
uint16_t PowerLimiterClass::getLastRequestedPowewrLimit() { int32_t PowerLimiterClass::getLastRequestedPowewrLimit() {
return _lastRequestedPowerLimit; return _lastRequestedPowerLimit;
} }
@ -203,7 +197,7 @@ bool PowerLimiterClass::canUseDirectSolarPower()
return false; return false;
} }
if (VeDirect.veFrame.PPV < 10.0) { if (VeDirect.veFrame.PPV < 20) {
// Not enough power // Not enough power
return false; return false;
} }
@ -215,13 +209,14 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
{ {
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
int32_t newPowerLimit = _powerMeter1Power + _powerMeter2Power + _powerMeter3Power; int32_t newPowerLimit = round(_powerMeter1Power + _powerMeter2Power + _powerMeter3Power);
float efficency = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_EFF); float efficency = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_EFF);
uint32_t victronChargePower = this->getDirectSolarPower(); int32_t victronChargePower = this->getDirectSolarPower();
uint32_t adjustedVictronChargePower = victronChargePower * (efficency > 0.0 ? (efficency / 100.0) : 1.0); // if inverter is off, use 1.0 int32_t adjustedVictronChargePower = victronChargePower * (efficency > 0.0 ? (efficency / 100.0) : 1.0); // if inverter is off, use 1.0
MessageOutput.printf("[PowerLimiterClass::loop] victronChargePower: %d, efficiency: %.2f, consumeSolarPowerOnly: %s \r\n", victronChargePower, efficency, consumeSolarPowerOnly ? "true" : "false"); MessageOutput.printf("[PowerLimiterClass::loop] victronChargePower: %d, efficiency: %.2f, consumeSolarPowerOnly: %s, powerConsumption: %d \r\n",
victronChargePower, efficency, consumeSolarPowerOnly ? "true" : "false", newPowerLimit);
if (millis() - _lastPowerMeterUpdate < (30 * 1000)) { if (millis() - _lastPowerMeterUpdate < (30 * 1000)) {
if (config.PowerLimiter_IsInverterBehindPowerMeter) { if (config.PowerLimiter_IsInverterBehindPowerMeter) {
@ -234,7 +229,7 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
newPowerLimit -= config.PowerLimiter_TargetPowerConsumption; newPowerLimit -= config.PowerLimiter_TargetPowerConsumption;
uint16_t upperPowerLimit = config.PowerLimiter_UpperPowerLimit; int32_t upperPowerLimit = config.PowerLimiter_UpperPowerLimit;
if (consumeSolarPowerOnly && (upperPowerLimit > adjustedVictronChargePower)) { if (consumeSolarPowerOnly && (upperPowerLimit > adjustedVictronChargePower)) {
// Battery voltage too low, use Victron solar power (corrected by efficency factor) only // Battery voltage too low, use Victron solar power (corrected by efficency factor) only
upperPowerLimit = adjustedVictronChargePower; upperPowerLimit = adjustedVictronChargePower;
@ -247,18 +242,35 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
// set the limit to config.PowerLimiter_LowerPowerLimit for safety reasons. // set the limit to config.PowerLimiter_LowerPowerLimit for safety reasons.
newPowerLimit = config.PowerLimiter_LowerPowerLimit; newPowerLimit = config.PowerLimiter_LowerPowerLimit;
} }
MessageOutput.printf("[PowerLimiterClass::loop] newPowerLimit: %d\r\n", newPowerLimit);
return newPowerLimit; return newPowerLimit;
} }
void PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, uint32_t newPowerLimit) void PowerLimiterClass::setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit)
{ {
MessageOutput.printf("[PowerLimiterClass::loop] Limit Non-Persistent: %d W\r\n", newPowerLimit); if(_lastRequestedPowerLimit != newPowerLimit) {
inverter->sendActivePowerControlRequest(Hoymiles.getRadio(), newPowerLimit, PowerLimitControlType::AbsolutNonPersistent); CONFIG_T& config = Configuration.get();
_lastRequestedPowerLimit = newPowerLimit;
_lastCommandSent = millis(); // if limit too low turn inverter offf
if (newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
if (inverter->isProducing()) {
MessageOutput.println("[PowerLimiterClass::loop] Stopping inverter...");
inverter->sendPowerControlRequest(Hoymiles.getRadio(), false);
_lastCommandSent = millis();
}
newPowerLimit = config.PowerLimiter_LowerPowerLimit;
} else if (!inverter->isProducing()) {
MessageOutput.println("[PowerLimiterClass::loop] Starting up inverter...");
inverter->sendPowerControlRequest(Hoymiles.getRadio(), true);
_lastCommandSent = millis();
}
MessageOutput.printf("[PowerLimiterClass::loop] Limit Non-Persistent: %d W\r\n", newPowerLimit);
inverter->sendActivePowerControlRequest(Hoymiles.getRadio(), newPowerLimit, PowerLimitControlType::AbsolutNonPersistent);
_lastRequestedPowerLimit = newPowerLimit;
}
} }
uint16_t PowerLimiterClass::getDirectSolarPower() int32_t PowerLimiterClass::getDirectSolarPower()
{ {
if (!canUseDirectSolarPower()) { if (!canUseDirectSolarPower()) {
return 0; return 0;

View File

@ -31,16 +31,16 @@ void PylontechCanReceiverClass::enable()
// Install TWAI driver // Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) { if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
MessageOutput.printf("Driver installed\n"); MessageOutput.printf("[Pylontech] Twai driver installed\n");
} else { } else {
MessageOutput.printf("Failed to install driver\n"); MessageOutput.printf("[Pylontech] Failed to install Twai driver\n");
} }
// Start TWAI driver // Start TWAI driver
if (twai_start() == ESP_OK) { if (twai_start() == ESP_OK) {
MessageOutput.printf("Driver started\n"); MessageOutput.printf("[Pylontech] Twai driver started\n");
} else { } else {
MessageOutput.printf("Failed to start driver\n"); MessageOutput.printf("[Pylontech] Failed to start Twai driver\n");
} }
} }
@ -102,7 +102,7 @@ void PylontechCanReceiverClass::parseCanPackets()
// Check for messages. twai_recive is blocking when there is no data so we return if there are no frames in the buffer // Check for messages. twai_recive is blocking when there is no data so we return if there are no frames in the buffer
twai_status_info_t status_info; twai_status_info_t status_info;
if (twai_get_status_info(&status_info) != ESP_OK) { if (twai_get_status_info(&status_info) != ESP_OK) {
MessageOutput .printf("Failed to get status info\n"); MessageOutput.printf("[Pylontech]Failed to get Twai status info\n");
return; return;
} }
if (status_info.msgs_to_rx == 0) { if (status_info.msgs_to_rx == 0) {
@ -112,7 +112,7 @@ void PylontechCanReceiverClass::parseCanPackets()
// Wait for message to be received, function is blocking // Wait for message to be received, function is blocking
twai_message_t rx_message; twai_message_t rx_message;
if (twai_receive(&rx_message, pdMS_TO_TICKS(100)) != ESP_OK) { if (twai_receive(&rx_message, pdMS_TO_TICKS(100)) != ESP_OK) {
MessageOutput.printf("Failed to receive message\n"); MessageOutput.printf("[Pylontech] Failed to receive message\n");
return; return;
} }
@ -201,7 +201,6 @@ void PylontechCanReceiverClass::parseCanPackets()
} }
case 0x35E: { case 0x35E: {
String manufacturer = String(rx_message.data, rx_message.data_length_code); String manufacturer = String(rx_message.data, rx_message.data_length_code);
//CAN.readString(); //CAN.readString();
@ -230,7 +229,6 @@ void PylontechCanReceiverClass::parseCanPackets()
Battery.chargeImmediately); Battery.chargeImmediately);
#endif #endif
// this->readUnsignedInt8();
break; break;
} }
} }

View File

@ -64,7 +64,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
displayPinObj[F("reset")] = pin.display_reset; displayPinObj[F("reset")] = pin.display_reset;
JsonObject display = root.createNestedObject("display"); JsonObject display = root.createNestedObject("display");
display[F("show_logo")] = config.Display_ShowLogo; display[F("rotation")] = config.Display_Rotation;
display[F("power_safe")] = config.Display_PowerSafe; display[F("power_safe")] = config.Display_PowerSafe;
display[F("screensaver")] = config.Display_ScreenSaver; display[F("screensaver")] = config.Display_ScreenSaver;
display[F("contrast")] = config.Display_Contrast; display[F("contrast")] = config.Display_Contrast;
@ -141,15 +141,15 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
bool performRestart = root[F("curPin")][F("name")].as<String>() != config.Dev_PinMapping; bool performRestart = root[F("curPin")][F("name")].as<String>() != config.Dev_PinMapping;
strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping)); strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping));
config.Display_ShowLogo = root[F("display")][F("show_logo")].as<bool>(); config.Display_Rotation = root[F("display")][F("rotation")].as<uint8_t>();
config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>(); config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>();
config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>(); config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_t>(); config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_t>();
Display.showLogo = config.Display_ShowLogo; Display.setOrientation(config.Display_Rotation);
Display.enablePowerSafe = config.Display_PowerSafe; Display.enablePowerSafe = config.Display_PowerSafe;
Display.enableScreensaver = config.Display_ScreenSaver; Display.enableScreensaver = config.Display_ScreenSaver;
Display.contrast = config.Display_Contrast; Display.setContrast(config.Display_Contrast);
Configuration.write(); Configuration.write();

View File

@ -37,6 +37,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
root[F("enabled")] = config.PowerLimiter_Enabled; root[F("enabled")] = config.PowerLimiter_Enabled;
root[F("solar_passtrough_enabled")] = config.PowerLimiter_SolarPassTroughEnabled; root[F("solar_passtrough_enabled")] = config.PowerLimiter_SolarPassTroughEnabled;
root[F("battery_drain_strategy")] = config.PowerLimiter_BatteryDrainStategy;
root[F("mqtt_topic_powermeter_1")] = config.PowerLimiter_MqttTopicPowerMeter1; root[F("mqtt_topic_powermeter_1")] = config.PowerLimiter_MqttTopicPowerMeter1;
root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2; root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2;
root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3; root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3;
@ -120,6 +121,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get(); CONFIG_T& config = Configuration.get();
config.PowerLimiter_Enabled = root[F("enabled")].as<bool>(); config.PowerLimiter_Enabled = root[F("enabled")].as<bool>();
config.PowerLimiter_SolarPassTroughEnabled = root[F("solar_passtrough_enabled")].as<bool>(); config.PowerLimiter_SolarPassTroughEnabled = root[F("solar_passtrough_enabled")].as<bool>();
config.PowerLimiter_BatteryDrainStategy= root[F("battery_drain_strategy")].as<uint8_t>();
strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, root[F("mqtt_topic_powermeter_1")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter1)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter1, root[F("mqtt_topic_powermeter_1")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter1));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, root[F("mqtt_topic_powermeter_2")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter2)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, root[F("mqtt_topic_powermeter_2")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter2));
strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, root[F("mqtt_topic_powermeter_3")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter3)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, root[F("mqtt_topic_powermeter_3")].as<String>().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter3));

View File

@ -70,6 +70,7 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
if (inv->Statistics()->getLastUpdate() > 0) { if (inv->Statistics()->getLastUpdate() > 0) {
for (auto& t : inv->Statistics()->getChannelTypes()) { for (auto& t : inv->Statistics()->getChannelTypes()) {
for (auto& c : inv->Statistics()->getChannelsByType(t)) { for (auto& c : inv->Statistics()->getChannelsByType(t)) {
addPanelInfo(stream, serial, i, inv, t, c);
addField(stream, serial, i, inv, t, c, FLD_PAC); addField(stream, serial, i, inv, t, c, FLD_PAC);
addField(stream, serial, i, inv, t, c, FLD_UAC); addField(stream, serial, i, inv, t, c, FLD_UAC);
addField(stream, serial, i, inv, t, c, FLD_IAC); addField(stream, serial, i, inv, t, c, FLD_IAC);
@ -120,3 +121,49 @@ void WebApiPrometheusClass::addField(AsyncResponseStream* stream, String& serial
inv->Statistics()->getChannelFieldValue(type, channel, fieldId)); inv->Statistics()->getChannelFieldValue(type, channel, fieldId));
} }
} }
void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel)
{
if (type != TYPE_DC) {
return;
}
const CONFIG_T& config = Configuration.get();
const bool printHelp = (idx == 0 && channel == 0);
if (printHelp) {
stream->print(F("# HELP opendtu_PanelInfo panel information\n"));
stream->print(F("# TYPE opendtu_PanelInfo gauge\n"));
}
stream->printf("opendtu_PanelInfo{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\",panelname=\"%s\"} 1\n",
serial.c_str(),
idx,
inv->name(),
channel,
config.Inverter[idx].channel[channel].Name
);
if (printHelp) {
stream->print(F("# HELP opendtu_MaxPower panel maximum output power\n"));
stream->print(F("# TYPE opendtu_MaxPower gauge\n"));
}
stream->printf("opendtu_MaxPower{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %d\n",
serial.c_str(),
idx,
inv->name(),
channel,
config.Inverter[idx].channel[channel].MaxChannelPower
);
if (printHelp) {
stream->print(F("# HELP opendtu_YieldTotalOffset panel yield offset (for used inverters)\n"));
stream->print(F("# TYPE opendtu_YieldTotalOffset gauge\n"));
}
stream->printf("opendtu_YieldTotalOffset{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %f\n",
serial.c_str(),
idx,
inv->name(),
channel,
config.Inverter[idx].channel[channel].YieldTotalOffset
);
}

View File

@ -117,10 +117,11 @@ void setup()
pin.display_clk, pin.display_clk,
pin.display_cs, pin.display_cs,
pin.display_reset); pin.display_reset);
Display.showLogo = config.Display_ShowLogo; Display.setOrientation(config.Display_Rotation);
Display.enablePowerSafe = config.Display_PowerSafe; Display.enablePowerSafe = config.Display_PowerSafe;
Display.enableScreensaver = config.Display_ScreenSaver; Display.enableScreensaver = config.Display_ScreenSaver;
Display.contrast = config.Display_Contrast; Display.setContrast(config.Display_Contrast);
Display.setStartupDisplay();
MessageOutput.println(F("done")); MessageOutput.println(F("done"));
// Check for default DTU serial // Check for default DTU serial

View File

@ -13,7 +13,7 @@
"dependencies": { "dependencies": {
"@popperjs/core": "^2.11.6", "@popperjs/core": "^2.11.6",
"bootstrap": "^5.3.0-alpha1", "bootstrap": "^5.3.0-alpha1",
"bootstrap-icons-vue": "^1.8.1", "bootstrap-icons-vue": "^1.10.3",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"spark-md5": "^3.0.2", "spark-md5": "^3.0.2",
"vue": "^3.2.47", "vue": "^3.2.47",
@ -21,23 +21,23 @@
"vue-router": "^4.1.6" "vue-router": "^4.1.6"
}, },
"devDependencies": { "devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.8.2", "@intlify/unplugin-vue-i18n": "^0.9.2",
"@rushstack/eslint-patch": "^1.2.0", "@rushstack/eslint-patch": "^1.2.0",
"@types/bootstrap": "^5.2.6", "@types/bootstrap": "^5.2.6",
"@types/node": "^18.14.6", "@types/node": "^18.15.3",
"@types/spark-md5": "^3.0.2", "@types/spark-md5": "^3.0.2",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.1.0",
"@vue/eslint-config-typescript": "^11.0.2", "@vue/eslint-config-typescript": "^11.0.2",
"@vue/tsconfig": "^0.1.3", "@vue/tsconfig": "^0.1.3",
"eslint": "^8.35.0", "eslint": "^8.36.0",
"eslint-plugin-vue": "^9.9.0", "eslint-plugin-vue": "^9.9.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"sass": "^1.58.3", "sass": "^1.59.3",
"terser": "^5.16.5", "terser": "^5.16.6",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^4.1.4", "vite": "^4.2.0",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-css-injected-by-js": "^3.0.1", "vite-plugin-css-injected-by-js": "^3.1.0",
"vue-tsc": "^1.2.0" "vue-tsc": "^1.2.0"
} }
} }

View File

@ -11,126 +11,21 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <template v-for="(category) in categories">
<td rowspan="6">NRF24</td> <tr v-for="(prop, prop_idx) in properties(category)">
<td>MISO</td> <td v-if="prop_idx == 0" :rowspan="properties(category).length">
<td>{{ selectedPinAssignment?.nrf24?.miso }}</td> {{ capitalizeFirstLetter(category) }}</td>
<td>{{ currentPinAssignment?.nrf24?.miso }}</td> <td :class="{ 'table-danger': !isEqual(category, prop) }">{{ prop }}</td>
</tr> <td>
<tr> <template v-if="((selectedPinAssignment as Device)[category as keyof Device])">
<td>MOSI</td> {{ (selectedPinAssignment as any)[category][prop] }}</template>
<td>{{ selectedPinAssignment?.nrf24?.mosi }}</td> </td>
<td>{{ currentPinAssignment?.nrf24?.mosi }}</td> <td>
</tr> <template v-if="((currentPinAssignment as Device)[category as keyof Device])">
<tr> {{ (currentPinAssignment as any)[category][prop] }}</template>
<td>CLK</td> </td>
<td>{{ selectedPinAssignment?.nrf24?.clk }}</td> </tr>
<td>{{ currentPinAssignment?.nrf24?.clk }}</td> </template>
</tr>
<tr>
<td>IRQ</td>
<td>{{ selectedPinAssignment?.nrf24?.irq }}</td>
<td>{{ currentPinAssignment?.nrf24?.irq }}</td>
</tr>
<tr>
<td>EN</td>
<td>{{ selectedPinAssignment?.nrf24?.en }}</td>
<td>{{ currentPinAssignment?.nrf24?.en }}</td>
</tr>
<tr>
<td>CS</td>
<td>{{ selectedPinAssignment?.nrf24?.cs }}</td>
<td>{{ currentPinAssignment?.nrf24?.cs }}</td>
</tr>
<tr>
<td rowspan="7">Ethernet</td>
<td>enabled</td>
<td>{{ selectedPinAssignment?.eth?.enabled }}</td>
<td>{{ currentPinAssignment?.eth?.enabled }}</td>
</tr>
<tr>
<td>phy_addr</td>
<td>{{ selectedPinAssignment?.eth?.phy_addr }}</td>
<td>{{ currentPinAssignment?.eth?.phy_addr }}</td>
</tr>
<tr>
<td>power</td>
<td>{{ selectedPinAssignment?.eth?.power }}</td>
<td>{{ currentPinAssignment?.eth?.power }}</td>
</tr>
<tr>
<td>mdc</td>
<td>{{ selectedPinAssignment?.eth?.mdc }}</td>
<td>{{ currentPinAssignment?.eth?.mdc }}</td>
</tr>
<tr>
<td>mdio</td>
<td>{{ selectedPinAssignment?.eth?.mdio }}</td>
<td>{{ currentPinAssignment?.eth?.mdio }}</td>
</tr>
<tr>
<td>type</td>
<td>{{ selectedPinAssignment?.eth?.type }}</td>
<td>{{ currentPinAssignment?.eth?.type }}</td>
</tr>
<tr>
<td>clk_mode</td>
<td>{{ selectedPinAssignment?.eth?.clk_mode }}</td>
<td>{{ currentPinAssignment?.eth?.clk_mode }}</td>
</tr>
<tr>
<td rowspan="5">Display</td>
<td>type</td>
<td>{{ selectedPinAssignment?.display?.type }}</td>
<td>{{ currentPinAssignment?.display?.type }}</td>
</tr>
<tr>
<td>data</td>
<td>{{ selectedPinAssignment?.display?.data }}</td>
<td>{{ currentPinAssignment?.display?.data }}</td>
</tr>
<tr>
<td>clk</td>
<td>{{ selectedPinAssignment?.display?.clk }}</td>
<td>{{ currentPinAssignment?.display?.clk }}</td>
</tr>
<tr>
<td>cs</td>
<td>{{ selectedPinAssignment?.display?.cs }}</td>
<td>{{ currentPinAssignment?.display?.cs }}</td>
</tr>
<tr>
<td>reset</td>
<td>{{ selectedPinAssignment?.display?.reset }}</td>
<td>{{ currentPinAssignment?.display?.reset }}</td>
</tr>
<tr>
<td rowspan="2">Victron</td>
<td>RX</td>
<td>{{ selectedPinAssignment?.victron?.rx }}</td>
<td>{{ currentPinAssignment?.victron?.rx }}</td>
</tr>
<tr>
<td>TX</td>
<td>{{ selectedPinAssignment?.victron?.tx }}</td>
<td>{{ currentPinAssignment?.victron?.tx }}</td>
</tr>
<tr>
<td rowspan="2">Battery</td>
<td>RX</td>
<td>{{ selectedPinAssignment?.battery?.rx }}</td>
<td>{{ currentPinAssignment?.battery?.rx }}</td>
</tr>
<tr>
<td>TX</td>
<td>{{ selectedPinAssignment?.battery?.tx }}</td>
<td>{{ currentPinAssignment?.battery?.tx }}</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -150,5 +45,53 @@ export default defineComponent({
selectedPinAssignment: { type: Object as PropType<Device | undefined>, required: true }, selectedPinAssignment: { type: Object as PropType<Device | undefined>, required: true },
currentPinAssignment: { type: Object as PropType<Device | undefined>, required: true }, currentPinAssignment: { type: Object as PropType<Device | undefined>, required: true },
}, },
computed: {
categories(): string[] {
let curArray: Array<string> = [];
if (this.currentPinAssignment) {
curArray = Object.keys(this.currentPinAssignment as Device);
}
let selArray: Array<string> = [];
if (this.selectedPinAssignment) {
selArray = Object.keys(this.selectedPinAssignment as Device);
}
let total: Array<string> = [];
total = total.concat(curArray, selArray);
return Array.from(new Set(total)).filter(cat => cat != 'name').sort();
},
},
methods: {
properties(category: string): string[] {
let curArray: Array<string> = [];
if ((this.currentPinAssignment as Device)[category as keyof Device]) {
curArray = Object.keys((this.currentPinAssignment as Device)[category as keyof Device]);
}
let selArray: Array<string> = [];
if ((this.selectedPinAssignment as Device)[category as keyof Device]) {
selArray = Object.keys((this.selectedPinAssignment as Device)[category as keyof Device]);
}
let total: Array<string> = [];
total = total.concat(curArray, selArray);
return Array.from(new Set(total)).sort();
},
isEqual(category: string, prop: string): boolean {
if (!((this.selectedPinAssignment as Device)[category as keyof Device])) {
return false;
}
if (!((this.currentPinAssignment as Device)[category as keyof Device])) {
return false;
}
return (this.selectedPinAssignment as any)[category][prop] == (this.currentPinAssignment as any)[category][prop];
},
capitalizeFirstLetter(value: string): string {
return value.charAt(0).toUpperCase() + value.slice(1);
},
}
}); });
</script> </script>

View File

@ -459,6 +459,9 @@
"General": "Allgemein", "General": "Allgemein",
"Enable": "Aktiviert", "Enable": "Aktiviert",
"EnableSolarPasstrough": "Aktiviere Solar Pass-trough", "EnableSolarPasstrough": "Aktiviere Solar Pass-trough",
"BatteryDrainStrategy": "Strategie zur Batterieentleerung",
"BatteryDrainWhenFull": "Leeren, wenn voll",
"BatteryDrainAtNight": "Leeren zur Nacht",
"SolarpasstroughInfo": "Diese Einstellung aktiviert die direkte Weitergabe der aktuell vom Laderegler gemeldeten Solarleistung an den Wechselrichter um eine unnötige Speicherung zu vermeiden und die Energieverluste zu minimieren.", "SolarpasstroughInfo": "Diese Einstellung aktiviert die direkte Weitergabe der aktuell vom Laderegler gemeldeten Solarleistung an den Wechselrichter um eine unnötige Speicherung zu vermeiden und die Energieverluste zu minimieren.",
"InverterId": "Wechselrichter ID", "InverterId": "Wechselrichter ID",
"InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.", "InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.",
@ -599,8 +602,12 @@
"PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt", "PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt",
"Screensaver": "Screensaver aktivieren:", "Screensaver": "Screensaver aktivieren:",
"ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)", "ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)",
"ShowLogo": "Logo anzeigen:",
"Contrast": "Kontrast ({contrast}):", "Contrast": "Kontrast ({contrast}):",
"Rotation": "Rotation:",
"rot0": "Keine Rotation",
"rot90": "90 Grad Drehung",
"rot180": "180 Grad Drehung",
"rot270": "270 Grad Drehung",
"Save": "@:dtuadmin.Save" "Save": "@:dtuadmin.Save"
}, },
"pininfo": { "pininfo": {

View File

@ -459,6 +459,9 @@
"General": "General", "General": "General",
"Enable": "Enable", "Enable": "Enable",
"EnableSolarPasstrough": "Enable Solar-Passtrough", "EnableSolarPasstrough": "Enable Solar-Passtrough",
"BatteryDrainStrategy": "Battery drain strategy",
"BatteryDrainWhenFull": "Empty when full",
"BatteryDrainAtNight": "Empty at night",
"SolarpasstroughInfo": "When the sun is shining, this setting enables the sychronization of the inverter limit with the current solar power of the Victron MPPT charger. This optimizes battery degradation and loses.", "SolarpasstroughInfo": "When the sun is shining, this setting enables the sychronization of the inverter limit with the current solar power of the Victron MPPT charger. This optimizes battery degradation and loses.",
"InverterId": "Inverter ID", "InverterId": "Inverter ID",
"InverterIdHint": "Select proper inverter ID where battery is connected to.", "InverterIdHint": "Select proper inverter ID where battery is connected to.",
@ -599,8 +602,12 @@
"PowerSafeHint": "Turn off the display if no inverter is producing.", "PowerSafeHint": "Turn off the display if no inverter is producing.",
"Screensaver": "Enable Screensaver:", "Screensaver": "Enable Screensaver:",
"ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)", "ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)",
"ShowLogo": "Show Logo:",
"Contrast": "Contrast ({contrast}):", "Contrast": "Contrast ({contrast}):",
"Rotation": "Rotation:",
"rot0": "No rotation",
"rot90": "90 degree rotation",
"rot180": "180 degree rotation",
"rot270": "270 degree rotation",
"Save": "@:dtuadmin.Save" "Save": "@:dtuadmin.Save"
}, },
"pininfo": { "pininfo": {

View File

@ -559,8 +559,12 @@
"PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.", "PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.",
"Screensaver": "Activer l'écran de veille", "Screensaver": "Activer l'écran de veille",
"ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)", "ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)",
"ShowLogo": "Afficher le logo",
"Contrast": "Contraste ({contrast}):", "Contrast": "Contraste ({contrast}):",
"Rotation": "Rotation:",
"rot0": "No rotation",
"rot90": "90 degree rotation",
"rot180": "180 degree rotation",
"rot270": "270 degree rotation",
"Save": "@:dtuadmin.Save" "Save": "@:dtuadmin.Save"
}, },
"pininfo": { "pininfo": {

View File

@ -1,7 +1,7 @@
import type { Device } from "./PinMapping"; import type { Device } from "./PinMapping";
export interface Display { export interface Display {
show_logo: boolean; rotation: number;
power_safe: boolean; power_safe: boolean;
screensaver: boolean; screensaver: boolean;
contrast: number; contrast: number;

View File

@ -1,6 +1,7 @@
export interface PowerLimiterConfig { export interface PowerLimiterConfig {
enabled: boolean; enabled: boolean;
solar_passtrough_enabled: boolean; solar_passtrough_enabled: boolean;
battery_drain_strategy: number;
mqtt_topic_powermeter_1: string; mqtt_topic_powermeter_1: string;
mqtt_topic_powermeter_2: string; mqtt_topic_powermeter_2: string;
mqtt_topic_powermeter_3: string; mqtt_topic_powermeter_3: string;

View File

@ -57,8 +57,18 @@
v-model="deviceConfigList.display.screensaver" type="checkbox" v-model="deviceConfigList.display.screensaver" type="checkbox"
:tooltip="$t('deviceadmin.ScreensaverHint')" /> :tooltip="$t('deviceadmin.ScreensaverHint')" />
<InputElement :label="$t('deviceadmin.ShowLogo')" <div class="row mb-3">
v-model="deviceConfigList.display.show_logo" type="checkbox" /> <label class="col-sm-2 col-form-label">
{{ $t('deviceadmin.Rotation') }}
</label>
<div class="col-sm-10">
<select class="form-select" v-model="deviceConfigList.display.rotation">
<option v-for="rotation in displayRotationList" :key="rotation.key" :value="rotation.key">
{{ rotation.value }}
</option>
</select>
</div>
</div>
<div class="row mb-3"> <div class="row mb-3">
<label for="inputDisplayContrast" class="col-sm-2 col-form-label">{{ <label for="inputDisplayContrast" class="col-sm-2 col-form-label">{{
@ -108,6 +118,12 @@ export default defineComponent({
alertMessage: "", alertMessage: "",
alertType: "info", alertType: "info",
showAlert: false, showAlert: false,
displayRotationList: [
{ key: 0, value: this.$t('deviceadmin.rot0') },
{ key: 1, value: this.$t('deviceadmin.rot90') },
{ key: 2, value: this.$t('deviceadmin.rot180') },
{ key: 3, value: this.$t('deviceadmin.rot270') },
],
} }
}, },
created() { created() {

View File

@ -29,13 +29,13 @@
</CardElement> </CardElement>
<CardElement :text="$t('ntpadmin.LocationConfiguration')" textVariant="text-bg-primary" add-space> <CardElement :text="$t('ntpadmin.LocationConfiguration')" textVariant="text-bg-primary" add-space>
<InputElement :label="$t('ntpadmin.Longitude')"
v-model="ntpConfigList.longitude"
type="number" min="-180" max="180" step="any"/>
<InputElement :label="$t('ntpadmin.Latitude')" <InputElement :label="$t('ntpadmin.Latitude')"
v-model="ntpConfigList.latitude" v-model="ntpConfigList.latitude"
type="number" min="-90" max="90" step="any"/> type="number" min="-90" max="90" step="any"/>
<InputElement :label="$t('ntpadmin.Longitude')"
v-model="ntpConfigList.longitude"
type="number" min="-180" max="180" step="any"/>
</CardElement> </CardElement>
<button type="submit" class="btn btn-primary mb-3">{{ $t('ntpadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('ntpadmin.Save') }}</button>
</form> </form>

View File

@ -15,6 +15,19 @@
v-model="powerLimiterConfigList.solar_passtrough_enabled" v-model="powerLimiterConfigList.solar_passtrough_enabled"
type="checkbox" wide/> type="checkbox" wide/>
<div class="row mb-3" v-show="powerLimiterConfigList.enabled && powerLimiterConfigList.solar_passtrough_enabled">
<label for="inputTimezone" class="col-sm-2 col-form-label">
{{ $t('powerlimiteradmin.BatteryDrainStrategy') }}:
</label>
<div class="col-sm-10">
<select class="form-select" v-model="powerLimiterConfigList.battery_drain_strategy">
<option v-for="batteryDrainStrategy in batteryDrainStrategyList" :key="batteryDrainStrategy.key" :value="batteryDrainStrategy.key">
{{ $t(batteryDrainStrategy.value) }}
</option>
</select>
</div>
</div>
<div class="alert alert-secondary" v-show="powerLimiterConfigList.enabled" role="alert" v-html="$t('powerlimiteradmin.SolarpasstroughInfo')"></div> <div class="alert alert-secondary" v-show="powerLimiterConfigList.enabled" role="alert" v-html="$t('powerlimiteradmin.SolarpasstroughInfo')"></div>
<div class="row mb-3" v-show="powerLimiterConfigList.enabled"> <div class="row mb-3" v-show="powerLimiterConfigList.enabled">
@ -256,6 +269,10 @@ export default defineComponent({
{ key: 2, value: "CH 2" }, { key: 2, value: "CH 2" },
{ key: 3, value: "CH 3" }, { key: 3, value: "CH 3" },
], ],
batteryDrainStrategyList: [
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
],
alertMessage: "", alertMessage: "",
alertType: "info", alertType: "info",
showAlert: false, showAlert: false,

View File

@ -17,7 +17,7 @@ export default defineConfig({
cssInjectedByJsPlugin(), cssInjectedByJsPlugin(),
VueI18nPlugin({ VueI18nPlugin({
/* options */ /* options */
include: path.resolve(path.dirname(fileURLToPath(import.meta.url)), './src/locales/**'), include: path.resolve(path.dirname(fileURLToPath(import.meta.url)), './src/locales/**.json'),
fullInstall: false, fullInstall: false,
forceStringify: true, forceStringify: true,
}), }),

View File

@ -7,124 +7,136 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9"
integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==
"@esbuild/android-arm64@0.16.17": "@esbuild/android-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz#15a8e2b407d03989b899e325151dc2e96d19c620"
integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg== integrity sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==
"@esbuild/android-arm@0.16.17": "@esbuild/android-arm@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.12.tgz#677a09297e1f4f37aba7b4fc4f31088b00484985"
integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw== integrity sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==
"@esbuild/android-x64@0.16.17": "@esbuild/android-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.12.tgz#b292729eef4e0060ae1941f6a021c4d2542a3521"
integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ== integrity sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==
"@esbuild/darwin-arm64@0.16.17": "@esbuild/darwin-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz#efa35318df931da05825894e1787b976d55adbe3"
integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w== integrity sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==
"@esbuild/darwin-x64@0.16.17": "@esbuild/darwin-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz#e7b54bb3f6dc81aadfd0485cd1623c648157e64d"
integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg== integrity sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==
"@esbuild/freebsd-arm64@0.16.17": "@esbuild/freebsd-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz#99a18a8579d6299c449566fe91d9b6a54cf2a591"
integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw== integrity sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==
"@esbuild/freebsd-x64@0.16.17": "@esbuild/freebsd-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz#0e090190fede307fb4022f671791a50dd5121abd"
integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug== integrity sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==
"@esbuild/linux-arm64@0.16.17": "@esbuild/linux-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz#7fe2a69f8a1a7153fa2b0f44aabcadb59475c7e0"
integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g== integrity sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==
"@esbuild/linux-arm@0.16.17": "@esbuild/linux-arm@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz#b87c76ebf1fe03e01fd6bb5cfc2f3c5becd5ee93"
integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ== integrity sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==
"@esbuild/linux-ia32@0.16.17": "@esbuild/linux-ia32@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz#9e9357090254524d32e6708883a47328f3037858"
integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg== integrity sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==
"@esbuild/linux-loong64@0.16.17": "@esbuild/linux-loong64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz#9deb605f9e2c82f59412ddfefb4b6b96d54b5b5b"
integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ== integrity sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==
"@esbuild/linux-mips64el@0.16.17": "@esbuild/linux-mips64el@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz#6ef170b974ddf5e6acdfa5b05f22b6e9dfd2b003"
integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw== integrity sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==
"@esbuild/linux-ppc64@0.16.17": "@esbuild/linux-ppc64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz#1638d3d4acf1d34aaf37cf8908c2e1cefed16204"
integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g== integrity sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==
"@esbuild/linux-riscv64@0.16.17": "@esbuild/linux-riscv64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz#135b6e9270a8e2de2b9094bb21a287517df520ef"
integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw== integrity sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==
"@esbuild/linux-s390x@0.16.17": "@esbuild/linux-s390x@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz#21e40830770c5d08368e300842bde382ce97d615"
integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w== integrity sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==
"@esbuild/linux-x64@0.16.17": "@esbuild/linux-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz#76c1c199871d48e1aaa47a762fb9e0dca52e1f7a"
integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw== integrity sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==
"@esbuild/netbsd-x64@0.16.17": "@esbuild/netbsd-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz#c7c3b3017a4b938c76c35f66af529baf62eac527"
integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA== integrity sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==
"@esbuild/openbsd-x64@0.16.17": "@esbuild/openbsd-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz#05d04217d980e049001afdbeacbb58d31bb5cefb"
integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg== integrity sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==
"@esbuild/sunos-x64@0.16.17": "@esbuild/sunos-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz#cf3862521600e4eb6c440ec3bad31ed40fb87ef3"
integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw== integrity sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==
"@esbuild/win32-arm64@0.16.17": "@esbuild/win32-arm64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz#43dd7fb5be77bf12a1550355ab2b123efd60868e"
integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw== integrity sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==
"@esbuild/win32-ia32@0.16.17": "@esbuild/win32-ia32@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz#9940963d0bff4ea3035a84e2b4c6e41c5e6296eb"
integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig== integrity sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==
"@esbuild/win32-x64@0.16.17": "@esbuild/win32-x64@0.17.12":
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz#3a11d13e9a5b0c05db88991b234d8baba1f96487"
integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q== integrity sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==
"@eslint/eslintrc@^2.0.0": "@eslint-community/eslint-utils@^4.2.0":
version "2.0.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz#a831e6e468b4b2b5ae42bf658bea015bf10bc518"
integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A== integrity sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403"
integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==
"@eslint/eslintrc@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d"
integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==
dependencies: dependencies:
ajv "^6.12.4" ajv "^6.12.4"
debug "^4.3.2" debug "^4.3.2"
espree "^9.4.0" espree "^9.5.0"
globals "^13.19.0" globals "^13.19.0"
ignore "^5.2.0" ignore "^5.2.0"
import-fresh "^3.2.1" import-fresh "^3.2.1"
@ -132,10 +144,10 @@
minimatch "^3.1.2" minimatch "^3.1.2"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@eslint/js@8.35.0": "@eslint/js@8.36.0":
version "8.35.0" version "8.36.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe"
integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==
"@humanwhocodes/config-array@^0.11.8": "@humanwhocodes/config-array@^0.11.8":
version "0.11.8" version "0.11.8"
@ -156,13 +168,15 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@intlify/bundle-utils@^4.0.0": "@intlify/bundle-utils@^5.1.2":
version "4.0.0" version "5.2.0"
resolved "https://registry.yarnpkg.com/@intlify/bundle-utils/-/bundle-utils-4.0.0.tgz#29c1d602c7e4e33b516581496a7c6740ed7e2585" resolved "https://registry.yarnpkg.com/@intlify/bundle-utils/-/bundle-utils-5.2.0.tgz#9dc11138d232d7cfb1163feb850f653ce4dfedaf"
integrity sha512-klXrYT9VXyKEXsD6UY3pShg0O5MPC07n0TZ5RrSs5ry6T1eZVolIFGJi9c3qcDrh1qjJxgikRnPBmD7qGDqbjw== integrity sha512-rIfoNUTBoZK6IfaEeuoYMQZSuAXhPyZoy+UsdZj+V4eM632ynN1bGt5ttkpGO8xe0c+esfYslgJxBz//bdu4qg==
dependencies: dependencies:
"@intlify/message-compiler" next "@intlify/message-compiler" next
"@intlify/shared" next "@intlify/shared" next
acorn "^8.8.2"
estree-walker "^2.0.2"
jsonc-eslint-parser "^1.0.1" jsonc-eslint-parser "^1.0.1"
source-map "0.6.1" source-map "0.6.1"
yaml-eslint-parser "^0.3.2" yaml-eslint-parser "^0.3.2"
@ -210,23 +224,23 @@
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.16.tgz#74f254dbb7eac633b86d690a341349db29573896" resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.16.tgz#74f254dbb7eac633b86d690a341349db29573896"
integrity sha512-kXbm4svALe3lX+EjdJxfnabOphqS4yQ1Ge/iIlR8tvUiYRCoNz3hig1M4336iY++Dfx5ytEQJPNjIcknNIuvig== integrity sha512-kXbm4svALe3lX+EjdJxfnabOphqS4yQ1Ge/iIlR8tvUiYRCoNz3hig1M4336iY++Dfx5ytEQJPNjIcknNIuvig==
"@intlify/unplugin-vue-i18n@^0.8.2": "@intlify/unplugin-vue-i18n@^0.9.2":
version "0.8.2" version "0.9.2"
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.8.2.tgz#4196cb5bee4243bb3a33af76ce9663f3e106809a" resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.9.2.tgz#7d9166a1a84343da6632c80815150487ac7f533f"
integrity sha512-cRnzPqSEZQOmTD+p4pwc3RTS9HxreLqfID0keoqZDZweCy/CGRMLLTNd15S4TUf1vSBhPF03DItEFDr1F+8MDA== integrity sha512-cNfa90+NVNdYJ0qqwRaEb2kGGp9zAve2xaAKCL7EzcQcvSWw42mhiOxcNkUc1QKlXnSHERMd6aT4/GUlFT1zBw==
dependencies: dependencies:
"@intlify/bundle-utils" "^4.0.0" "@intlify/bundle-utils" "^5.1.2"
"@intlify/shared" next "@intlify/shared" next
"@rollup/pluginutils" "^4.2.0" "@rollup/pluginutils" "^5.0.2"
"@vue/compiler-sfc" "^3.2.45" "@vue/compiler-sfc" "^3.2.47"
debug "^4.3.1" debug "^4.3.3"
fast-glob "^3.2.5" fast-glob "^3.2.12"
js-yaml "^4.1.0" js-yaml "^4.1.0"
json5 "^2.2.0" json5 "^2.2.3"
pathe "^1.0.0" pathe "^1.0.0"
picocolors "^1.0.0" picocolors "^1.0.0"
source-map "0.6.1" source-map "0.6.1"
unplugin "^1.0.0" unplugin "^1.1.0"
"@intlify/vue-devtools@9.2.2": "@intlify/vue-devtools@9.2.2":
version "9.2.2" version "9.2.2"
@ -307,13 +321,14 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
"@rollup/pluginutils@^4.2.0": "@rollup/pluginutils@^5.0.2":
version "4.2.1" version "5.0.2"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ== integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
dependencies: dependencies:
estree-walker "^2.0.1" "@types/estree" "^1.0.0"
picomatch "^2.2.2" estree-walker "^2.0.2"
picomatch "^2.3.1"
"@rushstack/eslint-patch@^1.2.0": "@rushstack/eslint-patch@^1.2.0":
version "1.2.0" version "1.2.0"
@ -327,15 +342,20 @@
dependencies: dependencies:
"@popperjs/core" "^2.9.2" "@popperjs/core" "^2.9.2"
"@types/estree@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
"@types/json-schema@^7.0.9": "@types/json-schema@^7.0.9":
version "7.0.11" version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
"@types/node@^18.14.6": "@types/node@^18.15.3":
version "18.14.6" version "18.15.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014"
integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA== integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==
"@types/spark-md5@^3.0.2": "@types/spark-md5@^3.0.2":
version "3.0.2" version "3.0.2"
@ -456,10 +476,10 @@
"@typescript-eslint/types" "5.32.0" "@typescript-eslint/types" "5.32.0"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
"@vitejs/plugin-vue@^4.0.0": "@vitejs/plugin-vue@^4.1.0":
version "4.0.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz#93815beffd23db46288c787352a8ea31a0c03e5e" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-4.1.0.tgz#b6a9d83cd91575f7ee15593f6444397f68751073"
integrity sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA== integrity sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==
"@volar/language-core@1.3.0-alpha.0": "@volar/language-core@1.3.0-alpha.0":
version "1.3.0-alpha.0" version "1.3.0-alpha.0"
@ -523,7 +543,7 @@
"@vue/compiler-core" "3.2.47" "@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47" "@vue/shared" "3.2.47"
"@vue/compiler-sfc@3.2.47", "@vue/compiler-sfc@^3.2.45", "@vue/compiler-sfc@^3.2.47": "@vue/compiler-sfc@3.2.47", "@vue/compiler-sfc@^3.2.47":
version "3.2.47" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ== integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
@ -696,10 +716,10 @@ boolbase@^1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
bootstrap-icons-vue@^1.8.1: bootstrap-icons-vue@^1.10.3:
version "1.8.1" version "1.10.3"
resolved "https://registry.yarnpkg.com/bootstrap-icons-vue/-/bootstrap-icons-vue-1.8.1.tgz#ce4a0c1f6efe41dabcc1341f2cb191d307fbaf50" resolved "https://registry.yarnpkg.com/bootstrap-icons-vue/-/bootstrap-icons-vue-1.10.3.tgz#ae725513c9655ce86effa2a0b09e9e65b02c8f1a"
integrity sha512-uItRULwQz0epETi9x/RBEqfjHmTAmkIIczpH1R6L9T6yyaaijk0826PzTWnWNm15tw66JT/8GNuXjB0HI5PHLw== integrity sha512-BzqmLufgHjFvSReJ1GQqNkl780UFK0rWT4Y1IQC7lZClXyOSsM5Ipw04BnuVmmrqgtSxzak83jcBwLJgCK3scg==
bootstrap@^5.3.0-alpha1: bootstrap@^5.3.0-alpha1:
version "5.3.0-alpha1" version "5.3.0-alpha1"
@ -847,7 +867,7 @@ de-indent@^1.0.2:
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -927,33 +947,33 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1" is-date-object "^1.0.1"
is-symbol "^1.0.2" is-symbol "^1.0.2"
esbuild@^0.16.14: esbuild@^0.17.5:
version "0.16.17" version "0.17.12"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.12.tgz#2ad7523bf1bc01881e9d904bc04e693bd3bdcf2f"
integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg== integrity sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==
optionalDependencies: optionalDependencies:
"@esbuild/android-arm" "0.16.17" "@esbuild/android-arm" "0.17.12"
"@esbuild/android-arm64" "0.16.17" "@esbuild/android-arm64" "0.17.12"
"@esbuild/android-x64" "0.16.17" "@esbuild/android-x64" "0.17.12"
"@esbuild/darwin-arm64" "0.16.17" "@esbuild/darwin-arm64" "0.17.12"
"@esbuild/darwin-x64" "0.16.17" "@esbuild/darwin-x64" "0.17.12"
"@esbuild/freebsd-arm64" "0.16.17" "@esbuild/freebsd-arm64" "0.17.12"
"@esbuild/freebsd-x64" "0.16.17" "@esbuild/freebsd-x64" "0.17.12"
"@esbuild/linux-arm" "0.16.17" "@esbuild/linux-arm" "0.17.12"
"@esbuild/linux-arm64" "0.16.17" "@esbuild/linux-arm64" "0.17.12"
"@esbuild/linux-ia32" "0.16.17" "@esbuild/linux-ia32" "0.17.12"
"@esbuild/linux-loong64" "0.16.17" "@esbuild/linux-loong64" "0.17.12"
"@esbuild/linux-mips64el" "0.16.17" "@esbuild/linux-mips64el" "0.17.12"
"@esbuild/linux-ppc64" "0.16.17" "@esbuild/linux-ppc64" "0.17.12"
"@esbuild/linux-riscv64" "0.16.17" "@esbuild/linux-riscv64" "0.17.12"
"@esbuild/linux-s390x" "0.16.17" "@esbuild/linux-s390x" "0.17.12"
"@esbuild/linux-x64" "0.16.17" "@esbuild/linux-x64" "0.17.12"
"@esbuild/netbsd-x64" "0.16.17" "@esbuild/netbsd-x64" "0.17.12"
"@esbuild/openbsd-x64" "0.16.17" "@esbuild/openbsd-x64" "0.17.12"
"@esbuild/sunos-x64" "0.16.17" "@esbuild/sunos-x64" "0.17.12"
"@esbuild/win32-arm64" "0.16.17" "@esbuild/win32-arm64" "0.17.12"
"@esbuild/win32-ia32" "0.16.17" "@esbuild/win32-ia32" "0.17.12"
"@esbuild/win32-x64" "0.16.17" "@esbuild/win32-x64" "0.17.12"
escape-string-regexp@^1.0.5: escape-string-regexp@^1.0.5:
version "1.0.5" version "1.0.5"
@ -1023,13 +1043,15 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@^8.35.0: eslint@^8.36.0:
version "8.35.0" version "8.36.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf"
integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==
dependencies: dependencies:
"@eslint/eslintrc" "^2.0.0" "@eslint-community/eslint-utils" "^4.2.0"
"@eslint/js" "8.35.0" "@eslint-community/regexpp" "^4.4.0"
"@eslint/eslintrc" "^2.0.1"
"@eslint/js" "8.36.0"
"@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/config-array" "^0.11.8"
"@humanwhocodes/module-importer" "^1.0.1" "@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8" "@nodelib/fs.walk" "^1.2.8"
@ -1040,9 +1062,8 @@ eslint@^8.35.0:
doctrine "^3.0.0" doctrine "^3.0.0"
escape-string-regexp "^4.0.0" escape-string-regexp "^4.0.0"
eslint-scope "^7.1.1" eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
espree "^9.4.0" espree "^9.5.0"
esquery "^1.4.2" esquery "^1.4.2"
esutils "^2.0.2" esutils "^2.0.2"
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
@ -1064,7 +1085,6 @@ eslint@^8.35.0:
minimatch "^3.1.2" minimatch "^3.1.2"
natural-compare "^1.4.0" natural-compare "^1.4.0"
optionator "^0.9.1" optionator "^0.9.1"
regexpp "^3.2.0"
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
strip-json-comments "^3.1.0" strip-json-comments "^3.1.0"
text-table "^0.2.0" text-table "^0.2.0"
@ -1087,10 +1107,10 @@ espree@^9.3.1:
acorn-jsx "^5.3.2" acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
espree@^9.4.0: espree@^9.5.0:
version "9.4.0" version "9.5.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113"
integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==
dependencies: dependencies:
acorn "^8.8.0" acorn "^8.8.0"
acorn-jsx "^5.3.2" acorn-jsx "^5.3.2"
@ -1127,7 +1147,7 @@ estraverse@^5.1.0, estraverse@^5.2.0:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
estree-walker@^2.0.1, estree-walker@^2.0.2: estree-walker@^2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
@ -1142,7 +1162,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^3.2.5: fast-glob@^3.2.12:
version "3.2.12" version "3.2.12"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
@ -1576,7 +1596,7 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json5@^2.2.0: json5@^2.2.3:
version "2.2.3" version "2.2.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
@ -1864,7 +1884,7 @@ picocolors@^1.0.0:
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
@ -1976,10 +1996,10 @@ rimraf@^3.0.2:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rollup@^3.10.0: rollup@^3.18.0:
version "3.14.0" version "3.19.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.14.0.tgz#f5925255f3b6e8de1dba3916d7619c7da5708d95" resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.19.1.tgz#2b3a31ac1ff9f3afab2e523fa687fef5b0ee20fc"
integrity sha512-o23sdgCLcLSe3zIplT9nQ1+r97okuaiR+vmAPZPTDYB7/f3tgWIYNyiQveMsZwshBT0is4eGax/HH83Q7CG+/Q== integrity sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
@ -1999,10 +2019,10 @@ safe-regex-test@^1.0.0:
get-intrinsic "^1.1.3" get-intrinsic "^1.1.3"
is-regex "^1.1.4" is-regex "^1.1.4"
sass@^1.58.3: sass@^1.59.3:
version "1.58.3" version "1.59.3"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.58.3.tgz#2348cc052061ba4f00243a208b09c40e031f270d" resolved "https://registry.yarnpkg.com/sass/-/sass-1.59.3.tgz#a1ddf855d75c70c26b4555df4403e1bbf8e4403f"
integrity sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A== integrity sha512-QCq98N3hX1jfTCoUAsF3eyGuXLsY7BCnCEg9qAact94Yc21npG2/mVOqoDvE0fCbWDqiM4WlcJQla0gWG2YlxQ==
dependencies: dependencies:
chokidar ">=3.0.0 <4.0.0" chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0" immutable "^4.0.0"
@ -2185,10 +2205,10 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
terser@^5.16.5: terser@^5.16.6:
version "5.16.5" version "5.16.6"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a" resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.6.tgz#f6c7a14a378ee0630fbe3ac8d1f41b4681109533"
integrity sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg== integrity sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==
dependencies: dependencies:
"@jridgewell/source-map" "^0.3.2" "@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0" acorn "^8.5.0"
@ -2251,10 +2271,10 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
unplugin@^1.0.0: unplugin@^1.1.0:
version "1.1.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.1.0.tgz#96a14aa52d7637a56a88dec6baf4a73902f2db87" resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.3.0.tgz#e092fc4010196435558b524e6609253085a80b6c"
integrity sha512-I8obQ8Rs/hnkxokRV6g8JKOQFgYNnTd9DL58vcSt5IJ9AkK8wbrtsnzD5hi4BJlvcY536JzfEXj9L6h7j559/A== integrity sha512-l4Udjxg2+vCuKRgIA2T8fHd7UwKWaLizh7t+3C72zjnN0+ZS+odzATFenymOUgcGqG1dkCSYE34h9wBbMXrKrA==
dependencies: dependencies:
acorn "^8.8.2" acorn "^8.8.2"
chokidar "^3.5.3" chokidar "^3.5.3"
@ -2290,20 +2310,20 @@ vite-plugin-compression@^0.5.1:
debug "^4.3.3" debug "^4.3.3"
fs-extra "^10.0.0" fs-extra "^10.0.0"
vite-plugin-css-injected-by-js@^3.0.1: vite-plugin-css-injected-by-js@^3.1.0:
version "3.0.1" version "3.1.0"
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.0.1.tgz#59a32449b53666c2cee2b74fa4867897fa817bd0" resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.1.0.tgz#d1160c975d40f256692e2465832e6ff18c22b3a3"
integrity sha512-M4Pv/eJnzEk13T06g79ho/qZXnkonkNs16hQZsK/zik4m1BQAVsHFHBvls0BVW8MVrPl8tvf/jWCZLoX6Khgnw== integrity sha512-qogCmpocZfcbSAYZQjS88ieIY0PzLUm7RkLFWFgAxkXdz3N6roZbSTNTxeIOj5IxFbZWACUPuVBBoo6qCuXDcw==
vite@^4.1.4: vite@^4.2.0:
version "4.1.4" version "4.2.0"
resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" resolved "https://registry.yarnpkg.com/vite/-/vite-4.2.0.tgz#d4e6eafbc034f3faf0ab376bd5b76ac15775eb99"
integrity sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg== integrity sha512-AbDTyzzwuKoRtMIRLGNxhLRuv1FpRgdIw+1y6AQG73Q5+vtecmvzKo/yk8X/vrHDpETRTx01ABijqUHIzBXi0g==
dependencies: dependencies:
esbuild "^0.16.14" esbuild "^0.17.5"
postcss "^8.4.21" postcss "^8.4.21"
resolve "^1.22.1" resolve "^1.22.1"
rollup "^3.10.0" rollup "^3.18.0"
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"