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)
[![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
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.
@ -235,6 +239,7 @@ Firmware version seems to play not a significant role and cannot be read from th
## Breaking changes
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!
* d4c838a 2023-02-06 BREAKING CHANGE: Prometheus API!
* 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_SolarPassTroughEnabled;
uint8_t PowerLimiter_BatteryDrainStategy;
uint32_t PowerLimiter_Interval;
char PowerLimiter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];
@ -108,10 +109,10 @@ struct CONFIG_T {
bool PowerLimiter_IsInverterBehindPowerMeter;
uint8_t PowerLimiter_InverterId;
uint8_t PowerLimiter_InverterChannelId;
uint32_t PowerLimiter_TargetPowerConsumption;
uint32_t PowerLimiter_TargetPowerConsumptionHysteresis;
uint32_t PowerLimiter_LowerPowerLimit;
uint32_t PowerLimiter_UpperPowerLimit;
int32_t PowerLimiter_TargetPowerConsumption;
int32_t PowerLimiter_TargetPowerConsumptionHysteresis;
int32_t PowerLimiter_LowerPowerLimit;
int32_t PowerLimiter_UpperPowerLimit;
uint32_t PowerLimiter_BatterySocStartThreshold;
uint32_t PowerLimiter_BatterySocStopThreshold;
float PowerLimiter_VoltageStartThreshold;
@ -128,7 +129,7 @@ struct CONFIG_T {
bool Display_PowerSafe;
bool Display_ScreenSaver;
bool Display_ShowLogo;
uint8_t Display_Rotation;
uint8_t Display_Contrast;
};

View File

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

View File

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

View File

@ -14,20 +14,25 @@ typedef enum {
STATE_NORMAL_OPERATION
} plStates;
typedef enum {
EMPTY_WHEN_FULL= 0,
EMPTY_AT_NIGTH
} batDrainStrategy;
class PowerLimiterClass {
public:
void init();
void loop();
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);
private:
uint32_t _lastCommandSent;
uint32_t _lastLoop;
uint32_t _lastPowerMeterUpdate;
uint16_t _lastRequestedPowerLimit;
int32_t _lastRequestedPowerLimit;
plStates _plState = STATE_DISCOVER;
float _powerMeter1Power;
@ -36,8 +41,8 @@ private:
bool canUseDirectSolarPower();
int32_t calcPowerLimit(std::shared_ptr<InverterAbstract> inverter, bool consumeSolarPowerOnly);
void setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, uint32_t newPowerLimit);
uint16_t getDirectSolarPower();
void setNewPowerLimit(std::shared_ptr<InverterAbstract> inverter, int32_t newPowerLimit);
int32_t getDirectSolarPower();
float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter);
bool isStartThresholdReached(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 addPanelInfo(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel);
AsyncWebServer* _server;
enum {

View File

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

View File

@ -33,16 +33,16 @@ typedef struct {
uint8_t ERR; // error code
uint32_t OR; // off reason
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 I; // battery current in A
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 H20; // yield today kWh
uint16_t H21; // maximum power today W
int32_t H21; // maximum power today W
double H22; // yield yesterday kWh
uint16_t H23; // maximum power yesterday W
int32_t H23; // maximum power yesterday W
} veStruct;
class VeDirectFrameHandler {

View File

@ -1,6 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x180000,
app1, app, ota_1, 0x190000,0x180000,
spiffs, data, spiffs, ,0x50000
app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x1F0000, 0x1E0000,
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 =
https://github.com/yubox-node-org/ESPAsyncWebServer
bblanchon/ArduinoJson @ ^6.20.1
https://github.com/bertmelis/espMqttClient.git#v1.3.3
bblanchon/ArduinoJson @ ^6.21.0
https://github.com/bertmelis/espMqttClient.git#v1.4.1
nrf24/RF24 @ ^1.4.5
olikraus/U8g2 @ ^2.34.13
buelowp/sunset @ ^1.1.7

View File

@ -88,7 +88,7 @@ bool ConfigurationClass::write()
JsonObject display = device.createNestedObject("display");
display["powersafe"] = config.Display_PowerSafe;
display["screensaver"] = config.Display_ScreenSaver;
display["showlogo"] = config.Display_ShowLogo;
display["rotation"] = config.Display_Rotation;
display["contrast"] = config.Display_Contrast;
JsonArray inverters = doc.createNestedArray("inverters");
@ -118,6 +118,7 @@ bool ConfigurationClass::write()
JsonObject powerlimiter = doc.createNestedObject("powerlimiter");
powerlimiter["enabled"] = config.PowerLimiter_Enabled;
powerlimiter["solar_passtrough_enabled"] = config.PowerLimiter_SolarPassTroughEnabled;
powerlimiter["battery_drain_strategy"] = config.PowerLimiter_BatteryDrainStategy;
powerlimiter["interval"] = config.PowerLimiter_Interval;
powerlimiter["mqtt_topic_powermeter_1"] = config.PowerLimiter_MqttTopicPowerMeter1;
powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2;
@ -256,7 +257,7 @@ bool ConfigurationClass::read()
JsonObject display = device["display"];
config.Display_PowerSafe = display["powersafe"] | DISPLAY_POWERSAFE;
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;
JsonArray inverters = doc["inverters"];
@ -286,6 +287,7 @@ bool ConfigurationClass::read()
JsonObject powerlimiter = doc["powerlimiter"];
config.PowerLimiter_Enabled = powerlimiter["enabled"] | POWERLIMITER_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;
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));

View File

@ -5,31 +5,6 @@
#include <map>
#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 = {
{ 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); } },
@ -52,56 +27,83 @@ void DisplayGraphicClass::init(DisplayType_t type, uint8_t data, uint8_t clk, ui
auto constructor = display_types[_display_type];
_display = constructor(reset, clk, data, cs);
_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)
{
// get the width and height of the display
uint16_t maxWidth = _display->getWidth();
uint16_t maxHeight = _display->getHeight();
uint8_t dispX;
if (!_isLarge) {
dispX = (line == 0) ? 5 : 0;
} else {
dispX = (line == 0) ? 20 : 5;
}
setFont(line);
// pxMovement +x (0 - 6 px)
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
dispX += enableScreensaver ? (_mExtra % 7) : 0;
_display->drawStr(dispX, _lineOffsets[line], text);
}
// set the font size based on the display size
switch (line) {
void DisplayGraphicClass::setOrientation(uint8_t rotation)
{
if (_display_type == DisplayType_t::None) {
return;
}
switch (rotation) {
case 0:
_display->setDisplayRotation(U8G2_R0);
break;
case 1:
if (maxWidth > 120 && maxHeight > 60) {
_display->setFont(u8g2_font_ncenB14_tr); // large display
} else {
_display->setFont(u8g2_font_logisoso16_tr); // small display
}
_display->setDisplayRotation(U8G2_R1);
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
}
case 2:
_display->setDisplayRotation(U8G2_R2);
break;
default:
if (maxWidth > 120 && maxHeight > 60) {
_display->setFont(u8g2_font_ncenB10_tr); // large display
} else {
_display->setFont(u8g2_font_5x8_tr); // small display
}
case 3:
_display->setDisplayRotation(U8G2_R3);
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 {
dispX = 5 + ex;
_isLarge = (_display->getWidth() > 100);
calcLineHeights();
}
// draw the Text, on the calculated pos
_display->drawStr(dispX, _dispY, text);
void DisplayGraphicClass::setStartupDisplay()
{
if (_display_type == DisplayType_t::None) {
return;
}
_display->clearBuffer();
printText("OpenDTU!", 0);
_display->sendBuffer();
}
void DisplayGraphicClass::loop()
@ -136,20 +138,6 @@ void DisplayGraphicClass::loop()
_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 ==========
if ((totalPower > 0) && (isprod > 0)) {
_display->setPowerSave(false);
@ -158,14 +146,14 @@ void DisplayGraphicClass::loop()
} else {
snprintf(_fmtText, sizeof(_fmtText), "%3.0f W", totalPower);
}
printText(_fmtText, 1);
printText(_fmtText, 0);
_previousMillis = millis();
}
//<=======================
//=====> Offline ===========
else {
printText("offline", 1);
printText("offline", 0);
// check if it's time to enter power saving mode
if (millis() - _previousMillis >= (_interval * 2)) {
_display->setPowerSave(enablePowerSafe);
@ -175,27 +163,34 @@ void DisplayGraphicClass::loop()
//=====> Today & Total Production =======
snprintf(_fmtText, sizeof(_fmtText), "today: %4.0f Wh", totalYieldDay);
printText(_fmtText, 2);
printText(_fmtText, 1);
snprintf(_fmtText, sizeof(_fmtText), "total: %.1f kWh", totalYieldTotal);
printText(_fmtText, 3);
printText(_fmtText, 2);
//<=======================
//=====> IP or Date-Time ========
if (!(_mExtra % 10) && NetworkSettings.localIP()) {
printText(NetworkSettings.localIP().toString().c_str(), 4);
printText(NetworkSettings.localIP().toString().c_str(), 3);
} else {
// Get current time
time_t now = time(nullptr);
strftime(_fmtText, sizeof(_fmtText), "%a %d.%m.%Y %H:%M", localtime(&now));
printText(_fmtText, 4);
printText(_fmtText, 3);
}
_display->sendBuffer();
_dispY = 0;
_mExtra++;
_lastDisplayUpdate = millis();
}
}
void DisplayGraphicClass::setContrast(uint8_t contrast)
{
if (_display_type == DisplayType_t::None) {
return;
}
_display->setContrast(contrast * 2.55f);
}
DisplayGraphicClass Display;

View File

@ -126,7 +126,9 @@ void MqttHandleInverterClass::publishField(std::shared_ptr<InverterAbstract> inv
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)

View File

@ -117,13 +117,7 @@ void PowerLimiterClass::loop()
if (inverter->isProducing()) {
MessageOutput.printf("[PowerLimiterClass::loop] DC voltage: %.2f Corrected DC voltage: %.2f...\r\n",
dcVoltage, correctedDcVoltage);
MessageOutput.println("[PowerLimiterClass::loop] Stopping inverter...");
inverter->sendPowerControlRequest(Hoymiles.getRadio(), false);
uint16_t newPowerLimit = (uint16_t)config.PowerLimiter_LowerPowerLimit;
inverter->sendActivePowerControlRequest(Hoymiles.getRadio(), newPowerLimit, PowerLimitControlType::AbsolutNonPersistent);
_lastRequestedPowerLimit = newPowerLimit;
_lastCommandSent = millis();
setNewPowerLimit(inverter, -1);
return;
}
@ -131,54 +125,54 @@ void PowerLimiterClass::loop()
if (isStopThresholdReached(inverter))
return;
// check for possible state changes
if (isStartThresholdReached(inverter) && calcPowerLimit(inverter, false) >= config.PowerLimiter_LowerPowerLimit) {
_plState = STATE_NORMAL_OPERATION;
}
else if (canUseDirectSolarPower() && calcPowerLimit(inverter, true) >= config.PowerLimiter_LowerPowerLimit) {
if (canUseDirectSolarPower()) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY;
}
// inverter on on state change
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;
if (isStartThresholdReached(inverter)) {
_plState = STATE_NORMAL_OPERATION;
}
else
return;
break;
case STATE_CONSUME_SOLAR_POWER_ONLY: {
int32_t newPowerLimit = calcPowerLimit(inverter, true);
if (!inverter->isProducing()
|| isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
if (isStopThresholdReached(inverter)) {
_plState = STATE_OFF;
break;
}
else if (!canUseDirectSolarPower() || isStartThresholdReached(inverter)) {
if (isStartThresholdReached(inverter)) {
_plState = STATE_NORMAL_OPERATION;
break;
}
if (!canUseDirectSolarPower()) {
if (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGTH)
_plState = STATE_NORMAL_OPERATION;
else
_plState = STATE_OFF;
break;
}
setNewPowerLimit(inverter, newPowerLimit);
return;
break;
}
case STATE_NORMAL_OPERATION: {
int32_t newPowerLimit = calcPowerLimit(inverter, false);
if (!inverter->isProducing()
|| isStopThresholdReached(inverter)
|| newPowerLimit < config.PowerLimiter_LowerPowerLimit) {
if (isStopThresholdReached(inverter)) {
_plState = STATE_OFF;
break;
}
// check if grid power consumption is within the upper an lower threshold of the target consumption
else if (newPowerLimit >= (config.PowerLimiter_TargetPowerConsumption - config.PowerLimiter_TargetPowerConsumptionHysteresis) &&
if (canUseDirectSolarPower() && (config.PowerLimiter_BatteryDrainStategy == EMPTY_AT_NIGTH)) {
_plState = STATE_CONSUME_SOLAR_POWER_ONLY;
break;
}
// 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);
setNewPowerLimit(inverter, newPowerLimit);;
return;
break;
}
@ -190,7 +184,7 @@ plStates PowerLimiterClass::getPowerLimiterState() {
return _plState;
}
uint16_t PowerLimiterClass::getLastRequestedPowewrLimit() {
int32_t PowerLimiterClass::getLastRequestedPowewrLimit() {
return _lastRequestedPowerLimit;
}
@ -203,7 +197,7 @@ bool PowerLimiterClass::canUseDirectSolarPower()
return false;
}
if (VeDirect.veFrame.PPV < 10.0) {
if (VeDirect.veFrame.PPV < 20) {
// Not enough power
return false;
}
@ -215,13 +209,14 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
{
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);
uint32_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 victronChargePower = this->getDirectSolarPower();
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 (config.PowerLimiter_IsInverterBehindPowerMeter) {
@ -234,7 +229,7 @@ int32_t PowerLimiterClass::calcPowerLimit(std::shared_ptr<InverterAbstract> inve
newPowerLimit -= config.PowerLimiter_TargetPowerConsumption;
uint16_t upperPowerLimit = config.PowerLimiter_UpperPowerLimit;
int32_t upperPowerLimit = config.PowerLimiter_UpperPowerLimit;
if (consumeSolarPowerOnly && (upperPowerLimit > adjustedVictronChargePower)) {
// Battery voltage too low, use Victron solar power (corrected by efficency factor) only
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.
newPowerLimit = config.PowerLimiter_LowerPowerLimit;
}
MessageOutput.printf("[PowerLimiterClass::loop] newPowerLimit: %d\r\n", 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)
{
if(_lastRequestedPowerLimit != newPowerLimit) {
CONFIG_T& config = Configuration.get();
// 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;
_lastCommandSent = millis();
}
}
uint16_t PowerLimiterClass::getDirectSolarPower()
int32_t PowerLimiterClass::getDirectSolarPower()
{
if (!canUseDirectSolarPower()) {
return 0;

View File

@ -31,16 +31,16 @@ void PylontechCanReceiverClass::enable()
// Install TWAI driver
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 {
MessageOutput.printf("Failed to install driver\n");
MessageOutput.printf("[Pylontech] Failed to install Twai driver\n");
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
MessageOutput.printf("Driver started\n");
MessageOutput.printf("[Pylontech] Twai driver started\n");
} 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
twai_status_info_t status_info;
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;
}
if (status_info.msgs_to_rx == 0) {
@ -112,7 +112,7 @@ void PylontechCanReceiverClass::parseCanPackets()
// Wait for message to be received, function is blocking
twai_message_t rx_message;
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;
}
@ -201,7 +201,6 @@ void PylontechCanReceiverClass::parseCanPackets()
}
case 0x35E: {
String manufacturer = String(rx_message.data, rx_message.data_length_code);
//CAN.readString();
@ -230,7 +229,6 @@ void PylontechCanReceiverClass::parseCanPackets()
Battery.chargeImmediately);
#endif
// this->readUnsignedInt8();
break;
}
}

View File

@ -64,7 +64,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
displayPinObj[F("reset")] = pin.display_reset;
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("screensaver")] = config.Display_ScreenSaver;
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;
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_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
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.enableScreensaver = config.Display_ScreenSaver;
Display.contrast = config.Display_Contrast;
Display.setContrast(config.Display_Contrast);
Configuration.write();

View File

@ -37,6 +37,7 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request)
root[F("enabled")] = config.PowerLimiter_Enabled;
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_2")] = config.PowerLimiter_MqttTopicPowerMeter2;
root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3;
@ -120,6 +121,7 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get();
config.PowerLimiter_Enabled = root[F("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_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));

View File

@ -70,6 +70,7 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
if (inv->Statistics()->getLastUpdate() > 0) {
for (auto& t : inv->Statistics()->getChannelTypes()) {
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_UAC);
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));
}
}
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_cs,
pin.display_reset);
Display.showLogo = config.Display_ShowLogo;
Display.setOrientation(config.Display_Rotation);
Display.enablePowerSafe = config.Display_PowerSafe;
Display.enableScreensaver = config.Display_ScreenSaver;
Display.contrast = config.Display_Contrast;
Display.setContrast(config.Display_Contrast);
Display.setStartupDisplay();
MessageOutput.println(F("done"));
// Check for default DTU serial

View File

@ -13,7 +13,7 @@
"dependencies": {
"@popperjs/core": "^2.11.6",
"bootstrap": "^5.3.0-alpha1",
"bootstrap-icons-vue": "^1.8.1",
"bootstrap-icons-vue": "^1.10.3",
"mitt": "^3.0.0",
"spark-md5": "^3.0.2",
"vue": "^3.2.47",
@ -21,23 +21,23 @@
"vue-router": "^4.1.6"
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.8.2",
"@intlify/unplugin-vue-i18n": "^0.9.2",
"@rushstack/eslint-patch": "^1.2.0",
"@types/bootstrap": "^5.2.6",
"@types/node": "^18.14.6",
"@types/node": "^18.15.3",
"@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/tsconfig": "^0.1.3",
"eslint": "^8.35.0",
"eslint": "^8.36.0",
"eslint-plugin-vue": "^9.9.0",
"npm-run-all": "^4.1.5",
"sass": "^1.58.3",
"terser": "^5.16.5",
"sass": "^1.59.3",
"terser": "^5.16.6",
"typescript": "^4.9.5",
"vite": "^4.1.4",
"vite": "^4.2.0",
"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"
}
}

View File

@ -11,126 +11,21 @@
</tr>
</thead>
<tbody>
<tr>
<td rowspan="6">NRF24</td>
<td>MISO</td>
<td>{{ selectedPinAssignment?.nrf24?.miso }}</td>
<td>{{ currentPinAssignment?.nrf24?.miso }}</td>
<template v-for="(category) in categories">
<tr v-for="(prop, prop_idx) in properties(category)">
<td v-if="prop_idx == 0" :rowspan="properties(category).length">
{{ capitalizeFirstLetter(category) }}</td>
<td :class="{ 'table-danger': !isEqual(category, prop) }">{{ prop }}</td>
<td>
<template v-if="((selectedPinAssignment as Device)[category as keyof Device])">
{{ (selectedPinAssignment as any)[category][prop] }}</template>
</td>
<td>
<template v-if="((currentPinAssignment as Device)[category as keyof Device])">
{{ (currentPinAssignment as any)[category][prop] }}</template>
</td>
</tr>
<tr>
<td>MOSI</td>
<td>{{ selectedPinAssignment?.nrf24?.mosi }}</td>
<td>{{ currentPinAssignment?.nrf24?.mosi }}</td>
</tr>
<tr>
<td>CLK</td>
<td>{{ selectedPinAssignment?.nrf24?.clk }}</td>
<td>{{ currentPinAssignment?.nrf24?.clk }}</td>
</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>
</template>
</tbody>
</table>
</div>
@ -150,5 +45,53 @@ export default defineComponent({
selectedPinAssignment: { 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>

View File

@ -459,6 +459,9 @@
"General": "Allgemein",
"Enable": "Aktiviert",
"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.",
"InverterId": "Wechselrichter ID",
"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",
"Screensaver": "Screensaver aktivieren:",
"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}):",
"Rotation": "Rotation:",
"rot0": "Keine Rotation",
"rot90": "90 Grad Drehung",
"rot180": "180 Grad Drehung",
"rot270": "270 Grad Drehung",
"Save": "@:dtuadmin.Save"
},
"pininfo": {

View File

@ -459,6 +459,9 @@
"General": "General",
"Enable": "Enable",
"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.",
"InverterId": "Inverter ID",
"InverterIdHint": "Select proper inverter ID where battery is connected to.",
@ -599,8 +602,12 @@
"PowerSafeHint": "Turn off the display if no inverter is producing.",
"Screensaver": "Enable Screensaver:",
"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}):",
"Rotation": "Rotation:",
"rot0": "No rotation",
"rot90": "90 degree rotation",
"rot180": "180 degree rotation",
"rot270": "270 degree rotation",
"Save": "@:dtuadmin.Save"
},
"pininfo": {

View File

@ -559,8 +559,12 @@
"PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.",
"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)",
"ShowLogo": "Afficher le logo",
"Contrast": "Contraste ({contrast}):",
"Rotation": "Rotation:",
"rot0": "No rotation",
"rot90": "90 degree rotation",
"rot180": "180 degree rotation",
"rot270": "270 degree rotation",
"Save": "@:dtuadmin.Save"
},
"pininfo": {

View File

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

View File

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

View File

@ -57,8 +57,18 @@
v-model="deviceConfigList.display.screensaver" type="checkbox"
:tooltip="$t('deviceadmin.ScreensaverHint')" />
<InputElement :label="$t('deviceadmin.ShowLogo')"
v-model="deviceConfigList.display.show_logo" type="checkbox" />
<div class="row mb-3">
<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">
<label for="inputDisplayContrast" class="col-sm-2 col-form-label">{{
@ -108,6 +118,12 @@ export default defineComponent({
alertMessage: "",
alertType: "info",
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() {

View File

@ -29,13 +29,13 @@
</CardElement>
<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')"
v-model="ntpConfigList.latitude"
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>
<button type="submit" class="btn btn-primary mb-3">{{ $t('ntpadmin.Save') }}</button>
</form>

View File

@ -15,6 +15,19 @@
v-model="powerLimiterConfigList.solar_passtrough_enabled"
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="row mb-3" v-show="powerLimiterConfigList.enabled">
@ -256,6 +269,10 @@ export default defineComponent({
{ key: 2, value: "CH 2" },
{ key: 3, value: "CH 3" },
],
batteryDrainStrategyList: [
{ key: 0, value: "powerlimiteradmin.BatteryDrainWhenFull"},
{ key: 1, value: "powerlimiteradmin.BatteryDrainAtNight" },
],
alertMessage: "",
alertType: "info",
showAlert: false,

View File

@ -17,7 +17,7 @@ export default defineConfig({
cssInjectedByJsPlugin(),
VueI18nPlugin({
/* 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,
forceStringify: true,
}),

View File

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