inital version of full solar passthrough
Webinterface change to set full solar passthrough values Adding webapi and config changes to enable full solar passthrough over certain battery Soc inital version of full solar passthrough in power limiter Passthrough mode can be enabled via MQTT translations re-enable comment remove unused variable
This commit is contained in:
commit
e7c8a89bd3
@ -18,5 +18,30 @@
|
|||||||
"type": 0,
|
"type": 0,
|
||||||
"clk_mode": 0
|
"clk_mode": 0
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WT32-ETH01 with SSD1306",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 4,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 32,
|
||||||
|
"irq": 33,
|
||||||
|
"en": 14,
|
||||||
|
"cs": 15
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 1,
|
||||||
|
"power": 16,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 0
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 2,
|
||||||
|
"data": 5,
|
||||||
|
"clk": 17
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -47,6 +47,7 @@ struct CHANNEL_CONFIG_T {
|
|||||||
struct INVERTER_CONFIG_T {
|
struct INVERTER_CONFIG_T {
|
||||||
uint64_t Serial;
|
uint64_t Serial;
|
||||||
char Name[INV_MAX_NAME_STRLEN + 1];
|
char Name[INV_MAX_NAME_STRLEN + 1];
|
||||||
|
uint8_t Order;
|
||||||
bool Poll_Enable;
|
bool Poll_Enable;
|
||||||
bool Poll_Enable_Night;
|
bool Poll_Enable_Night;
|
||||||
bool Command_Enable;
|
bool Command_Enable;
|
||||||
@ -82,6 +83,7 @@ struct CONFIG_T {
|
|||||||
char Ntp_TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1];
|
char Ntp_TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1];
|
||||||
double Ntp_Longitude;
|
double Ntp_Longitude;
|
||||||
double Ntp_Latitude;
|
double Ntp_Latitude;
|
||||||
|
uint8_t Ntp_SunsetType;
|
||||||
|
|
||||||
bool Mqtt_Enabled;
|
bool Mqtt_Enabled;
|
||||||
uint Mqtt_Port;
|
uint Mqtt_Port;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <TimeoutHelper.h>
|
#include <TimeoutHelper.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
|
||||||
class DatastoreClass {
|
class DatastoreClass {
|
||||||
public:
|
public:
|
||||||
@ -10,52 +12,69 @@ public:
|
|||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
// Sum of yield total of all enabled inverters, a inverter which is just disabled at night is also included
|
// Sum of yield total of all enabled inverters, a inverter which is just disabled at night is also included
|
||||||
float totalAcYieldTotalEnabled = 0;
|
float getTotalAcYieldTotalEnabled();
|
||||||
|
|
||||||
// Sum of yield day of all enabled inverters, a inverter which is just disabled at night is also included
|
// Sum of yield day of all enabled inverters, a inverter which is just disabled at night is also included
|
||||||
float totalAcYieldDayEnabled = 0;
|
float getTotalAcYieldDayEnabled();
|
||||||
|
|
||||||
// Sum of total AC power of all enabled inverters
|
// Sum of total AC power of all enabled inverters
|
||||||
float totalAcPowerEnabled = 0;
|
float getTotalAcPowerEnabled();
|
||||||
|
|
||||||
// Sum of total DC power of all enabled inverters
|
// Sum of total DC power of all enabled inverters
|
||||||
float totalDcPowerEnabled = 0;
|
float getTotalDcPowerEnabled();
|
||||||
|
|
||||||
// Sum of total DC power of all enabled inverters with maxStringPower set
|
// Sum of total DC power of all enabled inverters with maxStringPower set
|
||||||
float totalDcPowerIrradiation = 0;
|
float getTotalDcPowerIrradiation();
|
||||||
|
|
||||||
// Sum of total installed irradiation of all enabled inverters
|
// Sum of total installed irradiation of all enabled inverters
|
||||||
float totalDcIrradiationInstalled = 0;
|
float getTotalDcIrradiationInstalled();
|
||||||
|
|
||||||
// Percentage (1-100) of total irradiation
|
// Percentage (1-100) of total irradiation
|
||||||
float totalDcIrradiation = 0;
|
float getTotalDcIrradiation();
|
||||||
|
|
||||||
// Amount of relevant digits for yield total
|
// Amount of relevant digits for yield total
|
||||||
unsigned int totalAcYieldTotalDigits = 0;
|
unsigned int getTotalAcYieldTotalDigits();
|
||||||
|
|
||||||
// Amount of relevant digits for yield total
|
// Amount of relevant digits for yield total
|
||||||
unsigned int totalAcYieldDayDigits = 0;
|
unsigned int getTotalAcYieldDayDigits();
|
||||||
|
|
||||||
// Amount of relevant digits for AC power
|
// Amount of relevant digits for AC power
|
||||||
unsigned int totalAcPowerDigits = 0;
|
unsigned int getTotalAcPowerDigits();
|
||||||
|
|
||||||
// Amount of relevant digits for DC power
|
// Amount of relevant digits for DC power
|
||||||
unsigned int totalDcPowerDigits = 0;
|
unsigned int getTotalDcPowerDigits();
|
||||||
|
|
||||||
// True, if at least one inverter is reachable
|
// True, if at least one inverter is reachable
|
||||||
bool isAtLeastOneReachable = false;
|
bool getIsAtLeastOneReachable();
|
||||||
|
|
||||||
// True if at least one inverter is producing
|
// True if at least one inverter is producing
|
||||||
bool isAtLeastOneProducing = false;
|
bool getIsAtLeastOneProducing();
|
||||||
|
|
||||||
// True if all enabled inverters are producing
|
// True if all enabled inverters are producing
|
||||||
bool isAllEnabledProducing = false;
|
bool getIsAllEnabledProducing();
|
||||||
|
|
||||||
// True if all enabled inverters are reachable
|
// True if all enabled inverters are reachable
|
||||||
bool isAllEnabledReachable = false;
|
bool getIsAllEnabledReachable();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TimeoutHelper _updateTimeout;
|
TimeoutHelper _updateTimeout;
|
||||||
|
SemaphoreHandle_t _xSemaphore;
|
||||||
|
|
||||||
|
float _totalAcYieldTotalEnabled = 0;
|
||||||
|
float _totalAcYieldDayEnabled = 0;
|
||||||
|
float _totalAcPowerEnabled = 0;
|
||||||
|
float _totalDcPowerEnabled = 0;
|
||||||
|
float _totalDcPowerIrradiation = 0;
|
||||||
|
float _totalDcIrradiationInstalled = 0;
|
||||||
|
float _totalDcIrradiation = 0;
|
||||||
|
unsigned int _totalAcYieldTotalDigits = 0;
|
||||||
|
unsigned int _totalAcYieldDayDigits = 0;
|
||||||
|
unsigned int _totalAcPowerDigits = 0;
|
||||||
|
unsigned int _totalDcPowerDigits = 0;
|
||||||
|
bool _isAtLeastOneReachable = false;
|
||||||
|
bool _isAtLeastOneProducing = false;
|
||||||
|
bool _isAllEnabledProducing = false;
|
||||||
|
bool _isAllEnabledReachable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern DatastoreClass Datastore;
|
extern DatastoreClass Datastore;
|
||||||
@ -12,6 +12,7 @@ public:
|
|||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
bool isDayPeriod();
|
bool isDayPeriod();
|
||||||
|
bool isSunsetAvailable();
|
||||||
bool sunsetTime(struct tm* info);
|
bool sunsetTime(struct tm* info);
|
||||||
bool sunriseTime(struct tm* info);
|
bool sunriseTime(struct tm* info);
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ private:
|
|||||||
|
|
||||||
SunSet _sun;
|
SunSet _sun;
|
||||||
bool _isDayPeriod = true;
|
bool _isDayPeriod = true;
|
||||||
|
bool _isSunsetAvailable = true;
|
||||||
uint _sunriseMinutes = 0;
|
uint _sunriseMinutes = 0;
|
||||||
uint _sunsetMinutes = 0;
|
uint _sunsetMinutes = 0;
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ enum WebApiError {
|
|||||||
InverterInvalidMaxChannel,
|
InverterInvalidMaxChannel,
|
||||||
InverterChanged,
|
InverterChanged,
|
||||||
InverterDeleted,
|
InverterDeleted,
|
||||||
|
InverterOrdered,
|
||||||
|
|
||||||
LimitBase = 5000,
|
LimitBase = 5000,
|
||||||
LimitSerialZero,
|
LimitSerialZero,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ private:
|
|||||||
void onInverterAdd(AsyncWebServerRequest* request);
|
void onInverterAdd(AsyncWebServerRequest* request);
|
||||||
void onInverterEdit(AsyncWebServerRequest* request);
|
void onInverterEdit(AsyncWebServerRequest* request);
|
||||||
void onInverterDelete(AsyncWebServerRequest* request);
|
void onInverterDelete(AsyncWebServerRequest* request);
|
||||||
|
void onInverterOrder(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
AsyncWebServer* _server;
|
AsyncWebServer* _server;
|
||||||
};
|
};
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#define NTP_TIMEZONEDESCR "Europe/Berlin"
|
#define NTP_TIMEZONEDESCR "Europe/Berlin"
|
||||||
#define NTP_LONGITUDE 10.4515f
|
#define NTP_LONGITUDE 10.4515f
|
||||||
#define NTP_LATITUDE 51.1657f
|
#define NTP_LATITUDE 51.1657f
|
||||||
|
#define NTP_SUNSETTYPE 1
|
||||||
|
|
||||||
#define MQTT_ENABLED false
|
#define MQTT_ENABLED false
|
||||||
#define MQTT_HOST ""
|
#define MQTT_HOST ""
|
||||||
|
|||||||
@ -121,17 +121,25 @@ void HoymilesRadio_CMT::loop()
|
|||||||
if (!_rxBuffer.empty()) {
|
if (!_rxBuffer.empty()) {
|
||||||
fragment_t f = _rxBuffer.back();
|
fragment_t f = _rxBuffer.back();
|
||||||
if (checkFragmentCrc(&f)) {
|
if (checkFragmentCrc(&f)) {
|
||||||
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
|
||||||
|
|
||||||
if (nullptr != inv) {
|
serial_u dtuId = convertSerialToRadioId(_dtuSerial);
|
||||||
// Save packet in inverter rx buffer
|
|
||||||
Hoymiles.getMessageOutput()->printf("RX %.2f MHz --> ", getFrequencyFromChannel(f.channel));
|
|
||||||
dumpBuf(f.fragment, f.len, false);
|
|
||||||
Hoymiles.getMessageOutput()->printf("| %d dBm\r\n", f.rssi);
|
|
||||||
|
|
||||||
inv->addRxFragment(f.fragment, f.len);
|
// The CMT RF module does not filter foreign packages by itself.
|
||||||
} else {
|
// Has to be done manually here.
|
||||||
Hoymiles.getMessageOutput()->println("Inverter Not found!");
|
if (memcmp(&f.fragment[5], &dtuId.b[1], 4) == 0) {
|
||||||
|
|
||||||
|
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterByFragment(&f);
|
||||||
|
|
||||||
|
if (nullptr != inv) {
|
||||||
|
// Save packet in inverter rx buffer
|
||||||
|
Hoymiles.getMessageOutput()->printf("RX %.2f MHz --> ", getFrequencyFromChannel(f.channel));
|
||||||
|
dumpBuf(f.fragment, f.len, false);
|
||||||
|
Hoymiles.getMessageOutput()->printf("| %d dBm\r\n", f.rssi);
|
||||||
|
|
||||||
|
inv->addRxFragment(f.fragment, f.len);
|
||||||
|
} else {
|
||||||
|
Hoymiles.getMessageOutput()->println("Inverter Not found!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -68,6 +68,11 @@ bool MultiDataCommand::handleResponse(InverterAbstract* inverter, fragment_t fra
|
|||||||
uint16_t crc = 0xffff, crcRcv = 0;
|
uint16_t crc = 0xffff, crcRcv = 0;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < max_fragment_id; i++) {
|
for (uint8_t i = 0; i < max_fragment_id; i++) {
|
||||||
|
// Doublecheck if correct answer package
|
||||||
|
if (fragment[i].mainCmd != (_payload[0] | 0x80)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (i == max_fragment_id - 1) {
|
if (i == max_fragment_id - 1) {
|
||||||
// Last packet
|
// Last packet
|
||||||
crc = crc16(fragment[i].fragment, fragment[i].len - 2, crc);
|
crc = crc16(fragment[i].fragment, fragment[i].len - 2, crc);
|
||||||
|
|||||||
@ -6,9 +6,10 @@
|
|||||||
#include "../Hoymiles.h"
|
#include "../Hoymiles.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
const std::array<const AlarmMessage_t, 76> AlarmLogParser::_alarmMessages = {{
|
const std::array<const AlarmMessage_t, ALARM_MSG_COUNT> AlarmLogParser::_alarmMessages = {{
|
||||||
{ AlarmMessageType_t::ALL, 1, "Inverter start" },
|
{ AlarmMessageType_t::ALL, 1, "Inverter start" },
|
||||||
{ AlarmMessageType_t::ALL, 2, "DTU command failed" },
|
{ AlarmMessageType_t::ALL, 2, "DTU command failed" },
|
||||||
|
{ AlarmMessageType_t::ALL, 73, "Temperature >80°C" }, // https://github.com/tbnobody/OpenDTU/discussions/590#discussioncomment-6049750
|
||||||
{ AlarmMessageType_t::ALL, 121, "Over temperature protection" },
|
{ AlarmMessageType_t::ALL, 121, "Over temperature protection" },
|
||||||
{ AlarmMessageType_t::ALL, 124, "Shut down by remote control" },
|
{ AlarmMessageType_t::ALL, 124, "Shut down by remote control" },
|
||||||
{ AlarmMessageType_t::ALL, 125, "Grid configuration parameter error" },
|
{ AlarmMessageType_t::ALL, 125, "Grid configuration parameter error" },
|
||||||
|
|||||||
@ -9,6 +9,8 @@
|
|||||||
#define ALARM_LOG_ENTRY_SIZE 12
|
#define ALARM_LOG_ENTRY_SIZE 12
|
||||||
#define ALARM_LOG_PAYLOAD_SIZE (ALARM_LOG_ENTRY_COUNT * ALARM_LOG_ENTRY_SIZE + 4)
|
#define ALARM_LOG_PAYLOAD_SIZE (ALARM_LOG_ENTRY_COUNT * ALARM_LOG_ENTRY_SIZE + 4)
|
||||||
|
|
||||||
|
#define ALARM_MSG_COUNT 77
|
||||||
|
|
||||||
struct AlarmLogEntry_t {
|
struct AlarmLogEntry_t {
|
||||||
uint16_t MessageId;
|
uint16_t MessageId;
|
||||||
String Message;
|
String Message;
|
||||||
@ -50,5 +52,5 @@ private:
|
|||||||
|
|
||||||
AlarmMessageType_t _messageType = AlarmMessageType_t::ALL;
|
AlarmMessageType_t _messageType = AlarmMessageType_t::ALL;
|
||||||
|
|
||||||
static const std::array<const AlarmMessage_t, 76> _alarmMessages;
|
static const std::array<const AlarmMessage_t, ALARM_MSG_COUNT> _alarmMessages;
|
||||||
};
|
};
|
||||||
@ -32,7 +32,8 @@ const devInfo_t devInfo[] = {
|
|||||||
{ { 0x10, 0x10, 0x51, ALL }, 450, "HMS-450" }, // 01
|
{ { 0x10, 0x10, 0x51, ALL }, 450, "HMS-450" }, // 01
|
||||||
{ { 0x10, 0x10, 0x71, ALL }, 500, "HMS-500" }, // 02
|
{ { 0x10, 0x10, 0x71, ALL }, 500, "HMS-500" }, // 02
|
||||||
{ { 0x10, 0x21, 0x11, ALL }, 600, "HMS-600" }, // 01
|
{ { 0x10, 0x21, 0x11, ALL }, 600, "HMS-600" }, // 01
|
||||||
{ { 0x10, 0x21, 0x41, ALL }, 800, "HMS-800" }, // 00
|
{ { 0x10, 0x21, 0x41, ALL }, 800, "HMS-800" }, // 00
|
||||||
|
{ { 0x10, 0x11, 0x51, ALL }, 900, "HMS-900" }, // 01
|
||||||
{ { 0x10, 0x21, 0x71, ALL }, 1000, "HMS-1000" }, // 05
|
{ { 0x10, 0x21, 0x71, ALL }, 1000, "HMS-1000" }, // 05
|
||||||
{ { 0x10, 0x22, 0x41, ALL }, 1600, "HMS-1600" }, // 4
|
{ { 0x10, 0x22, 0x41, ALL }, 1600, "HMS-1600" }, // 4
|
||||||
{ { 0x10, 0x12, 0x51, ALL }, 1800, "HMS-1800" }, // 01
|
{ { 0x10, 0x12, 0x51, ALL }, 1800, "HMS-1800" }, // 01
|
||||||
|
|||||||
77
pio-scripts/create_factory_bin.py
Normal file
77
pio-scripts/create_factory_bin.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Part of ESPEasy build toolchain.
|
||||||
|
#
|
||||||
|
# Combines separate bin files with their respective offsets into a single file
|
||||||
|
# This single file must then be flashed to an ESP32 node with 0 offset.
|
||||||
|
#
|
||||||
|
# Original implementation: Bartłomiej Zimoń (@uzi18)
|
||||||
|
# Maintainer: Gijs Noorlander (@TD-er)
|
||||||
|
#
|
||||||
|
# Special thanks to @Jason2866 (Tasmota) for helping debug flashing to >4MB flash
|
||||||
|
# Thanks @jesserockz (esphome) for adapting to use esptool.py with merge_bin
|
||||||
|
#
|
||||||
|
# Typical layout of the generated file:
|
||||||
|
# Offset | File
|
||||||
|
# - 0x1000 | ~\.platformio\packages\framework-arduinoespressif32\tools\sdk\esp32\bin\bootloader_dout_40m.bin
|
||||||
|
# - 0x8000 | ~\ESPEasy\.pio\build\<env name>\partitions.bin
|
||||||
|
# - 0xe000 | ~\.platformio\packages\framework-arduinoespressif32\tools\partitions\boot_app0.bin
|
||||||
|
# - 0x10000 | ~\ESPEasy\.pio\build\<env name>/<built binary>.bin
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
platform = env.PioPlatform()
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
|
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||||
|
import esptool
|
||||||
|
|
||||||
|
def esp32_create_combined_bin(source, target, env):
|
||||||
|
print("Generating combined binary for serial flashing")
|
||||||
|
|
||||||
|
# The offset from begin of the file where the app0 partition starts
|
||||||
|
# This is defined in the partition .csv file
|
||||||
|
app_offset = 0x10000
|
||||||
|
|
||||||
|
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||||
|
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||||
|
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||||
|
chip = env.get("BOARD_MCU")
|
||||||
|
flash_size = env.BoardConfig().get("upload.flash_size")
|
||||||
|
flash_freq = env.BoardConfig().get("build.f_flash", '40m')
|
||||||
|
flash_freq = flash_freq.replace('000000L', 'm')
|
||||||
|
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
|
||||||
|
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
|
||||||
|
if flash_mode == "qio" or flash_mode == "qout":
|
||||||
|
flash_mode = "dio"
|
||||||
|
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||||
|
flash_mode = "dout"
|
||||||
|
cmd = [
|
||||||
|
"--chip",
|
||||||
|
chip,
|
||||||
|
"merge_bin",
|
||||||
|
"-o",
|
||||||
|
new_file_name,
|
||||||
|
"--flash_mode",
|
||||||
|
flash_mode,
|
||||||
|
"--flash_freq",
|
||||||
|
flash_freq,
|
||||||
|
"--flash_size",
|
||||||
|
flash_size,
|
||||||
|
]
|
||||||
|
|
||||||
|
print(" Offset | File")
|
||||||
|
for section in sections:
|
||||||
|
sect_adr, sect_file = section.split(" ", 1)
|
||||||
|
print(f" - {sect_adr} | {sect_file}")
|
||||||
|
cmd += [sect_adr, sect_file]
|
||||||
|
|
||||||
|
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||||
|
cmd += [hex(app_offset), firmware_name]
|
||||||
|
|
||||||
|
print('Using esptool.py arguments: %s' % ' '.join(cmd))
|
||||||
|
|
||||||
|
esptool.main(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||||
@ -29,7 +29,7 @@ build_unflags =
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/yubox-node-org/ESPAsyncWebServer
|
https://github.com/yubox-node-org/ESPAsyncWebServer
|
||||||
bblanchon/ArduinoJson @ ^6.21.2
|
bblanchon/ArduinoJson @ ^6.21.2
|
||||||
https://github.com/bertmelis/espMqttClient.git#v1.4.2
|
https://github.com/bertmelis/espMqttClient.git#v1.4.3
|
||||||
nrf24/RF24 @ ^1.4.5
|
nrf24/RF24 @ ^1.4.5
|
||||||
olikraus/U8g2 @ ^2.34.17
|
olikraus/U8g2 @ ^2.34.17
|
||||||
buelowp/sunset @ ^1.1.7
|
buelowp/sunset @ ^1.1.7
|
||||||
@ -40,6 +40,7 @@ lib_deps =
|
|||||||
extra_scripts =
|
extra_scripts =
|
||||||
pre:pio-scripts/auto_firmware_version.py
|
pre:pio-scripts/auto_firmware_version.py
|
||||||
pre:pio-scripts/patch_apply.py
|
pre:pio-scripts/patch_apply.py
|
||||||
|
post:pio-scripts/create_factory_bin.py
|
||||||
|
|
||||||
board_build.partitions = partitions_custom.csv
|
board_build.partitions = partitions_custom.csv
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
|
|||||||
@ -46,6 +46,7 @@ bool ConfigurationClass::write()
|
|||||||
ntp["timezone_descr"] = config.Ntp_TimezoneDescr;
|
ntp["timezone_descr"] = config.Ntp_TimezoneDescr;
|
||||||
ntp["latitude"] = config.Ntp_Latitude;
|
ntp["latitude"] = config.Ntp_Latitude;
|
||||||
ntp["longitude"] = config.Ntp_Longitude;
|
ntp["longitude"] = config.Ntp_Longitude;
|
||||||
|
ntp["sunsettype"] = config.Ntp_SunsetType;
|
||||||
|
|
||||||
JsonObject mqtt = doc.createNestedObject("mqtt");
|
JsonObject mqtt = doc.createNestedObject("mqtt");
|
||||||
mqtt["enabled"] = config.Mqtt_Enabled;
|
mqtt["enabled"] = config.Mqtt_Enabled;
|
||||||
@ -102,6 +103,7 @@ bool ConfigurationClass::write()
|
|||||||
JsonObject inv = inverters.createNestedObject();
|
JsonObject inv = inverters.createNestedObject();
|
||||||
inv["serial"] = config.Inverter[i].Serial;
|
inv["serial"] = config.Inverter[i].Serial;
|
||||||
inv["name"] = config.Inverter[i].Name;
|
inv["name"] = config.Inverter[i].Name;
|
||||||
|
inv["order"] = config.Inverter[i].Order;
|
||||||
inv["poll_enable"] = config.Inverter[i].Poll_Enable;
|
inv["poll_enable"] = config.Inverter[i].Poll_Enable;
|
||||||
inv["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
|
inv["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
|
||||||
inv["command_enable"] = config.Inverter[i].Command_Enable;
|
inv["command_enable"] = config.Inverter[i].Command_Enable;
|
||||||
@ -241,6 +243,7 @@ bool ConfigurationClass::read()
|
|||||||
strlcpy(config.Ntp_TimezoneDescr, ntp["timezone_descr"] | NTP_TIMEZONEDESCR, sizeof(config.Ntp_TimezoneDescr));
|
strlcpy(config.Ntp_TimezoneDescr, ntp["timezone_descr"] | NTP_TIMEZONEDESCR, sizeof(config.Ntp_TimezoneDescr));
|
||||||
config.Ntp_Latitude = ntp["latitude"] | NTP_LATITUDE;
|
config.Ntp_Latitude = ntp["latitude"] | NTP_LATITUDE;
|
||||||
config.Ntp_Longitude = ntp["longitude"] | NTP_LONGITUDE;
|
config.Ntp_Longitude = ntp["longitude"] | NTP_LONGITUDE;
|
||||||
|
config.Ntp_SunsetType = ntp["sunsettype"] | NTP_SUNSETTYPE;
|
||||||
|
|
||||||
JsonObject mqtt = doc["mqtt"];
|
JsonObject mqtt = doc["mqtt"];
|
||||||
config.Mqtt_Enabled = mqtt["enabled"] | MQTT_ENABLED;
|
config.Mqtt_Enabled = mqtt["enabled"] | MQTT_ENABLED;
|
||||||
@ -297,6 +300,7 @@ bool ConfigurationClass::read()
|
|||||||
JsonObject inv = inverters[i].as<JsonObject>();
|
JsonObject inv = inverters[i].as<JsonObject>();
|
||||||
config.Inverter[i].Serial = inv["serial"] | 0ULL;
|
config.Inverter[i].Serial = inv["serial"] | 0ULL;
|
||||||
strlcpy(config.Inverter[i].Name, inv["name"] | "", sizeof(config.Inverter[i].Name));
|
strlcpy(config.Inverter[i].Name, inv["name"] | "", sizeof(config.Inverter[i].Name));
|
||||||
|
config.Inverter[i].Order = inv["order"] | 0;
|
||||||
|
|
||||||
config.Inverter[i].Poll_Enable = inv["poll_enable"] | true;
|
config.Inverter[i].Poll_Enable = inv["poll_enable"] | true;
|
||||||
config.Inverter[i].Poll_Enable_Night = inv["poll_enable_night"] | true;
|
config.Inverter[i].Poll_Enable_Night = inv["poll_enable_night"] | true;
|
||||||
|
|||||||
@ -6,10 +6,17 @@
|
|||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include <Hoymiles.h>
|
#include <Hoymiles.h>
|
||||||
|
|
||||||
|
#define DAT_SEMAPHORE_TAKE() \
|
||||||
|
do { \
|
||||||
|
} while (xSemaphoreTake(_xSemaphore, portMAX_DELAY) != pdPASS)
|
||||||
|
#define DAT_SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore)
|
||||||
|
|
||||||
DatastoreClass Datastore;
|
DatastoreClass Datastore;
|
||||||
|
|
||||||
DatastoreClass::DatastoreClass()
|
DatastoreClass::DatastoreClass()
|
||||||
{
|
{
|
||||||
|
_xSemaphore = xSemaphoreCreateMutex();
|
||||||
|
DAT_SEMAPHORE_GIVE(); // release before first use
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatastoreClass::init()
|
void DatastoreClass::init()
|
||||||
@ -24,23 +31,25 @@ void DatastoreClass::loop()
|
|||||||
uint8_t isProducing = 0;
|
uint8_t isProducing = 0;
|
||||||
uint8_t isReachable = 0;
|
uint8_t isReachable = 0;
|
||||||
|
|
||||||
totalAcYieldTotalEnabled = 0;
|
DAT_SEMAPHORE_TAKE();
|
||||||
totalAcYieldTotalDigits = 0;
|
|
||||||
|
|
||||||
totalAcYieldDayEnabled = 0;
|
_totalAcYieldTotalEnabled = 0;
|
||||||
totalAcYieldDayDigits = 0;
|
_totalAcYieldTotalDigits = 0;
|
||||||
|
|
||||||
totalAcPowerEnabled = 0;
|
_totalAcYieldDayEnabled = 0;
|
||||||
totalAcPowerDigits = 0;
|
_totalAcYieldDayDigits = 0;
|
||||||
|
|
||||||
totalDcPowerEnabled = 0;
|
_totalAcPowerEnabled = 0;
|
||||||
totalDcPowerDigits = 0;
|
_totalAcPowerDigits = 0;
|
||||||
|
|
||||||
totalDcPowerIrradiation = 0;
|
_totalDcPowerEnabled = 0;
|
||||||
totalDcIrradiationInstalled = 0;
|
_totalDcPowerDigits = 0;
|
||||||
|
|
||||||
isAllEnabledProducing = true;
|
_totalDcPowerIrradiation = 0;
|
||||||
isAllEnabledReachable = true;
|
_totalDcIrradiationInstalled = 0;
|
||||||
|
|
||||||
|
_isAllEnabledProducing = true;
|
||||||
|
_isAllEnabledReachable = true;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
@ -57,7 +66,7 @@ void DatastoreClass::loop()
|
|||||||
isProducing++;
|
isProducing++;
|
||||||
} else {
|
} else {
|
||||||
if (inv->getEnablePolling()) {
|
if (inv->getEnablePolling()) {
|
||||||
isAllEnabledProducing = false;
|
_isAllEnabledProducing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,42 +74,164 @@ void DatastoreClass::loop()
|
|||||||
isReachable++;
|
isReachable++;
|
||||||
} else {
|
} else {
|
||||||
if (inv->getEnablePolling()) {
|
if (inv->getEnablePolling()) {
|
||||||
isAllEnabledReachable = false;
|
_isAllEnabledReachable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||||
if (cfg->Poll_Enable) {
|
if (cfg->Poll_Enable) {
|
||||||
totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||||
totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||||
|
|
||||||
totalAcYieldTotalDigits = max<unsigned int>(totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
||||||
totalAcYieldDayDigits = max<unsigned int>(totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
||||||
}
|
}
|
||||||
if (inv->getEnablePolling()) {
|
if (inv->getEnablePolling()) {
|
||||||
totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
_totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||||
totalAcPowerDigits = max<unsigned int>(totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
_totalAcPowerDigits = max<unsigned int>(_totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_DC)) {
|
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_DC)) {
|
||||||
if (inv->getEnablePolling()) {
|
if (inv->getEnablePolling()) {
|
||||||
totalDcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
_totalDcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||||
totalDcPowerDigits = max<unsigned int>(totalDcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_DC, c, FLD_PDC));
|
_totalDcPowerDigits = max<unsigned int>(_totalDcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_DC, c, FLD_PDC));
|
||||||
|
|
||||||
if (inv->Statistics()->getStringMaxPower(c) > 0) {
|
if (inv->Statistics()->getStringMaxPower(c) > 0) {
|
||||||
totalDcPowerIrradiation += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
_totalDcPowerIrradiation += inv->Statistics()->getChannelFieldValue(TYPE_DC, c, FLD_PDC);
|
||||||
totalDcIrradiationInstalled += inv->Statistics()->getStringMaxPower(c);
|
_totalDcIrradiationInstalled += inv->Statistics()->getStringMaxPower(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isAtLeastOneProducing = isProducing > 0;
|
_isAtLeastOneProducing = isProducing > 0;
|
||||||
isAtLeastOneReachable = isReachable > 0;
|
_isAtLeastOneReachable = isReachable > 0;
|
||||||
|
|
||||||
totalDcIrradiation = totalDcIrradiationInstalled > 0 ? totalDcPowerIrradiation / totalDcIrradiationInstalled * 100.0f : 0;
|
_totalDcIrradiation = _totalDcIrradiationInstalled > 0 ? _totalDcPowerIrradiation / _totalDcIrradiationInstalled * 100.0f : 0;
|
||||||
|
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
|
||||||
_updateTimeout.reset();
|
_updateTimeout.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalAcYieldTotalEnabled()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalAcYieldTotalEnabled;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalAcYieldDayEnabled()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalAcYieldDayEnabled;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalAcPowerEnabled()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalAcPowerEnabled;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalDcPowerEnabled()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalDcPowerEnabled;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalDcPowerIrradiation()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalDcPowerIrradiation;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalDcIrradiationInstalled()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalDcIrradiationInstalled;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DatastoreClass::getTotalDcIrradiation()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
float retval = _totalDcIrradiation;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DatastoreClass::getTotalAcYieldTotalDigits()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
unsigned int retval = _totalAcYieldTotalDigits;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DatastoreClass::getTotalAcYieldDayDigits()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
unsigned int retval = _totalAcYieldDayDigits;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DatastoreClass::getTotalAcPowerDigits()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
unsigned int retval = _totalAcPowerDigits;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DatastoreClass::getTotalDcPowerDigits()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
unsigned int retval = _totalDcPowerDigits;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DatastoreClass::getIsAtLeastOneReachable()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
bool retval = _isAtLeastOneReachable;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DatastoreClass::getIsAtLeastOneProducing()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
bool retval = _isAtLeastOneProducing;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DatastoreClass::getIsAllEnabledProducing()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
bool retval = _isAllEnabledProducing;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DatastoreClass::getIsAllEnabledReachable()
|
||||||
|
{
|
||||||
|
DAT_SEMAPHORE_TAKE();
|
||||||
|
bool retval = _isAllEnabledReachable;
|
||||||
|
DAT_SEMAPHORE_GIVE();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|||||||
@ -141,12 +141,12 @@ void DisplayGraphicClass::loop()
|
|||||||
_display->clearBuffer();
|
_display->clearBuffer();
|
||||||
|
|
||||||
//=====> Actual Production ==========
|
//=====> Actual Production ==========
|
||||||
if (Datastore.isAtLeastOneReachable) {
|
if (Datastore.getIsAtLeastOneReachable()) {
|
||||||
_display->setPowerSave(false);
|
_display->setPowerSave(false);
|
||||||
if (Datastore.totalAcPowerEnabled > 999) {
|
if (Datastore.getTotalAcPowerEnabled() > 999) {
|
||||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], (Datastore.totalAcPowerEnabled / 1000));
|
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], (Datastore.getTotalAcPowerEnabled() / 1000));
|
||||||
} else {
|
} else {
|
||||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], Datastore.totalAcPowerEnabled);
|
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], Datastore.getTotalAcPowerEnabled());
|
||||||
}
|
}
|
||||||
printText(_fmtText, 0);
|
printText(_fmtText, 0);
|
||||||
_previousMillis = millis();
|
_previousMillis = millis();
|
||||||
@ -164,10 +164,10 @@ void DisplayGraphicClass::loop()
|
|||||||
//<=======================
|
//<=======================
|
||||||
|
|
||||||
//=====> Today & Total Production =======
|
//=====> Today & Total Production =======
|
||||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.totalAcYieldDayEnabled);
|
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.getTotalAcYieldDayEnabled());
|
||||||
printText(_fmtText, 1);
|
printText(_fmtText, 1);
|
||||||
|
|
||||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.totalAcYieldTotalEnabled);
|
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.getTotalAcYieldTotalEnabled());
|
||||||
printText(_fmtText, 2);
|
printText(_fmtText, 2);
|
||||||
//<=======================
|
//<=======================
|
||||||
|
|
||||||
|
|||||||
@ -59,10 +59,10 @@ void LedSingleClass::loop()
|
|||||||
_ledState[1] = LedState_t::Off;
|
_ledState[1] = LedState_t::Off;
|
||||||
if (Hoymiles.getNumInverters()) {
|
if (Hoymiles.getNumInverters()) {
|
||||||
// set LED status
|
// set LED status
|
||||||
if (Datastore.isAllEnabledReachable && Datastore.isAllEnabledProducing) {
|
if (Datastore.getIsAllEnabledReachable() && Datastore.getIsAllEnabledProducing()) {
|
||||||
_ledState[1] = LedState_t::On;
|
_ledState[1] = LedState_t::On;
|
||||||
}
|
}
|
||||||
if (Datastore.isAllEnabledReachable && !Datastore.isAllEnabledProducing) {
|
if (Datastore.getIsAllEnabledReachable() && !Datastore.getIsAllEnabledProducing()) {
|
||||||
_ledState[1] = LedState_t::Blink;
|
_ledState[1] = LedState_t::Blink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,13 +22,13 @@ void MqttHandleInverterTotalClass::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_lastPublish.occured()) {
|
if (_lastPublish.occured()) {
|
||||||
MqttSettings.publish("ac/power", String(Datastore.totalAcPowerEnabled, Datastore.totalAcPowerDigits));
|
MqttSettings.publish("ac/power", String(Datastore.getTotalAcPowerEnabled(), Datastore.getTotalAcPowerDigits()));
|
||||||
MqttSettings.publish("ac/yieldtotal", String(Datastore.totalAcYieldTotalEnabled, Datastore.totalAcYieldTotalDigits));
|
MqttSettings.publish("ac/yieldtotal", String(Datastore.getTotalAcYieldTotalEnabled(), Datastore.getTotalAcYieldTotalDigits()));
|
||||||
MqttSettings.publish("ac/yieldday", String(Datastore.totalAcYieldDayEnabled, Datastore.totalAcYieldDayDigits));
|
MqttSettings.publish("ac/yieldday", String(Datastore.getTotalAcYieldDayEnabled(), Datastore.getTotalAcYieldDayDigits()));
|
||||||
MqttSettings.publish("ac/is_valid", String(Datastore.isAllEnabledReachable));
|
MqttSettings.publish("ac/is_valid", String(Datastore.getIsAllEnabledReachable()));
|
||||||
MqttSettings.publish("dc/power", String(Datastore.totalDcPowerEnabled, Datastore.totalDcPowerDigits));
|
MqttSettings.publish("dc/power", String(Datastore.getTotalDcPowerEnabled(), Datastore.getTotalDcPowerDigits()));
|
||||||
MqttSettings.publish("dc/irradiation", String(Datastore.totalDcIrradiation, 3));
|
MqttSettings.publish("dc/irradiation", String(Datastore.getTotalDcIrradiation(), 3));
|
||||||
MqttSettings.publish("dc/is_valid", String(Datastore.isAllEnabledReachable));
|
MqttSettings.publish("dc/is_valid", String(Datastore.getIsAllEnabledReachable()));
|
||||||
|
|
||||||
_lastPublish.set(Configuration.get().Mqtt_PublishInterval * 1000);
|
_lastPublish.set(Configuration.get().Mqtt_PublishInterval * 1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,11 @@ bool SunPositionClass::isDayPeriod()
|
|||||||
return _isDayPeriod;
|
return _isDayPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SunPositionClass::isSunsetAvailable()
|
||||||
|
{
|
||||||
|
return _isSunsetAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
void SunPositionClass::updateSunData()
|
void SunPositionClass::updateSunData()
|
||||||
{
|
{
|
||||||
CONFIG_T const& config = Configuration.get();
|
CONFIG_T const& config = Configuration.get();
|
||||||
@ -37,7 +42,7 @@ void SunPositionClass::updateSunData()
|
|||||||
|
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
if (!getLocalTime(&timeinfo, 5)) {
|
if (!getLocalTime(&timeinfo, 5)) {
|
||||||
_isDayPeriod = false;
|
_isDayPeriod = true;
|
||||||
_sunriseMinutes = 0;
|
_sunriseMinutes = 0;
|
||||||
_sunsetMinutes = 0;
|
_sunsetMinutes = 0;
|
||||||
_isValidInfo = false;
|
_isValidInfo = false;
|
||||||
@ -45,11 +50,43 @@ void SunPositionClass::updateSunData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_sun.setCurrentDate(1900 + timeinfo.tm_year, timeinfo.tm_mon + 1, timeinfo.tm_mday);
|
_sun.setCurrentDate(1900 + timeinfo.tm_year, timeinfo.tm_mon + 1, timeinfo.tm_mday);
|
||||||
_sunriseMinutes = static_cast<int>(_sun.calcCustomSunrise(SunSet::SUNSET_NAUTICAL));
|
|
||||||
_sunsetMinutes = static_cast<int>(_sun.calcCustomSunset(SunSet::SUNSET_NAUTICAL));
|
double sunset_type;
|
||||||
|
switch (config.Ntp_SunsetType) {
|
||||||
|
case 0:
|
||||||
|
sunset_type = SunSet::SUNSET_OFFICIAL;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sunset_type = SunSet::SUNSET_CIVIL;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sunset_type = SunSet::SUNSET_ASTONOMICAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sunset_type = SunSet::SUNSET_NAUTICAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
double sunriseRaw = _sun.calcCustomSunrise(sunset_type);
|
||||||
|
double sunsetRaw = _sun.calcCustomSunset(sunset_type);
|
||||||
|
|
||||||
|
// If no sunset/sunrise exists (e.g. astronomical calculation in summer)
|
||||||
|
// assume it's day period
|
||||||
|
if (std::isnan(sunriseRaw) || std::isnan(sunsetRaw)) {
|
||||||
|
_isDayPeriod = true;
|
||||||
|
_isSunsetAvailable = false;
|
||||||
|
_sunriseMinutes = 0;
|
||||||
|
_sunsetMinutes = 0;
|
||||||
|
_isValidInfo = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sunriseMinutes = static_cast<int>(sunriseRaw);
|
||||||
|
_sunsetMinutes = static_cast<int>(sunsetRaw);
|
||||||
uint minutesPastMidnight = timeinfo.tm_hour * 60 + timeinfo.tm_min;
|
uint minutesPastMidnight = timeinfo.tm_hour * 60 + timeinfo.tm_min;
|
||||||
|
|
||||||
_isDayPeriod = (minutesPastMidnight >= _sunriseMinutes) && (minutesPastMidnight < _sunsetMinutes);
|
_isDayPeriod = (minutesPastMidnight >= _sunriseMinutes) && (minutesPastMidnight < _sunsetMinutes);
|
||||||
|
_isSunsetAvailable = true;
|
||||||
_isValidInfo = true;
|
_isValidInfo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ void WebApiInverterClass::init(AsyncWebServer* server)
|
|||||||
_server->on("/api/inverter/add", HTTP_POST, std::bind(&WebApiInverterClass::onInverterAdd, this, _1));
|
_server->on("/api/inverter/add", HTTP_POST, std::bind(&WebApiInverterClass::onInverterAdd, this, _1));
|
||||||
_server->on("/api/inverter/edit", HTTP_POST, std::bind(&WebApiInverterClass::onInverterEdit, this, _1));
|
_server->on("/api/inverter/edit", HTTP_POST, std::bind(&WebApiInverterClass::onInverterEdit, this, _1));
|
||||||
_server->on("/api/inverter/del", HTTP_POST, std::bind(&WebApiInverterClass::onInverterDelete, this, _1));
|
_server->on("/api/inverter/del", HTTP_POST, std::bind(&WebApiInverterClass::onInverterDelete, this, _1));
|
||||||
|
_server->on("/api/inverter/order", HTTP_POST, std::bind(&WebApiInverterClass::onInverterOrder, this, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebApiInverterClass::loop()
|
void WebApiInverterClass::loop()
|
||||||
@ -44,6 +45,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
|
|||||||
JsonObject obj = data.createNestedObject();
|
JsonObject obj = data.createNestedObject();
|
||||||
obj["id"] = i;
|
obj["id"] = i;
|
||||||
obj["name"] = String(config.Inverter[i].Name);
|
obj["name"] = String(config.Inverter[i].Name);
|
||||||
|
obj["order"] = config.Inverter[i].Order;
|
||||||
|
|
||||||
// Inverter Serial is read as HEX
|
// Inverter Serial is read as HEX
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
char buffer[sizeof(uint64_t) * 8 + 1];
|
||||||
@ -390,3 +392,72 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
MqttHandleHass.forceUpdate();
|
MqttHandleHass.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request)
|
||||||
|
{
|
||||||
|
if (!WebApi.checkCredentials(request)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
|
JsonObject retMsg = response->getRoot();
|
||||||
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
|
if (!request->hasParam("data", true)) {
|
||||||
|
retMsg["message"] = "No values found!";
|
||||||
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
|
if (json.length() > 1024) {
|
||||||
|
retMsg["message"] = "Data too large!";
|
||||||
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicJsonDocument root(1024);
|
||||||
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
retMsg["message"] = "Failed to parse data!";
|
||||||
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(root.containsKey("order"))) {
|
||||||
|
retMsg["message"] = "Values are missing!";
|
||||||
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The order array contains list or id in the right order
|
||||||
|
JsonArray orderArray = root["order"].as<JsonArray>();
|
||||||
|
uint8_t order = 0;
|
||||||
|
for(JsonVariant id : orderArray) {
|
||||||
|
uint8_t inverter_id = id.as<uint8_t>();
|
||||||
|
if (inverter_id < INV_MAX_COUNT) {
|
||||||
|
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[inverter_id];
|
||||||
|
inverter.Order = order;
|
||||||
|
}
|
||||||
|
order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration.write();
|
||||||
|
|
||||||
|
retMsg["type"] = "success";
|
||||||
|
retMsg["message"] = "Inverter order saved!";
|
||||||
|
retMsg["code"] = WebApiError::InverterOrdered;
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
@ -52,14 +52,21 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
|
|||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
||||||
root["ntp_localtime"] = timeStringBuff;
|
root["ntp_localtime"] = timeStringBuff;
|
||||||
|
|
||||||
SunPosition.sunriseTime(&timeinfo);
|
if (SunPosition.sunriseTime(&timeinfo)) {
|
||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
||||||
|
} else {
|
||||||
|
strcpy(timeStringBuff, "--");
|
||||||
|
}
|
||||||
root["sun_risetime"] = timeStringBuff;
|
root["sun_risetime"] = timeStringBuff;
|
||||||
|
|
||||||
SunPosition.sunsetTime(&timeinfo);
|
if (SunPosition.sunsetTime(&timeinfo)) {
|
||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
||||||
|
} else {
|
||||||
|
strcpy(timeStringBuff, "--");
|
||||||
|
}
|
||||||
root["sun_settime"] = timeStringBuff;
|
root["sun_settime"] = timeStringBuff;
|
||||||
|
|
||||||
|
root["sun_isSunsetAvailable"] = SunPosition.isSunsetAvailable();
|
||||||
root["sun_isDayPeriod"] = SunPosition.isDayPeriod();
|
root["sun_isDayPeriod"] = SunPosition.isDayPeriod();
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
@ -81,6 +88,7 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request)
|
|||||||
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
|
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
|
||||||
root["longitude"] = config.Ntp_Longitude;
|
root["longitude"] = config.Ntp_Longitude;
|
||||||
root["latitude"] = config.Ntp_Latitude;
|
root["latitude"] = config.Ntp_Latitude;
|
||||||
|
root["sunsettype"] = config.Ntp_SunsetType;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -125,7 +133,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude"))) {
|
if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude") && root.containsKey("sunsettype"))) {
|
||||||
retMsg["message"] = "Values are missing!";
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg["code"] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
@ -166,6 +174,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
|
|||||||
strlcpy(config.Ntp_TimezoneDescr, root["ntp_timezone_descr"].as<String>().c_str(), sizeof(config.Ntp_TimezoneDescr));
|
strlcpy(config.Ntp_TimezoneDescr, root["ntp_timezone_descr"].as<String>().c_str(), sizeof(config.Ntp_TimezoneDescr));
|
||||||
config.Ntp_Latitude = root["latitude"].as<double>();
|
config.Ntp_Latitude = root["latitude"].as<double>();
|
||||||
config.Ntp_Longitude = root["longitude"].as<double>();
|
config.Ntp_Longitude = root["longitude"].as<double>();
|
||||||
|
config.Ntp_SunsetType = root["sunsettype"].as<uint8_t>();
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg["type"] = "success";
|
retMsg["type"] = "success";
|
||||||
|
|||||||
@ -105,9 +105,14 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonObject invObject = invArray.createNestedObject();
|
JsonObject invObject = invArray.createNestedObject();
|
||||||
|
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||||
|
if (inv_cfg == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
invObject["serial"] = inv->serialString();
|
invObject["serial"] = inv->serialString();
|
||||||
invObject["name"] = inv->name();
|
invObject["name"] = inv->name();
|
||||||
|
invObject["order"] = inv_cfg->Order;
|
||||||
invObject["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
invObject["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
||||||
invObject["poll_enabled"] = inv->getEnablePolling();
|
invObject["poll_enabled"] = inv->getEnablePolling();
|
||||||
invObject["reachable"] = inv->isReachable();
|
invObject["reachable"] = inv->isReachable();
|
||||||
@ -124,10 +129,7 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
JsonObject chanTypeObj = invObject.createNestedObject(inv->Statistics()->getChannelTypeName(t));
|
JsonObject chanTypeObj = invObject.createNestedObject(inv->Statistics()->getChannelTypeName(t));
|
||||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||||
if (t == TYPE_DC) {
|
if (t == TYPE_DC) {
|
||||||
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
chanTypeObj[String(static_cast<uint8_t>(c))]["name"]["u"] = inv_cfg->channel[c].Name;
|
||||||
if (inv_cfg != nullptr) {
|
|
||||||
chanTypeObj[String(static_cast<uint8_t>(c))]["name"]["u"] = inv_cfg->channel[c].Name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addField(chanTypeObj, i, inv, t, c, FLD_PAC);
|
addField(chanTypeObj, i, inv, t, c, FLD_PAC);
|
||||||
addField(chanTypeObj, i, inv, t, c, FLD_UAC);
|
addField(chanTypeObj, i, inv, t, c, FLD_UAC);
|
||||||
@ -164,9 +166,9 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonObject totalObj = root.createNestedObject("total");
|
JsonObject totalObj = root.createNestedObject("total");
|
||||||
addTotalField(totalObj, "Power", Datastore.totalAcPowerEnabled, "W", Datastore.totalAcPowerDigits);
|
addTotalField(totalObj, "Power", Datastore.getTotalAcPowerEnabled(), "W", Datastore.getTotalAcPowerDigits());
|
||||||
addTotalField(totalObj, "YieldDay", Datastore.totalAcYieldDayEnabled, "Wh", Datastore.totalAcYieldDayDigits);
|
addTotalField(totalObj, "YieldDay", Datastore.getTotalAcYieldDayEnabled(), "Wh", Datastore.getTotalAcYieldDayDigits());
|
||||||
addTotalField(totalObj, "YieldTotal", Datastore.totalAcYieldTotalEnabled, "kWh", Datastore.totalAcYieldTotalDigits);
|
addTotalField(totalObj, "YieldTotal", Datastore.getTotalAcYieldTotalEnabled(), "kWh", Datastore.getTotalAcYieldTotalDigits());
|
||||||
|
|
||||||
JsonObject hintObj = root.createNestedObject("hints");
|
JsonObject hintObj = root.createNestedObject("hints");
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
|
|||||||
@ -11,32 +11,34 @@
|
|||||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.11.7",
|
"@popperjs/core": "^2.11.8",
|
||||||
"bootstrap": "^5.3.0-alpha3",
|
"bootstrap": "^5.3.0",
|
||||||
"bootstrap-icons-vue": "^1.10.3",
|
"bootstrap-icons-vue": "^1.10.3",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
|
"sortablejs": "^1.15.0",
|
||||||
"spark-md5": "^3.0.2",
|
"spark-md5": "^3.0.2",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.2.1"
|
"vue-router": "^4.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^0.10.0",
|
"@intlify/unplugin-vue-i18n": "^0.11.0",
|
||||||
"@rushstack/eslint-patch": "^1.3.0",
|
"@rushstack/eslint-patch": "^1.3.0",
|
||||||
"@tsconfig/node18": "^2.0.1",
|
"@tsconfig/node18": "^2.0.1",
|
||||||
"@types/bootstrap": "^5.2.6",
|
"@types/bootstrap": "^5.2.6",
|
||||||
"@types/node": "^20.2.3",
|
"@types/node": "^20.2.5",
|
||||||
|
"@types/sortablejs": "^1.15.1",
|
||||||
"@types/spark-md5": "^3.0.2",
|
"@types/spark-md5": "^3.0.2",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"@vue/eslint-config-typescript": "^11.0.3",
|
"@vue/eslint-config-typescript": "^11.0.3",
|
||||||
"@vue/tsconfig": "^0.4.0",
|
"@vue/tsconfig": "^0.4.0",
|
||||||
"eslint": "^8.41.0",
|
"eslint": "^8.41.0",
|
||||||
"eslint-plugin-vue": "^9.14.0",
|
"eslint-plugin-vue": "^9.14.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"sass": "^1.62.1",
|
"sass": "^1.62.1",
|
||||||
"terser": "^5.17.6",
|
"terser": "^5.17.7",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.1.3",
|
||||||
"vite": "^4.3.8",
|
"vite": "^4.3.9",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-css-injected-by-js": "^3.1.1",
|
"vite-plugin-css-injected-by-js": "^3.1.1",
|
||||||
"vue-tsc": "^1.6.5"
|
"vue-tsc": "^1.6.5"
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
"4006": "Ungültige Anzahl an Kanalwerten übergeben!",
|
"4006": "Ungültige Anzahl an Kanalwerten übergeben!",
|
||||||
"4007": "Wechselrichter geändert!",
|
"4007": "Wechselrichter geändert!",
|
||||||
"4008": "Wechselrichter gelöscht!",
|
"4008": "Wechselrichter gelöscht!",
|
||||||
|
"4009": "Wechselrichter Reihenfolge gespeichert!",
|
||||||
"5001": "@:apiresponse.2001",
|
"5001": "@:apiresponse.2001",
|
||||||
"5002": "Das Limit muss zwischen 1 und {max} sein!",
|
"5002": "Das Limit muss zwischen 1 und {max} sein!",
|
||||||
"5003": "Ungültiten Typ angegeben!",
|
"5003": "Ungültiten Typ angegeben!",
|
||||||
@ -276,8 +277,9 @@
|
|||||||
"Synced": "synchronisiert",
|
"Synced": "synchronisiert",
|
||||||
"NotSynced": "nicht synchronisiert",
|
"NotSynced": "nicht synchronisiert",
|
||||||
"LocalTime": "Lokale Uhrzeit",
|
"LocalTime": "Lokale Uhrzeit",
|
||||||
"Sunrise": "Nautische Morgendämmerung",
|
"Sunrise": "Morgendämmerung",
|
||||||
"Sunset": "Nautische Abenddämmerung",
|
"Sunset": "Abenddämmerung",
|
||||||
|
"NotAvailable": "Nicht verfügbar",
|
||||||
"Mode": "Modus",
|
"Mode": "Modus",
|
||||||
"Day": "Tag",
|
"Day": "Tag",
|
||||||
"Night": "Nacht"
|
"Night": "Nacht"
|
||||||
@ -408,6 +410,12 @@
|
|||||||
"LocationConfiguration": "Standortkonfiguration",
|
"LocationConfiguration": "Standortkonfiguration",
|
||||||
"Longitude": "Längengrad:",
|
"Longitude": "Längengrad:",
|
||||||
"Latitude": "Breitengrad:",
|
"Latitude": "Breitengrad:",
|
||||||
|
"SunSetType": "Dämmerungstyp:",
|
||||||
|
"SunSetTypeHint": "Beeinflusst die Tag/Nacht Berechnung. Es kann bis zu einer Minute dauern bis der neue Typ angewendet wurde.",
|
||||||
|
"OFFICIAL": "Standard Dämmerung (90.8°)",
|
||||||
|
"NAUTICAL": "Nautische Dämmerung (102°)",
|
||||||
|
"CIVIL": "Bürgerliche Dämmerung (96°)",
|
||||||
|
"ASTONOMICAL": "Astronomische Dämmerung (108°)",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"ManualTimeSynchronization": "Manuelle Zeitsynchronization",
|
"ManualTimeSynchronization": "Manuelle Zeitsynchronization",
|
||||||
"CurrentOpenDtuTime": "Aktuelle OpenDTU-Zeit:",
|
"CurrentOpenDtuTime": "Aktuelle OpenDTU-Zeit:",
|
||||||
@ -564,6 +572,7 @@
|
|||||||
"StatusHint": "<b>Hinweis:</b> Der Wechselrichter wird über seinen DC-Eingang mit Strom versorgt. Wenn keine Sonne scheint, ist der Wechselrichter aus. Es können trotzdem Anfragen gesendet werden.",
|
"StatusHint": "<b>Hinweis:</b> Der Wechselrichter wird über seinen DC-Eingang mit Strom versorgt. Wenn keine Sonne scheint, ist der Wechselrichter aus. Es können trotzdem Anfragen gesendet werden.",
|
||||||
"Type": "Typ",
|
"Type": "Typ",
|
||||||
"Action": "Aktion",
|
"Action": "Aktion",
|
||||||
|
"SaveOrder": "Reihenfolge speichern",
|
||||||
"DeleteInverter": "Wechselrichter löschen",
|
"DeleteInverter": "Wechselrichter löschen",
|
||||||
"EditInverter": "Wechselrichter bearbeiten",
|
"EditInverter": "Wechselrichter bearbeiten",
|
||||||
"InverterSerial": "Wechselrichter Seriennummer:",
|
"InverterSerial": "Wechselrichter Seriennummer:",
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
"4006": "Invalid amount of max channel setting given!",
|
"4006": "Invalid amount of max channel setting given!",
|
||||||
"4007": "Inverter changed!",
|
"4007": "Inverter changed!",
|
||||||
"4008": "Inverter deleted!",
|
"4008": "Inverter deleted!",
|
||||||
|
"4009": "Inverter order saved!",
|
||||||
"5001": "@:apiresponse.2001",
|
"5001": "@:apiresponse.2001",
|
||||||
"5002": "Limit must between 1 and {max}!",
|
"5002": "Limit must between 1 and {max}!",
|
||||||
"5003": "Invalid type specified!",
|
"5003": "Invalid type specified!",
|
||||||
@ -276,8 +277,9 @@
|
|||||||
"Synced": "synced",
|
"Synced": "synced",
|
||||||
"NotSynced": "not synced",
|
"NotSynced": "not synced",
|
||||||
"LocalTime": "Local Time",
|
"LocalTime": "Local Time",
|
||||||
"Sunrise": "Nautical Sunrise",
|
"Sunrise": "Sunrise",
|
||||||
"Sunset": "Nautical Sunset",
|
"Sunset": "Sunset",
|
||||||
|
"NotAvailable": "Not Available",
|
||||||
"Mode": "Mode",
|
"Mode": "Mode",
|
||||||
"Day": "Day",
|
"Day": "Day",
|
||||||
"Night": "Night"
|
"Night": "Night"
|
||||||
@ -408,6 +410,12 @@
|
|||||||
"LocationConfiguration": "Location Configuration",
|
"LocationConfiguration": "Location Configuration",
|
||||||
"Longitude": "Longitude",
|
"Longitude": "Longitude",
|
||||||
"Latitude": "Latitude",
|
"Latitude": "Latitude",
|
||||||
|
"SunSetType": "Sunset type",
|
||||||
|
"SunSetTypeHint": "Affects the day/night calculation. It can take up to one minute until the new type will be applied.",
|
||||||
|
"OFFICIAL": "Standard dawn (90.8°)",
|
||||||
|
"NAUTICAL": "Nautical dawn (102°)",
|
||||||
|
"CIVIL": "Civil dawn (96°)",
|
||||||
|
"ASTONOMICAL": "Astronomical dawn (108°)",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"ManualTimeSynchronization": "Manual Time Synchronization",
|
"ManualTimeSynchronization": "Manual Time Synchronization",
|
||||||
"CurrentOpenDtuTime": "Current OpenDTU Time:",
|
"CurrentOpenDtuTime": "Current OpenDTU Time:",
|
||||||
@ -568,6 +576,7 @@
|
|||||||
"StatusHint": "<b>Hint:</b> The inverter is powered by its DC input. If there is no sun, the inverter is off. Requests can still be sent.",
|
"StatusHint": "<b>Hint:</b> The inverter is powered by its DC input. If there is no sun, the inverter is off. Requests can still be sent.",
|
||||||
"Type": "Type",
|
"Type": "Type",
|
||||||
"Action": "Action",
|
"Action": "Action",
|
||||||
|
"SaveOrder": "Save order",
|
||||||
"DeleteInverter": "Delete inverter",
|
"DeleteInverter": "Delete inverter",
|
||||||
"EditInverter": "Edit inverter",
|
"EditInverter": "Edit inverter",
|
||||||
"InverterSerial": "Inverter Serial:",
|
"InverterSerial": "Inverter Serial:",
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
"4006": "Réglage du montant maximal de canaux invalide !",
|
"4006": "Réglage du montant maximal de canaux invalide !",
|
||||||
"4007": "Onduleur modifié !",
|
"4007": "Onduleur modifié !",
|
||||||
"4008": "Onduleur supprimé !",
|
"4008": "Onduleur supprimé !",
|
||||||
|
"4009": "Inverter order saved!",
|
||||||
"5001": "@:apiresponse.2001",
|
"5001": "@:apiresponse.2001",
|
||||||
"5002": "La limite doit être comprise entre 1 et {max} !",
|
"5002": "La limite doit être comprise entre 1 et {max} !",
|
||||||
"5003": "Type spécifié invalide !",
|
"5003": "Type spécifié invalide !",
|
||||||
@ -275,8 +276,9 @@
|
|||||||
"Synced": "synchronisée",
|
"Synced": "synchronisée",
|
||||||
"NotSynced": "pas synchronisée",
|
"NotSynced": "pas synchronisée",
|
||||||
"LocalTime": "Heure locale",
|
"LocalTime": "Heure locale",
|
||||||
"Sunrise": "Nautical Sunrise",
|
"Sunrise": "Sunrise",
|
||||||
"Sunset": "Nautical Sunset",
|
"Sunset": "Sunset",
|
||||||
|
"NotAvailable": "Not Available",
|
||||||
"Mode": "Mode",
|
"Mode": "Mode",
|
||||||
"Day": "Day",
|
"Day": "Day",
|
||||||
"Night": "Night"
|
"Night": "Night"
|
||||||
@ -407,6 +409,12 @@
|
|||||||
"LocationConfiguration": "Géolocalisation",
|
"LocationConfiguration": "Géolocalisation",
|
||||||
"Longitude": "Longitude",
|
"Longitude": "Longitude",
|
||||||
"Latitude": "Latitude",
|
"Latitude": "Latitude",
|
||||||
|
"SunSetType": "Sunset type",
|
||||||
|
"SunSetTypeHint": "Affects the day/night calculation. It can take up to one minute until the new type will be applied.",
|
||||||
|
"OFFICIAL": "Standard dawn (90.8°)",
|
||||||
|
"NAUTICAL": "Nautical dawn (102°)",
|
||||||
|
"CIVIL": "Civil dawn (96°)",
|
||||||
|
"ASTONOMICAL": "Astronomical dawn (108°)",
|
||||||
"Save": "@:dtuadmin.Save",
|
"Save": "@:dtuadmin.Save",
|
||||||
"ManualTimeSynchronization": "Synchronisation manuelle de l'heure",
|
"ManualTimeSynchronization": "Synchronisation manuelle de l'heure",
|
||||||
"CurrentOpenDtuTime": "Heure actuelle de l'OpenDTU",
|
"CurrentOpenDtuTime": "Heure actuelle de l'OpenDTU",
|
||||||
@ -491,6 +499,7 @@
|
|||||||
"StatusHint": "<b>Astuce :</b> L'onduleur est alimenté par son entrée courant continu. S'il n'y a pas de soleil, l'onduleur est éteint, mais les requêtes peuvent toujours être envoyées.",
|
"StatusHint": "<b>Astuce :</b> L'onduleur est alimenté par son entrée courant continu. S'il n'y a pas de soleil, l'onduleur est éteint, mais les requêtes peuvent toujours être envoyées.",
|
||||||
"Type": "Type",
|
"Type": "Type",
|
||||||
"Action": "Action",
|
"Action": "Action",
|
||||||
|
"SaveOrder": "Save order",
|
||||||
"DeleteInverter": "Supprimer l'onduleur",
|
"DeleteInverter": "Supprimer l'onduleur",
|
||||||
"EditInverter": "Modifier l'onduleur",
|
"EditInverter": "Modifier l'onduleur",
|
||||||
"InverterSerial": "Numéro de série de l'onduleur",
|
"InverterSerial": "Numéro de série de l'onduleur",
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export interface InverterStatistics {
|
|||||||
export interface Inverter {
|
export interface Inverter {
|
||||||
serial: number;
|
serial: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
order: number;
|
||||||
data_age: number;
|
data_age: number;
|
||||||
poll_enabled: boolean;
|
poll_enabled: boolean;
|
||||||
reachable: boolean;
|
reachable: boolean;
|
||||||
|
|||||||
@ -4,4 +4,5 @@ export interface NtpConfig {
|
|||||||
ntp_timezone_descr: string;
|
ntp_timezone_descr: string;
|
||||||
latitude: number;
|
latitude: number;
|
||||||
longitude: number;
|
longitude: number;
|
||||||
|
sunsettype: number;
|
||||||
}
|
}
|
||||||
@ -7,4 +7,5 @@ export interface NtpStatus {
|
|||||||
sun_risetime: string;
|
sun_risetime: string;
|
||||||
sun_settime: string;
|
sun_settime: string;
|
||||||
sun_isDayPeriod: boolean;
|
sun_isDayPeriod: boolean;
|
||||||
|
sun_isSunsetAvailable: boolean;
|
||||||
}
|
}
|
||||||
@ -470,7 +470,9 @@ export default defineComponent({
|
|||||||
'decimalTwoDigits');
|
'decimalTwoDigits');
|
||||||
},
|
},
|
||||||
inverterData(): Inverter[] {
|
inverterData(): Inverter[] {
|
||||||
return this.liveData.inverters;
|
return this.liveData.inverters.slice().sort((a : Inverter, b: Inverter) => {
|
||||||
|
return a.order - b.order;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
<th scope="col">{{ $t('inverteradmin.Status') }}</th>
|
<th scope="col">{{ $t('inverteradmin.Status') }}</th>
|
||||||
<th>{{ $t('inverteradmin.Serial') }}</th>
|
<th>{{ $t('inverteradmin.Serial') }}</th>
|
||||||
<th>{{ $t('inverteradmin.Name') }}</th>
|
<th>{{ $t('inverteradmin.Name') }}</th>
|
||||||
@ -35,8 +36,9 @@
|
|||||||
<th>{{ $t('inverteradmin.Action') }}</th>
|
<th>{{ $t('inverteradmin.Action') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody ref="invList">
|
||||||
<tr v-for="inverter in sortedInverters" v-bind:key="inverter.id">
|
<tr v-for="inverter in inverters" v-bind:key="inverter.id" :data-id="inverter.id">
|
||||||
|
<td><BIconGripHorizontal class="drag-handle" /></td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge" :title="$t('inverteradmin.Receive')" :class="{
|
<span class="badge" :title="$t('inverteradmin.Receive')" :class="{
|
||||||
'text-bg-warning': !inverter.poll_enable_night,
|
'text-bg-warning': !inverter.poll_enable_night,
|
||||||
@ -63,6 +65,9 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ml-auto text-right">
|
||||||
|
<button class="btn btn-primary my-2" @click="onSaveOrder()">{{ $t('inverteradmin.SaveOrder') }}</button>
|
||||||
|
</div>
|
||||||
</CardElement>
|
</CardElement>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|
||||||
@ -197,6 +202,7 @@ import BasePage from '@/components/BasePage.vue';
|
|||||||
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
||||||
import CardElement from '@/components/CardElement.vue';
|
import CardElement from '@/components/CardElement.vue';
|
||||||
import InputElement from '@/components/InputElement.vue';
|
import InputElement from '@/components/InputElement.vue';
|
||||||
|
import Sortable from 'sortablejs';
|
||||||
import { authHeader, handleResponse } from '@/utils/authentication';
|
import { authHeader, handleResponse } from '@/utils/authentication';
|
||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
import {
|
import {
|
||||||
@ -205,6 +211,7 @@ import {
|
|||||||
BIconTrash,
|
BIconTrash,
|
||||||
BIconArrowDown,
|
BIconArrowDown,
|
||||||
BIconArrowUp,
|
BIconArrowUp,
|
||||||
|
BIconGripHorizontal,
|
||||||
} from 'bootstrap-icons-vue';
|
} from 'bootstrap-icons-vue';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
@ -219,6 +226,7 @@ declare interface Inverter {
|
|||||||
serial: number;
|
serial: number;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
order: number;
|
||||||
poll_enable: boolean;
|
poll_enable: boolean;
|
||||||
poll_enable_night: boolean;
|
poll_enable_night: boolean;
|
||||||
command_enable: boolean;
|
command_enable: boolean;
|
||||||
@ -244,6 +252,7 @@ export default defineComponent({
|
|||||||
BIconTrash,
|
BIconTrash,
|
||||||
BIconArrowDown,
|
BIconArrowDown,
|
||||||
BIconArrowUp,
|
BIconArrowUp,
|
||||||
|
BIconGripHorizontal,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -253,7 +262,8 @@ export default defineComponent({
|
|||||||
selectedInverterData: {} as Inverter,
|
selectedInverterData: {} as Inverter,
|
||||||
inverters: [] as Inverter[],
|
inverters: [] as Inverter[],
|
||||||
dataLoading: true,
|
dataLoading: true,
|
||||||
alert: {} as AlertResponse
|
alert: {} as AlertResponse,
|
||||||
|
sortable: {} as Sortable,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -263,21 +273,27 @@ export default defineComponent({
|
|||||||
created() {
|
created() {
|
||||||
this.getInverters();
|
this.getInverters();
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
sortedInverters(): Inverter[] {
|
|
||||||
return this.inverters.slice().sort((a, b) => {
|
|
||||||
return a.serial - b.serial;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
getInverters() {
|
getInverters() {
|
||||||
this.dataLoading = true;
|
this.dataLoading = true;
|
||||||
fetch("/api/inverter/list", { headers: authHeader() })
|
fetch("/api/inverter/list", { headers: authHeader() })
|
||||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.inverters = data.inverter;
|
this.inverters = data.inverter.slice().sort((a : Inverter, b: Inverter) => {
|
||||||
|
return a.order - b.order;
|
||||||
|
});
|
||||||
this.dataLoading = false;
|
this.dataLoading = false;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const table = this.$refs.invList as HTMLElement;
|
||||||
|
|
||||||
|
this.sortable = Sortable.create(table, {
|
||||||
|
sort: true,
|
||||||
|
handle: '.drag-handle',
|
||||||
|
animation: 150,
|
||||||
|
draggable: 'tr',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
callInverterApiEndpoint(endpoint: string, jsonData: string) {
|
callInverterApiEndpoint(endpoint: string, jsonData: string) {
|
||||||
@ -316,7 +332,16 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
onCloseModal(modal: bootstrap.Modal) {
|
onCloseModal(modal: bootstrap.Modal) {
|
||||||
modal.hide();
|
modal.hide();
|
||||||
}
|
},
|
||||||
|
onSaveOrder() {
|
||||||
|
this.callInverterApiEndpoint("order", JSON.stringify({ order: this.sortable.toArray() }));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.drag-handle {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -36,6 +36,21 @@
|
|||||||
<InputElement :label="$t('ntpadmin.Longitude')"
|
<InputElement :label="$t('ntpadmin.Longitude')"
|
||||||
v-model="ntpConfigList.longitude"
|
v-model="ntpConfigList.longitude"
|
||||||
type="number" min="-180" max="180" step="any"/>
|
type="number" min="-180" max="180" step="any"/>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label class="col-sm-2 col-form-label">
|
||||||
|
{{ $t('ntpadmin.SunSetType') }}
|
||||||
|
<BIconInfoCircle v-tooltip :title="$t('ntpadmin.SunSetTypeHint')" />
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-select" v-model="ntpConfigList.sunsettype">
|
||||||
|
<option v-for="sunsettype in sunsetTypeList" :key="sunsettype.key" :value="sunsettype.key">
|
||||||
|
{{ $t(`ntpadmin.` + sunsettype.value) }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</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>
|
||||||
@ -67,6 +82,7 @@ import InputElement from '@/components/InputElement.vue';
|
|||||||
import type { NtpConfig } from "@/types/NtpConfig";
|
import type { NtpConfig } from "@/types/NtpConfig";
|
||||||
import { authHeader, handleResponse } from '@/utils/authentication';
|
import { authHeader, handleResponse } from '@/utils/authentication';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import { BIconInfoCircle } from 'bootstrap-icons-vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -74,6 +90,7 @@ export default defineComponent({
|
|||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
CardElement,
|
CardElement,
|
||||||
InputElement,
|
InputElement,
|
||||||
|
BIconInfoCircle,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -88,6 +105,12 @@ export default defineComponent({
|
|||||||
alertMessage: "",
|
alertMessage: "",
|
||||||
alertType: "info",
|
alertType: "info",
|
||||||
showAlert: false,
|
showAlert: false,
|
||||||
|
sunsetTypeList: [
|
||||||
|
{ key: 0, value: 'OFFICIAL' },
|
||||||
|
{ key: 1, value: 'NAUTICAL' },
|
||||||
|
{ key: 2, value: 'CIVIL' },
|
||||||
|
{ key: 3, value: 'ASTONOMICAL' },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@ -38,11 +38,13 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t('ntpinfo.Sunrise') }}</th>
|
<th>{{ $t('ntpinfo.Sunrise') }}</th>
|
||||||
<td>{{ ntpDataList.sun_risetime }}</td>
|
<td v-if="ntpDataList.sun_isSunsetAvailable">{{ ntpDataList.sun_risetime }}</td>
|
||||||
|
<td v-else>{{ $t('ntpinfo.NotAvailable') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t('ntpinfo.Sunset') }}</th>
|
<th>{{ $t('ntpinfo.Sunset') }}</th>
|
||||||
<td>{{ ntpDataList.sun_settime }}</td>
|
<td v-if="ntpDataList.sun_isSunsetAvailable">{{ ntpDataList.sun_settime }}</td>
|
||||||
|
<td v-else>{{ $t('ntpinfo.NotAvailable') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t('ntpinfo.Mode') }}</th>
|
<th>{{ $t('ntpinfo.Mode') }}</th>
|
||||||
|
|||||||
146
webapp/yarn.lock
146
webapp/yarn.lock
@ -180,10 +180,10 @@
|
|||||||
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@^5.4.0":
|
"@intlify/bundle-utils@^6.0.1":
|
||||||
version "5.4.0"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@intlify/bundle-utils/-/bundle-utils-5.4.0.tgz#12d1e2316a52cdf4818f5f183dc2726da35886c0"
|
resolved "https://registry.yarnpkg.com/@intlify/bundle-utils/-/bundle-utils-6.0.1.tgz#889ef90a07f54d3285082f1fff99be06db49c65f"
|
||||||
integrity sha512-oJbibbP5djdQYTv0cQC4PYRHPpS5nF/KZ7MWM1/yhdsGzjvCekJHWk25MCQIIOrfQ+aw5tKi2t66KpYEUki/tw==
|
integrity sha512-BkeZNKZiC0B7K3OYMwiPLoAqsZmKH3SxTL75vYAkuQ//XWR8WO0NpfjXhTxgLTVFHxMcNb2agAopC0DP6fqDrg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/message-compiler" "9.3.0-beta.17"
|
"@intlify/message-compiler" "9.3.0-beta.17"
|
||||||
"@intlify/shared" "9.3.0-beta.17"
|
"@intlify/shared" "9.3.0-beta.17"
|
||||||
@ -192,6 +192,7 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
jsonc-eslint-parser "^1.0.1"
|
jsonc-eslint-parser "^1.0.1"
|
||||||
magic-string "^0.30.0"
|
magic-string "^0.30.0"
|
||||||
|
mlly "^1.2.0"
|
||||||
source-map "0.6.1"
|
source-map "0.6.1"
|
||||||
yaml-eslint-parser "^0.3.2"
|
yaml-eslint-parser "^0.3.2"
|
||||||
|
|
||||||
@ -238,12 +239,12 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.17.tgz#1180dcb0b30741555fad0b62e4621802e8272ee5"
|
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.3.0-beta.17.tgz#1180dcb0b30741555fad0b62e4621802e8272ee5"
|
||||||
integrity sha512-mscf7RQsUTOil35jTij4KGW1RC9SWQjYScwLxP53Ns6g24iEd5HN7ksbt9O6FvTmlQuX77u+MXpBdfJsGqizLQ==
|
integrity sha512-mscf7RQsUTOil35jTij4KGW1RC9SWQjYScwLxP53Ns6g24iEd5HN7ksbt9O6FvTmlQuX77u+MXpBdfJsGqizLQ==
|
||||||
|
|
||||||
"@intlify/unplugin-vue-i18n@^0.10.0":
|
"@intlify/unplugin-vue-i18n@^0.11.0":
|
||||||
version "0.10.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.10.0.tgz#28a05a7b9e0a7cc35e91e6762e5e6e57f954a45c"
|
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.11.0.tgz#43d2730d86ceb214e7e147b0cc8f78f7d7df0707"
|
||||||
integrity sha512-Sf8fe26/d8rBNcg+zBSb7RA1uyhrG9zhIM+CRX6lqcznMDjLRr/1tuVaJ9E6xqJkzjfPgRzNcCqwMt6rpNkL7Q==
|
integrity sha512-ivcLZo08fvepHWV8o5lcKfhcKFSWqhwrqIAU6pUIbvq2ICo9fnXnIPYIZj7FeuHDLW1G3ADm44ZhQC3nYmvDlg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/bundle-utils" "^5.4.0"
|
"@intlify/bundle-utils" "^6.0.1"
|
||||||
"@intlify/shared" "9.3.0-beta.17"
|
"@intlify/shared" "9.3.0-beta.17"
|
||||||
"@rollup/pluginutils" "^5.0.2"
|
"@rollup/pluginutils" "^5.0.2"
|
||||||
"@vue/compiler-sfc" "^3.2.47"
|
"@vue/compiler-sfc" "^3.2.47"
|
||||||
@ -283,10 +284,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||||
|
|
||||||
"@jridgewell/source-map@^0.3.2":
|
"@jridgewell/source-map@^0.3.3":
|
||||||
version "0.3.2"
|
version "0.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda"
|
||||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/gen-mapping" "^0.3.0"
|
"@jridgewell/gen-mapping" "^0.3.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
@ -325,10 +326,10 @@
|
|||||||
"@nodelib/fs.scandir" "2.1.5"
|
"@nodelib/fs.scandir" "2.1.5"
|
||||||
fastq "^1.6.0"
|
fastq "^1.6.0"
|
||||||
|
|
||||||
"@popperjs/core@^2.11.7":
|
"@popperjs/core@^2.11.8":
|
||||||
version "2.11.7"
|
version "2.11.8"
|
||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||||
integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
|
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||||
|
|
||||||
"@popperjs/core@^2.9.2":
|
"@popperjs/core@^2.9.2":
|
||||||
version "2.11.5"
|
version "2.11.5"
|
||||||
@ -371,16 +372,21 @@
|
|||||||
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@^20.2.3":
|
"@types/node@^20.2.5":
|
||||||
version "20.2.3"
|
version "20.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.3.tgz#b31eb300610c3835ac008d690de6f87e28f9b878"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb"
|
||||||
integrity sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==
|
integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==
|
||||||
|
|
||||||
"@types/semver@^7.3.12":
|
"@types/semver@^7.3.12":
|
||||||
version "7.3.13"
|
version "7.3.13"
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
|
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
|
||||||
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
|
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
|
||||||
|
|
||||||
|
"@types/sortablejs@^1.15.1":
|
||||||
|
version "1.15.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.15.1.tgz#123abafbe936f754fee5eb5b49009ce1f1075aa5"
|
||||||
|
integrity sha512-g/JwBNToh6oCTAwNS8UGVmjO7NLDKsejVhvE4x1eWiPTC3uCuNsa/TD4ssvX3du+MLiM+SHPNDuijp8y76JzLQ==
|
||||||
|
|
||||||
"@types/spark-md5@^3.0.2":
|
"@types/spark-md5@^3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/spark-md5/-/spark-md5-3.0.2.tgz#da2e8a778a20335fc4f40b6471c4b0d86b70da55"
|
resolved "https://registry.yarnpkg.com/@types/spark-md5/-/spark-md5-3.0.2.tgz#da2e8a778a20335fc4f40b6471c4b0d86b70da55"
|
||||||
@ -766,16 +772,16 @@ acorn@^7.1.1, acorn@^7.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||||
|
|
||||||
acorn@^8.5.0, acorn@^8.8.2:
|
|
||||||
version "8.8.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
|
||||||
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
|
||||||
|
|
||||||
acorn@^8.8.0:
|
acorn@^8.8.0:
|
||||||
version "8.8.0"
|
version "8.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
|
||||||
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
|
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
|
||||||
|
|
||||||
|
acorn@^8.8.2:
|
||||||
|
version "8.8.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
|
||||||
|
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
|
||||||
|
|
||||||
ajv@^6.10.0, ajv@^6.12.4:
|
ajv@^6.10.0, ajv@^6.12.4:
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||||
@ -843,10 +849,10 @@ bootstrap-icons-vue@^1.10.3:
|
|||||||
resolved "https://registry.yarnpkg.com/bootstrap-icons-vue/-/bootstrap-icons-vue-1.10.3.tgz#ae725513c9655ce86effa2a0b09e9e65b02c8f1a"
|
resolved "https://registry.yarnpkg.com/bootstrap-icons-vue/-/bootstrap-icons-vue-1.10.3.tgz#ae725513c9655ce86effa2a0b09e9e65b02c8f1a"
|
||||||
integrity sha512-BzqmLufgHjFvSReJ1GQqNkl780UFK0rWT4Y1IQC7lZClXyOSsM5Ipw04BnuVmmrqgtSxzak83jcBwLJgCK3scg==
|
integrity sha512-BzqmLufgHjFvSReJ1GQqNkl780UFK0rWT4Y1IQC7lZClXyOSsM5Ipw04BnuVmmrqgtSxzak83jcBwLJgCK3scg==
|
||||||
|
|
||||||
bootstrap@^5.3.0-alpha3:
|
bootstrap@^5.3.0:
|
||||||
version "5.3.0-alpha3"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.0-alpha3.tgz#ad64d9a663c53ab7aca99c560e0bd16b5e023441"
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.0.tgz#0718a7cc29040ee8dbf1bd652b896f3436a87c29"
|
||||||
integrity sha512-FBhOWMxkCFr74hesJdchLXhqagPTXS+kRNU3gE0FR5Ki/AdPSz32Ik96Z28+yBluCnE/pc9st7l1yPwKgbtfSA==
|
integrity sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw==
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
@ -1119,10 +1125,10 @@ escodegen@^2.0.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
eslint-plugin-vue@^9.14.0:
|
eslint-plugin-vue@^9.14.1:
|
||||||
version "9.14.0"
|
version "9.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.14.0.tgz#73004a62d794e276a60d471114d81ed8887efcb8"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.14.1.tgz#3b0c9857642dac547c7564031cfb09d283eafdd4"
|
||||||
integrity sha512-4O7EuiqPGVQA1wYCzLvCzsBTv9JIPHLHhrf0k55DLzbwtmJbSw2TKS0G/l7pOwi9RWMSkjIT7ftChU5gZpgnJw==
|
integrity sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.3.0"
|
"@eslint-community/eslint-utils" "^4.3.0"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
@ -1746,6 +1752,11 @@ jsonc-eslint-parser@^1.0.1:
|
|||||||
espree "^6.0.0"
|
espree "^6.0.0"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
jsonc-parser@^3.2.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
|
||||||
|
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
|
||||||
|
|
||||||
jsonfile@^6.0.1:
|
jsonfile@^6.0.1:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||||
@ -1856,6 +1867,16 @@ mitt@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
|
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
|
||||||
integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
|
integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
|
||||||
|
|
||||||
|
mlly@^1.2.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.3.0.tgz#3184cb80c6437bda861a9f452ae74e3434ed9cd1"
|
||||||
|
integrity sha512-HT5mcgIQKkOrZecOjOX3DJorTikWXwsBfpcr/MGBkhfWcjiqvnaL/9ppxvIUXfjT6xt4DVIAsN9fMUz1ev4bIw==
|
||||||
|
dependencies:
|
||||||
|
acorn "^8.8.2"
|
||||||
|
pathe "^1.1.0"
|
||||||
|
pkg-types "^1.0.3"
|
||||||
|
ufo "^1.1.2"
|
||||||
|
|
||||||
ms@2.1.2:
|
ms@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
@ -2045,7 +2066,7 @@ path-type@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||||
|
|
||||||
pathe@^1.0.0:
|
pathe@^1.0.0, pathe@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
|
resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
|
||||||
integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
|
integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
|
||||||
@ -2070,6 +2091,15 @@ pify@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||||
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
||||||
|
|
||||||
|
pkg-types@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868"
|
||||||
|
integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
|
||||||
|
dependencies:
|
||||||
|
jsonc-parser "^3.2.0"
|
||||||
|
mlly "^1.2.0"
|
||||||
|
pathe "^1.1.0"
|
||||||
|
|
||||||
postcss-selector-parser@^6.0.9:
|
postcss-selector-parser@^6.0.9:
|
||||||
version "6.0.10"
|
version "6.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
|
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
|
||||||
@ -2266,6 +2296,11 @@ slash@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
|
sortablejs@^1.15.0:
|
||||||
|
version "1.15.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"
|
||||||
|
integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==
|
||||||
|
|
||||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
@ -2383,13 +2418,13 @@ 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.17.6:
|
terser@^5.17.7:
|
||||||
version "5.17.6"
|
version "5.17.7"
|
||||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.6.tgz#d810e75e1bb3350c799cd90ebefe19c9412c12de"
|
resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.7.tgz#2a8b134826fe179b711969fd9d9a0c2479b2a8c3"
|
||||||
integrity sha512-V8QHcs8YuyLkLHsJO5ucyff1ykrLVsR4dNnS//L5Y3NiSXpbK1J+WMVUs67eI0KTxs9JtHhgEQpXQVHlHI92DQ==
|
integrity sha512-/bi0Zm2C6VAexlGgLlVxA0P2lru/sdLyfCVaRMfKVo9nWxbmz7f/sD8VPybPeSUJaJcwmCJis9pBIhcVcG1QcQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/source-map" "^0.3.2"
|
"@jridgewell/source-map" "^0.3.3"
|
||||||
acorn "^8.5.0"
|
acorn "^8.8.2"
|
||||||
commander "^2.20.0"
|
commander "^2.20.0"
|
||||||
source-map-support "~0.5.20"
|
source-map-support "~0.5.20"
|
||||||
|
|
||||||
@ -2436,10 +2471,15 @@ type-fest@^0.20.2:
|
|||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
||||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||||
|
|
||||||
typescript@^5.0.4:
|
typescript@^5.1.3:
|
||||||
version "5.0.4"
|
version "5.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826"
|
||||||
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==
|
||||||
|
|
||||||
|
ufo@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76"
|
||||||
|
integrity sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==
|
||||||
|
|
||||||
unbox-primitive@^1.0.2:
|
unbox-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@ -2500,10 +2540,10 @@ vite-plugin-css-injected-by-js@^3.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.1.1.tgz#8324412636cf6fdada1a86f595aa2e78458e5ddb"
|
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.1.1.tgz#8324412636cf6fdada1a86f595aa2e78458e5ddb"
|
||||||
integrity sha512-mwrFvEEy0TuH8Ul0cb2HgjmNboQ/JnEFy+kHCWqAJph3ikMOiIuyYVdx0JO4nEIWJyzSnc4TTdmoTulsikvJEg==
|
integrity sha512-mwrFvEEy0TuH8Ul0cb2HgjmNboQ/JnEFy+kHCWqAJph3ikMOiIuyYVdx0JO4nEIWJyzSnc4TTdmoTulsikvJEg==
|
||||||
|
|
||||||
vite@^4.3.8:
|
vite@^4.3.9:
|
||||||
version "4.3.8"
|
version "4.3.9"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.8.tgz#70cd6a294ab52d7fb8f37f5bc63d117dd19e9918"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-4.3.9.tgz#db896200c0b1aa13b37cdc35c9e99ee2fdd5f96d"
|
||||||
integrity sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==
|
integrity sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.17.5"
|
esbuild "^0.17.5"
|
||||||
postcss "^8.4.23"
|
postcss "^8.4.23"
|
||||||
@ -2547,10 +2587,10 @@ vue-i18n@^9.2.2:
|
|||||||
"@intlify/vue-devtools" "9.2.2"
|
"@intlify/vue-devtools" "9.2.2"
|
||||||
"@vue/devtools-api" "^6.2.1"
|
"@vue/devtools-api" "^6.2.1"
|
||||||
|
|
||||||
vue-router@^4.2.1:
|
vue-router@^4.2.2:
|
||||||
version "4.2.1"
|
version "4.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.2.1.tgz#f8ab85c89e74682cad71519480fdf2b855e8c9e0"
|
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.2.2.tgz#b0097b66d89ca81c0986be03da244c7b32a4fd81"
|
||||||
integrity sha512-nW28EeifEp8Abc5AfmAShy5ZKGsGzjcnZ3L1yc2DYUo+MqbBClrRP9yda3dIekM4I50/KnEwo1wkBLf7kHH5Cw==
|
integrity sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.0"
|
"@vue/devtools-api" "^6.5.0"
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user