Merge branch 'master' of https://github.com/tbnobody/OpenDTU into Database

This commit is contained in:
Ralf Bauer 2024-06-18 21:37:23 +02:00
commit 04881da9b1
68 changed files with 719 additions and 527 deletions

View File

@ -5,11 +5,18 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: > value: >
### ✋ **This is bug tracker, not a support forum** ### ⚠️ Please remember: issues are for *bugs*
That is, something you believe affects every single user of OpenDTU, not just you. If you're not sure, start with one of the other options below.
- type: markdown
attributes:
value: |
#### Have a question? 👉 [Start a new discussion](https://github.com/tbnobody/OpenDTU/discussions/new) or [ask in chat](https://discord.gg/WzhxEY62mB).
If something isn't working right, you have questions or need help, [**get in touch on the Discussions**](https://github.com/tbnobody/OpenDTU/discussions). #### Before opening an issue, please double check:
Please quickly search existing issues first before submitting a bug. - [Documentation](https://www.opendtu.solar).
- [The FAQs](https://www.opendtu.solar/firmware/faq/).
- [Existing issues and discussions](https://github.com/tbnobody/OpenDTU/search?q=&type=issues).
- type: textarea - type: textarea
id: what-happened id: what-happened
attributes: attributes:
@ -66,3 +73,14 @@ body:
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations: validations:
required: false required: false
- type: checkboxes
id: required-checks
attributes:
label: Please confirm the following
options:
- label: I believe this issue is a bug that affects all users of OpenDTU, not something specific to my installation.
required: true
- label: I have already searched for relevant existing issues and discussions before opening this report.
required: true
- label: I have updated the title field above with a concise description.
required: true

View File

@ -1,3 +1,4 @@
{ {
"C_Cpp.clang_format_style": "WebKit" "C_Cpp.clang_format_style": "WebKit",
"cmake.sourceDirectory": "C:/git/OpenDTU-Database/.pio/libdeps/generic_esp32/ArduinoJson/src"
} }

View File

@ -47,6 +47,7 @@ struct INVERTER_CONFIG_T {
uint8_t ReachableThreshold; uint8_t ReachableThreshold;
bool ZeroRuntimeDataIfUnrechable; bool ZeroRuntimeDataIfUnrechable;
bool ZeroYieldDayOnMidnight; bool ZeroYieldDayOnMidnight;
bool ClearEventlogOnMidnight;
bool YieldDayCorrection; bool YieldDayCorrection;
CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT]; CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT];
}; };

View File

@ -13,6 +13,9 @@ public:
static String getTopic(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId); static String getTopic(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId);
void subscribeTopics();
void unsubscribeTopics();
private: private:
void loop(); void loop();
void publishField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId); void publishField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId);

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2024 Thomas Basler and others
*/
#include "CpuTemperature.h"
#include <Arduino.h>
#if defined(CONFIG_IDF_TARGET_ESP32)
// there is no official API available on the original ESP32
extern "C" {
uint8_t temprature_sens_read();
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
#include "driver/temp_sensor.h"
#endif
CpuTemperatureClass CpuTemperature;
float CpuTemperatureClass::read()
{
std::lock_guard<std::mutex> lock(_mutex);
float temperature = NAN;
bool success = false;
#if defined(CONFIG_IDF_TARGET_ESP32)
uint8_t raw = temprature_sens_read();
ESP_LOGV(TAG, "Raw temperature value: %d", raw);
temperature = (raw - 32) / 1.8f;
success = (raw != 128);
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
temp_sensor_set_config(tsens);
temp_sensor_start();
#if defined(CONFIG_IDF_TARGET_ESP32S3) && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 3))
#error \
"ESP32-S3 internal temperature sensor requires ESP IDF V4.4.3 or higher. See https://github.com/esphome/issues/issues/4271"
#endif
esp_err_t result = temp_sensor_read_celsius(&temperature);
temp_sensor_stop();
success = (result == ESP_OK);
#endif
if (success && std::isfinite(temperature)) {
return temperature;
} else {
ESP_LOGD(TAG, "Ignoring invalid temperature (success=%d, value=%.1f)", success, temperature);
return NAN;
}
}

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
class CpuTemperatureClass {
public:
float read();
private:
std::mutex _mutex;
};
extern CpuTemperatureClass CpuTemperature;

View File

@ -141,6 +141,9 @@ void HoymilesClass::loop()
if (inv->getZeroYieldDayOnMidnight()) { if (inv->getZeroYieldDayOnMidnight()) {
inv->Statistics()->zeroDailyData(); inv->Statistics()->zeroDailyData();
} }
if (inv->getClearEventlogOnMidnight()) {
inv->EventLog()->clearBuffer();
}
} }
lastWeekDay = currentWeekDay; lastWeekDay = currentWeekDay;

View File

@ -22,9 +22,9 @@ public:
} }
template <typename T> template <typename T>
std::shared_ptr<T> prepareCommand() std::shared_ptr<T> prepareCommand(InverterAbstract* inv)
{ {
return std::make_shared<T>(); return std::make_shared<T>(inv);
} }
protected: protected:

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -25,8 +25,8 @@ ID Target Addr Source Addr Cmd SCmd ? Limit Type CRC16 CRC8
#define CRC_SIZE 6 #define CRC_SIZE 6
ActivePowerControlCommand::ActivePowerControlCommand(const uint64_t target_address, const uint64_t router_address) ActivePowerControlCommand::ActivePowerControlCommand(InverterAbstract* inv, const uint64_t router_address)
: DevControlCommand(target_address, router_address) : DevControlCommand(inv, router_address)
{ {
_payload[10] = 0x0b; _payload[10] = 0x0b;
_payload[11] = 0x00; _payload[11] = 0x00;
@ -62,24 +62,24 @@ void ActivePowerControlCommand::setActivePowerLimit(const float limit, const Pow
udpateCRC(CRC_SIZE); udpateCRC(CRC_SIZE);
} }
bool ActivePowerControlCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool ActivePowerControlCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
if (!DevControlCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!DevControlCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
if ((getType() == PowerLimitControlType::RelativNonPersistent) || (getType() == PowerLimitControlType::RelativPersistent)) { if ((getType() == PowerLimitControlType::RelativNonPersistent) || (getType() == PowerLimitControlType::RelativPersistent)) {
inverter.SystemConfigPara()->setLimitPercent(getLimit()); _inv->SystemConfigPara()->setLimitPercent(getLimit());
} else { } else {
const uint16_t max_power = inverter.DevInfo()->getMaxPower(); const uint16_t max_power = _inv->DevInfo()->getMaxPower();
if (max_power > 0) { if (max_power > 0) {
inverter.SystemConfigPara()->setLimitPercent(static_cast<float>(getLimit()) / max_power * 100); _inv->SystemConfigPara()->setLimitPercent(static_cast<float>(getLimit()) / max_power * 100);
} else { } else {
// TODO(tbnobody): Not implemented yet because we only can publish the percentage value // TODO(tbnobody): Not implemented yet because we only can publish the percentage value
} }
} }
inverter.SystemConfigPara()->setLastUpdateCommand(millis()); _inv->SystemConfigPara()->setLastUpdateCommand(millis());
inverter.SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK); _inv->SystemConfigPara()->setLastLimitCommandSuccess(CMD_OK);
return true; return true;
} }
@ -94,7 +94,7 @@ PowerLimitControlType ActivePowerControlCommand::getType()
return (PowerLimitControlType)(((uint16_t)_payload[14] << 8) | _payload[15]); return (PowerLimitControlType)(((uint16_t)_payload[14] << 8) | _payload[15]);
} }
void ActivePowerControlCommand::gotTimeout(InverterAbstract& inverter) void ActivePowerControlCommand::gotTimeout()
{ {
inverter.SystemConfigPara()->setLastLimitCommandSuccess(CMD_NOK); _inv->SystemConfigPara()->setLastLimitCommandSuccess(CMD_NOK);
} }

View File

@ -12,12 +12,12 @@ typedef enum { // ToDo: to be verified by field tests
class ActivePowerControlCommand : public DevControlCommand { class ActivePowerControlCommand : public DevControlCommand {
public: public:
explicit ActivePowerControlCommand(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit ActivePowerControlCommand(InverterAbstract* inv, const uint64_t router_address = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
void setActivePowerLimit(const float limit, const PowerLimitControlType type = RelativNonPersistent); void setActivePowerLimit(const float limit, const PowerLimitControlType type = RelativNonPersistent);
float getLimit() const; float getLimit() const;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -23,8 +23,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap AlarmId Pa
#include "AlarmDataCommand.h" #include "AlarmDataCommand.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
AlarmDataCommand::AlarmDataCommand(const uint64_t target_address, const uint64_t router_address, const time_t time) AlarmDataCommand::AlarmDataCommand(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x11); setDataType(0x11);
@ -36,28 +36,28 @@ String AlarmDataCommand::getCommandName() const
return "AlarmData"; return "AlarmData";
} }
bool AlarmDataCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool AlarmDataCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.EventLog()->beginAppendFragment(); _inv->EventLog()->beginAppendFragment();
inverter.EventLog()->clearBuffer(); _inv->EventLog()->clearBuffer();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.EventLog()->appendFragment(offs, fragment[i].fragment, fragment[i].len); _inv->EventLog()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.EventLog()->endAppendFragment(); _inv->EventLog()->endAppendFragment();
inverter.EventLog()->setLastAlarmRequestSuccess(CMD_OK); _inv->EventLog()->setLastAlarmRequestSuccess(CMD_OK);
inverter.EventLog()->setLastUpdate(millis()); _inv->EventLog()->setLastUpdate(millis());
return true; return true;
} }
void AlarmDataCommand::gotTimeout(InverterAbstract& inverter) void AlarmDataCommand::gotTimeout()
{ {
inverter.EventLog()->setLastAlarmRequestSuccess(CMD_NOK); _inv->EventLog()->setLastAlarmRequestSuccess(CMD_NOK);
} }

View File

@ -5,10 +5,10 @@
class AlarmDataCommand : public MultiDataCommand { class AlarmDataCommand : public MultiDataCommand {
public: public:
explicit AlarmDataCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit AlarmDataCommand(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
}; };

View File

@ -19,8 +19,8 @@ ID Target Addr Source Addr ? ? ? CH ? CRC8
*/ */
#include "ChannelChangeCommand.h" #include "ChannelChangeCommand.h"
ChannelChangeCommand::ChannelChangeCommand(const uint64_t target_address, const uint64_t router_address, const uint8_t channel) ChannelChangeCommand::ChannelChangeCommand(InverterAbstract* inv, const uint64_t router_address, const uint8_t channel)
: CommandAbstract(target_address, router_address) : CommandAbstract(inv, router_address)
{ {
_payload[0] = 0x56; _payload[0] = 0x56;
_payload[13] = 0x14; _payload[13] = 0x14;
@ -67,7 +67,7 @@ void ChannelChangeCommand::setCountryMode(const CountryModeId_t mode)
} }
} }
bool ChannelChangeCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool ChannelChangeCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
return true; return true;
} }

View File

@ -6,7 +6,7 @@
class ChannelChangeCommand : public CommandAbstract { class ChannelChangeCommand : public CommandAbstract {
public: public:
explicit ChannelChangeCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const uint8_t channel = 0); explicit ChannelChangeCommand(InverterAbstract* inv, const uint64_t router_address = 0, const uint8_t channel = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
@ -15,7 +15,7 @@ public:
void setCountryMode(const CountryModeId_t mode); void setCountryMode(const CountryModeId_t mode);
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual uint8_t getMaxResendCount(); virtual uint8_t getMaxResendCount();
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -29,13 +29,16 @@ Source Address: 80 12 23 04
#include "CommandAbstract.h" #include "CommandAbstract.h"
#include "crc.h" #include "crc.h"
#include <string.h> #include <string.h>
#include "../inverters/InverterAbstract.h"
CommandAbstract::CommandAbstract(const uint64_t target_address, const uint64_t router_address) CommandAbstract::CommandAbstract(InverterAbstract* inv, const uint64_t router_address)
{ {
memset(_payload, 0, RF_LEN); memset(_payload, 0, RF_LEN);
_payload_size = 0; _payload_size = 0;
setTargetAddress(target_address); _inv = inv;
setTargetAddress(_inv->serial());
setRouterAddress(router_address); setRouterAddress(router_address);
setSendCount(0); setSendCount(0);
setTimeout(0); setTimeout(0);
@ -122,7 +125,7 @@ void CommandAbstract::convertSerialToPacketId(uint8_t buffer[], const uint64_t s
buffer[0] = s.b[3]; buffer[0] = s.b[3];
} }
void CommandAbstract::gotTimeout(InverterAbstract& inverter) void CommandAbstract::gotTimeout()
{ {
} }

View File

@ -13,7 +13,7 @@ class InverterAbstract;
class CommandAbstract { class CommandAbstract {
public: public:
explicit CommandAbstract(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit CommandAbstract(InverterAbstract* inv, const uint64_t router_address = 0);
virtual ~CommandAbstract() {}; virtual ~CommandAbstract() {};
const uint8_t* getDataPayload(); const uint8_t* getDataPayload();
@ -21,7 +21,6 @@ public:
uint8_t getDataSize() const; uint8_t getDataSize() const;
void setTargetAddress(const uint64_t address);
uint64_t getTargetAddress() const; uint64_t getTargetAddress() const;
void setRouterAddress(const uint64_t address); void setRouterAddress(const uint64_t address);
@ -38,8 +37,8 @@ public:
virtual CommandAbstract* getRequestFrameCommand(const uint8_t frame_no); virtual CommandAbstract* getRequestFrameCommand(const uint8_t frame_no);
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) = 0; virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id) = 0;
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
// Sets the amount how often the specific command is resent if all fragments where missing // Sets the amount how often the specific command is resent if all fragments where missing
virtual uint8_t getMaxResendCount() const; virtual uint8_t getMaxResendCount() const;
@ -56,6 +55,9 @@ protected:
uint64_t _targetAddress; uint64_t _targetAddress;
uint64_t _routerAddress; uint64_t _routerAddress;
InverterAbstract* _inv;
private: private:
void setTargetAddress(const uint64_t address);
static void convertSerialToPacketId(uint8_t buffer[], const uint64_t serial); static void convertSerialToPacketId(uint8_t buffer[], const uint64_t serial);
}; };

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -23,8 +23,8 @@ ID Target Addr Source Addr Cmd Payload CRC16 CRC8
#include "DevControlCommand.h" #include "DevControlCommand.h"
#include "crc.h" #include "crc.h"
DevControlCommand::DevControlCommand(const uint64_t target_address, const uint64_t router_address) DevControlCommand::DevControlCommand(InverterAbstract* inv, const uint64_t router_address)
: CommandAbstract(target_address, router_address) : CommandAbstract(inv, router_address)
{ {
_payload[0] = 0x51; _payload[0] = 0x51;
_payload[9] = 0x81; _payload[9] = 0x81;
@ -39,7 +39,7 @@ void DevControlCommand::udpateCRC(const uint8_t len)
_payload[10 + len + 1] = (uint8_t)(crc); _payload[10 + len + 1] = (uint8_t)(crc);
} }
bool DevControlCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool DevControlCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
if (fragment[i].mainCmd != (_payload[0] | 0x80)) { if (fragment[i].mainCmd != (_payload[0] | 0x80)) {

View File

@ -5,9 +5,9 @@
class DevControlCommand : public CommandAbstract { class DevControlCommand : public CommandAbstract {
public: public:
explicit DevControlCommand(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit DevControlCommand(InverterAbstract* inv, const uint64_t router_address = 0);
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
protected: protected:
void udpateCRC(const uint8_t len); void udpateCRC(const uint8_t len);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -21,8 +21,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "DevInfoAllCommand.h" #include "DevInfoAllCommand.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
DevInfoAllCommand::DevInfoAllCommand(const uint64_t target_address, const uint64_t router_address, const time_t time) DevInfoAllCommand::DevInfoAllCommand(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x01); setDataType(0x01);
@ -34,22 +34,22 @@ String DevInfoAllCommand::getCommandName() const
return "DevInfoAll"; return "DevInfoAll";
} }
bool DevInfoAllCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool DevInfoAllCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.DevInfo()->beginAppendFragment(); _inv->DevInfo()->beginAppendFragment();
inverter.DevInfo()->clearBufferAll(); _inv->DevInfo()->clearBufferAll();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.DevInfo()->appendFragmentAll(offs, fragment[i].fragment, fragment[i].len); _inv->DevInfo()->appendFragmentAll(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.DevInfo()->endAppendFragment(); _inv->DevInfo()->endAppendFragment();
inverter.DevInfo()->setLastUpdateAll(millis()); _inv->DevInfo()->setLastUpdateAll(millis());
return true; return true;
} }

View File

@ -5,9 +5,9 @@
class DevInfoAllCommand : public MultiDataCommand { class DevInfoAllCommand : public MultiDataCommand {
public: public:
explicit DevInfoAllCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit DevInfoAllCommand(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -21,8 +21,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "DevInfoSimpleCommand.h" #include "DevInfoSimpleCommand.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
DevInfoSimpleCommand::DevInfoSimpleCommand(const uint64_t target_address, const uint64_t router_address, const time_t time) DevInfoSimpleCommand::DevInfoSimpleCommand(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x00); setDataType(0x00);
@ -34,22 +34,22 @@ String DevInfoSimpleCommand::getCommandName() const
return "DevInfoSimple"; return "DevInfoSimple";
} }
bool DevInfoSimpleCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool DevInfoSimpleCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.DevInfo()->beginAppendFragment(); _inv->DevInfo()->beginAppendFragment();
inverter.DevInfo()->clearBufferSimple(); _inv->DevInfo()->clearBufferSimple();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.DevInfo()->appendFragmentSimple(offs, fragment[i].fragment, fragment[i].len); _inv->DevInfo()->appendFragmentSimple(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.DevInfo()->endAppendFragment(); _inv->DevInfo()->endAppendFragment();
inverter.DevInfo()->setLastUpdateSimple(millis()); _inv->DevInfo()->setLastUpdateSimple(millis());
return true; return true;
} }

View File

@ -5,9 +5,9 @@
class DevInfoSimpleCommand : public MultiDataCommand { class DevInfoSimpleCommand : public MultiDataCommand {
public: public:
explicit DevInfoSimpleCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit DevInfoSimpleCommand(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -22,8 +22,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "Hoymiles.h" #include "Hoymiles.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
GridOnProFilePara::GridOnProFilePara(const uint64_t target_address, const uint64_t router_address, const time_t time) GridOnProFilePara::GridOnProFilePara(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x02); setDataType(0x02);
@ -35,22 +35,22 @@ String GridOnProFilePara::getCommandName() const
return "GridOnProFilePara"; return "GridOnProFilePara";
} }
bool GridOnProFilePara::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool GridOnProFilePara::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.GridProfile()->beginAppendFragment(); _inv->GridProfile()->beginAppendFragment();
inverter.GridProfile()->clearBuffer(); _inv->GridProfile()->clearBuffer();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.GridProfile()->appendFragment(offs, fragment[i].fragment, fragment[i].len); _inv->GridProfile()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.GridProfile()->endAppendFragment(); _inv->GridProfile()->endAppendFragment();
inverter.GridProfile()->setLastUpdate(millis()); _inv->GridProfile()->setLastUpdate(millis());
return true; return true;
} }

View File

@ -5,9 +5,9 @@
class GridOnProFilePara : public MultiDataCommand { class GridOnProFilePara : public MultiDataCommand {
public: public:
explicit GridOnProFilePara(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit GridOnProFilePara(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -28,8 +28,9 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "MultiDataCommand.h" #include "MultiDataCommand.h"
#include "crc.h" #include "crc.h"
MultiDataCommand::MultiDataCommand(const uint64_t target_address, const uint64_t router_address, const uint8_t data_type, const time_t time) MultiDataCommand::MultiDataCommand(InverterAbstract* inv, const uint64_t router_address, const uint8_t data_type, const time_t time)
: CommandAbstract(target_address, router_address) : CommandAbstract(inv, router_address)
, _cmdRequestFrame(inv)
{ {
_payload[0] = 0x15; _payload[0] = 0x15;
_payload[9] = 0x80; _payload[9] = 0x80;
@ -79,13 +80,12 @@ time_t MultiDataCommand::getTime() const
CommandAbstract* MultiDataCommand::getRequestFrameCommand(const uint8_t frame_no) CommandAbstract* MultiDataCommand::getRequestFrameCommand(const uint8_t frame_no)
{ {
_cmdRequestFrame.setTargetAddress(getTargetAddress());
_cmdRequestFrame.setFrameNo(frame_no); _cmdRequestFrame.setFrameNo(frame_no);
return &_cmdRequestFrame; return &_cmdRequestFrame;
} }
bool MultiDataCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool MultiDataCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// All fragments are available --> Check CRC // All fragments are available --> Check CRC
uint16_t crc = 0xffff, crcRcv = 0; uint16_t crc = 0xffff, crcRcv = 0;

View File

@ -7,14 +7,14 @@
class MultiDataCommand : public CommandAbstract { class MultiDataCommand : public CommandAbstract {
public: public:
explicit MultiDataCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const uint8_t data_type = 0, const time_t time = 0); explicit MultiDataCommand(InverterAbstract* inv, const uint64_t router_address = 0, const uint8_t data_type = 0, const time_t time = 0);
void setTime(const time_t time); void setTime(const time_t time);
time_t getTime() const; time_t getTime() const;
CommandAbstract* getRequestFrameCommand(const uint8_t frame_no); CommandAbstract* getRequestFrameCommand(const uint8_t frame_no);
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
protected: protected:
void setDataType(const uint8_t data_type); void setDataType(const uint8_t data_type);

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
#include "ParaSetCommand.h" #include "ParaSetCommand.h"
ParaSetCommand::ParaSetCommand(const uint64_t target_address, const uint64_t router_address) ParaSetCommand::ParaSetCommand(InverterAbstract* inv, const uint64_t router_address)
: CommandAbstract(target_address, router_address) : CommandAbstract(inv, router_address)
{ {
_payload[0] = 0x52; _payload[0] = 0x52;
} }

View File

@ -5,5 +5,5 @@
class ParaSetCommand : public CommandAbstract { class ParaSetCommand : public CommandAbstract {
public: public:
explicit ParaSetCommand(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit ParaSetCommand(InverterAbstract* inv, const uint64_t router_address = 0);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -26,8 +26,8 @@ ID Target Addr Source Addr Cmd SCmd ? CRC16 CRC8
#define CRC_SIZE 2 #define CRC_SIZE 2
PowerControlCommand::PowerControlCommand(const uint64_t target_address, const uint64_t router_address) PowerControlCommand::PowerControlCommand(InverterAbstract* inv, const uint64_t router_address)
: DevControlCommand(target_address, router_address) : DevControlCommand(inv, router_address)
{ {
_payload[10] = 0x00; // TurnOn _payload[10] = 0x00; // TurnOn
_payload[11] = 0x00; _payload[11] = 0x00;
@ -44,20 +44,20 @@ String PowerControlCommand::getCommandName() const
return "PowerControl"; return "PowerControl";
} }
bool PowerControlCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool PowerControlCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
if (!DevControlCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!DevControlCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
inverter.PowerCommand()->setLastUpdateCommand(millis()); _inv->PowerCommand()->setLastUpdateCommand(millis());
inverter.PowerCommand()->setLastPowerCommandSuccess(CMD_OK); _inv->PowerCommand()->setLastPowerCommandSuccess(CMD_OK);
return true; return true;
} }
void PowerControlCommand::gotTimeout(InverterAbstract& inverter) void PowerControlCommand::gotTimeout()
{ {
inverter.PowerCommand()->setLastPowerCommandSuccess(CMD_NOK); _inv->PowerCommand()->setLastPowerCommandSuccess(CMD_NOK);
} }
void PowerControlCommand::setPowerOn(const bool state) void PowerControlCommand::setPowerOn(const bool state)

View File

@ -5,12 +5,12 @@
class PowerControlCommand : public DevControlCommand { class PowerControlCommand : public DevControlCommand {
public: public:
explicit PowerControlCommand(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit PowerControlCommand(InverterAbstract* inv, const uint64_t router_address = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
void setPowerOn(const bool state); void setPowerOn(const bool state);
void setRestart(); void setRestart();

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -22,8 +22,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "Hoymiles.h" #include "Hoymiles.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
RealTimeRunDataCommand::RealTimeRunDataCommand(const uint64_t target_address, const uint64_t router_address, const time_t time) RealTimeRunDataCommand::RealTimeRunDataCommand(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x0b); setDataType(0x0b);
@ -35,10 +35,10 @@ String RealTimeRunDataCommand::getCommandName() const
return "RealTimeRunData"; return "RealTimeRunData";
} }
bool RealTimeRunDataCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool RealTimeRunDataCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
@ -46,7 +46,7 @@ bool RealTimeRunDataCommand::handleResponse(InverterAbstract& inverter, const fr
// In case of low power in the inverter it occours that some incomplete fragments // In case of low power in the inverter it occours that some incomplete fragments
// with a valid CRC are received. // with a valid CRC are received.
const uint8_t fragmentsSize = getTotalFragmentSize(fragment, max_fragment_id); const uint8_t fragmentsSize = getTotalFragmentSize(fragment, max_fragment_id);
const uint8_t expectedSize = inverter.Statistics()->getExpectedByteCount(); const uint8_t expectedSize = _inv->Statistics()->getExpectedByteCount();
if (fragmentsSize < expectedSize) { if (fragmentsSize < expectedSize) {
Hoymiles.getMessageOutput()->printf("ERROR in %s: Received fragment size: %d, min expected size: %d\r\n", Hoymiles.getMessageOutput()->printf("ERROR in %s: Received fragment size: %d, min expected size: %d\r\n",
getCommandName().c_str(), fragmentsSize, expectedSize); getCommandName().c_str(), fragmentsSize, expectedSize);
@ -56,19 +56,19 @@ bool RealTimeRunDataCommand::handleResponse(InverterAbstract& inverter, const fr
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.Statistics()->beginAppendFragment(); _inv->Statistics()->beginAppendFragment();
inverter.Statistics()->clearBuffer(); _inv->Statistics()->clearBuffer();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.Statistics()->appendFragment(offs, fragment[i].fragment, fragment[i].len); _inv->Statistics()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.Statistics()->endAppendFragment(); _inv->Statistics()->endAppendFragment();
inverter.Statistics()->resetRxFailureCount(); _inv->Statistics()->resetRxFailureCount();
inverter.Statistics()->setLastUpdate(millis()); _inv->Statistics()->setLastUpdate(millis());
return true; return true;
} }
void RealTimeRunDataCommand::gotTimeout(InverterAbstract& inverter) void RealTimeRunDataCommand::gotTimeout()
{ {
inverter.Statistics()->incrementRxFailureCount(); _inv->Statistics()->incrementRxFailureCount();
} }

View File

@ -5,10 +5,10 @@
class RealTimeRunDataCommand : public MultiDataCommand { class RealTimeRunDataCommand : public MultiDataCommand {
public: public:
explicit RealTimeRunDataCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit RealTimeRunDataCommand(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -22,8 +22,8 @@ ID Target Addr Source Addr Frm CRC8
*/ */
#include "RequestFrameCommand.h" #include "RequestFrameCommand.h"
RequestFrameCommand::RequestFrameCommand(const uint64_t target_address, const uint64_t router_address, uint8_t frame_no) RequestFrameCommand::RequestFrameCommand(InverterAbstract* inv, const uint64_t router_address, uint8_t frame_no)
: SingleDataCommand(target_address, router_address) : SingleDataCommand(inv, router_address)
{ {
if (frame_no > 127) { if (frame_no > 127) {
frame_no = 0; frame_no = 0;
@ -47,7 +47,7 @@ uint8_t RequestFrameCommand::getFrameNo() const
return _payload[9] & (~0x80); return _payload[9] & (~0x80);
} }
bool RequestFrameCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool RequestFrameCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
return true; return true;
} }

View File

@ -5,12 +5,12 @@
class RequestFrameCommand : public SingleDataCommand { class RequestFrameCommand : public SingleDataCommand {
public: public:
explicit RequestFrameCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, uint8_t frame_no = 0); explicit RequestFrameCommand(InverterAbstract* inv, const uint64_t router_address = 0, uint8_t frame_no = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
void setFrameNo(const uint8_t frame_no); void setFrameNo(const uint8_t frame_no);
uint8_t getFrameNo() const; uint8_t getFrameNo() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -19,8 +19,8 @@ ID Target Addr Source Addr CRC8
*/ */
#include "SingleDataCommand.h" #include "SingleDataCommand.h"
SingleDataCommand::SingleDataCommand(const uint64_t target_address, const uint64_t router_address) SingleDataCommand::SingleDataCommand(InverterAbstract* inv, const uint64_t router_address)
: CommandAbstract(target_address, router_address) : CommandAbstract(inv, router_address)
{ {
_payload[0] = 0x15; _payload[0] = 0x15;
setTimeout(100); setTimeout(100);

View File

@ -5,5 +5,5 @@
class SingleDataCommand : public CommandAbstract { class SingleDataCommand : public CommandAbstract {
public: public:
explicit SingleDataCommand(const uint64_t target_address = 0, const uint64_t router_address = 0); explicit SingleDataCommand(InverterAbstract* inv, const uint64_t router_address = 0);
}; };

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/* /*
@ -22,8 +22,8 @@ ID Target Addr Source Addr Idx DT ? Time Gap Pa
#include "Hoymiles.h" #include "Hoymiles.h"
#include "inverters/InverterAbstract.h" #include "inverters/InverterAbstract.h"
SystemConfigParaCommand::SystemConfigParaCommand(const uint64_t target_address, const uint64_t router_address, const time_t time) SystemConfigParaCommand::SystemConfigParaCommand(InverterAbstract* inv, const uint64_t router_address, const time_t time)
: MultiDataCommand(target_address, router_address) : MultiDataCommand(inv, router_address)
{ {
setTime(time); setTime(time);
setDataType(0x05); setDataType(0x05);
@ -35,10 +35,10 @@ String SystemConfigParaCommand::getCommandName() const
return "SystemConfigPara"; return "SystemConfigPara";
} }
bool SystemConfigParaCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) bool SystemConfigParaCommand::handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id)
{ {
// Check CRC of whole payload // Check CRC of whole payload
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { if (!MultiDataCommand::handleResponse(fragment, max_fragment_id)) {
return false; return false;
} }
@ -46,7 +46,7 @@ bool SystemConfigParaCommand::handleResponse(InverterAbstract& inverter, const f
// In case of low power in the inverter it occours that some incomplete fragments // In case of low power in the inverter it occours that some incomplete fragments
// with a valid CRC are received. // with a valid CRC are received.
const uint8_t fragmentsSize = getTotalFragmentSize(fragment, max_fragment_id); const uint8_t fragmentsSize = getTotalFragmentSize(fragment, max_fragment_id);
const uint8_t expectedSize = inverter.SystemConfigPara()->getExpectedByteCount(); const uint8_t expectedSize = _inv->SystemConfigPara()->getExpectedByteCount();
if (fragmentsSize < expectedSize) { if (fragmentsSize < expectedSize) {
Hoymiles.getMessageOutput()->printf("ERROR in %s: Received fragment size: %d, min expected size: %d\r\n", Hoymiles.getMessageOutput()->printf("ERROR in %s: Received fragment size: %d, min expected size: %d\r\n",
getCommandName().c_str(), fragmentsSize, expectedSize); getCommandName().c_str(), fragmentsSize, expectedSize);
@ -56,19 +56,19 @@ bool SystemConfigParaCommand::handleResponse(InverterAbstract& inverter, const f
// Move all fragments into target buffer // Move all fragments into target buffer
uint8_t offs = 0; uint8_t offs = 0;
inverter.SystemConfigPara()->beginAppendFragment(); _inv->SystemConfigPara()->beginAppendFragment();
inverter.SystemConfigPara()->clearBuffer(); _inv->SystemConfigPara()->clearBuffer();
for (uint8_t i = 0; i < max_fragment_id; i++) { for (uint8_t i = 0; i < max_fragment_id; i++) {
inverter.SystemConfigPara()->appendFragment(offs, fragment[i].fragment, fragment[i].len); _inv->SystemConfigPara()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
offs += (fragment[i].len); offs += (fragment[i].len);
} }
inverter.SystemConfigPara()->endAppendFragment(); _inv->SystemConfigPara()->endAppendFragment();
inverter.SystemConfigPara()->setLastUpdateRequest(millis()); _inv->SystemConfigPara()->setLastUpdateRequest(millis());
inverter.SystemConfigPara()->setLastLimitRequestSuccess(CMD_OK); _inv->SystemConfigPara()->setLastLimitRequestSuccess(CMD_OK);
return true; return true;
} }
void SystemConfigParaCommand::gotTimeout(InverterAbstract& inverter) void SystemConfigParaCommand::gotTimeout()
{ {
inverter.SystemConfigPara()->setLastLimitRequestSuccess(CMD_NOK); _inv->SystemConfigPara()->setLastLimitRequestSuccess(CMD_NOK);
} }

View File

@ -5,10 +5,10 @@
class SystemConfigParaCommand : public MultiDataCommand { class SystemConfigParaCommand : public MultiDataCommand {
public: public:
explicit SystemConfigParaCommand(const uint64_t target_address = 0, const uint64_t router_address = 0, const time_t time = 0); explicit SystemConfigParaCommand(InverterAbstract* inv, const uint64_t router_address = 0, const time_t time = 0);
virtual String getCommandName() const; virtual String getCommandName() const;
virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual bool handleResponse(const fragment_t fragment[], const uint8_t max_fragment_id);
virtual void gotTimeout(InverterAbstract& inverter); virtual void gotTimeout();
}; };

View File

@ -18,10 +18,9 @@ bool HMS_Abstract::sendChangeChannelRequest()
return false; return false;
} }
auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>(); auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>(this);
cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode()); cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode());
cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency())); cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
cmdChannel->setTargetAddress(serial());
_radio->enqueCommand(cmdChannel); _radio->enqueCommand(cmdChannel);
return true; return true;

View File

@ -20,10 +20,9 @@ bool HMT_Abstract::sendChangeChannelRequest()
return false; return false;
} }
auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>(); auto cmdChannel = _radio->prepareCommand<ChannelChangeCommand>(this);
cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode()); cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode());
cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency())); cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency()));
cmdChannel->setTargetAddress(serial());
_radio->enqueCommand(cmdChannel); _radio->enqueCommand(cmdChannel);
return true; return true;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
#include "HM_Abstract.h" #include "HM_Abstract.h"
#include "HoymilesRadio.h" #include "HoymilesRadio.h"
@ -30,9 +30,8 @@ bool HM_Abstract::sendStatsRequest()
time_t now; time_t now;
time(&now); time(&now);
auto cmd = _radio->prepareCommand<RealTimeRunDataCommand>(); auto cmd = _radio->prepareCommand<RealTimeRunDataCommand>(this);
cmd->setTime(now); cmd->setTime(now);
cmd->setTargetAddress(serial());
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
return true; return true;
@ -62,9 +61,8 @@ bool HM_Abstract::sendAlarmLogRequest(const bool force)
time_t now; time_t now;
time(&now); time(&now);
auto cmd = _radio->prepareCommand<AlarmDataCommand>(); auto cmd = _radio->prepareCommand<AlarmDataCommand>(this);
cmd->setTime(now); cmd->setTime(now);
cmd->setTargetAddress(serial());
EventLog()->setLastAlarmRequestSuccess(CMD_PENDING); EventLog()->setLastAlarmRequestSuccess(CMD_PENDING);
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
@ -85,14 +83,12 @@ bool HM_Abstract::sendDevInfoRequest()
time_t now; time_t now;
time(&now); time(&now);
auto cmdAll = _radio->prepareCommand<DevInfoAllCommand>(); auto cmdAll = _radio->prepareCommand<DevInfoAllCommand>(this);
cmdAll->setTime(now); cmdAll->setTime(now);
cmdAll->setTargetAddress(serial());
_radio->enqueCommand(cmdAll); _radio->enqueCommand(cmdAll);
auto cmdSimple = _radio->prepareCommand<DevInfoSimpleCommand>(); auto cmdSimple = _radio->prepareCommand<DevInfoSimpleCommand>(this);
cmdSimple->setTime(now); cmdSimple->setTime(now);
cmdSimple->setTargetAddress(serial());
_radio->enqueCommand(cmdSimple); _radio->enqueCommand(cmdSimple);
return true; return true;
@ -112,9 +108,8 @@ bool HM_Abstract::sendSystemConfigParaRequest()
time_t now; time_t now;
time(&now); time(&now);
auto cmd = _radio->prepareCommand<SystemConfigParaCommand>(); auto cmd = _radio->prepareCommand<SystemConfigParaCommand>(this);
cmd->setTime(now); cmd->setTime(now);
cmd->setTargetAddress(serial());
SystemConfigPara()->setLastLimitRequestSuccess(CMD_PENDING); SystemConfigPara()->setLastLimitRequestSuccess(CMD_PENDING);
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
@ -134,9 +129,8 @@ bool HM_Abstract::sendActivePowerControlRequest(float limit, const PowerLimitCon
_activePowerControlLimit = limit; _activePowerControlLimit = limit;
_activePowerControlType = type; _activePowerControlType = type;
auto cmd = _radio->prepareCommand<ActivePowerControlCommand>(); auto cmd = _radio->prepareCommand<ActivePowerControlCommand>(this);
cmd->setActivePowerLimit(limit, type); cmd->setActivePowerLimit(limit, type);
cmd->setTargetAddress(serial());
SystemConfigPara()->setLastLimitCommandSuccess(CMD_PENDING); SystemConfigPara()->setLastLimitCommandSuccess(CMD_PENDING);
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
@ -160,9 +154,8 @@ bool HM_Abstract::sendPowerControlRequest(const bool turnOn)
_powerState = 0; _powerState = 0;
} }
auto cmd = _radio->prepareCommand<PowerControlCommand>(); auto cmd = _radio->prepareCommand<PowerControlCommand>(this);
cmd->setPowerOn(turnOn); cmd->setPowerOn(turnOn);
cmd->setTargetAddress(serial());
PowerCommand()->setLastPowerCommandSuccess(CMD_PENDING); PowerCommand()->setLastPowerCommandSuccess(CMD_PENDING);
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
@ -177,9 +170,8 @@ bool HM_Abstract::sendRestartControlRequest()
_powerState = 2; _powerState = 2;
auto cmd = _radio->prepareCommand<PowerControlCommand>(); auto cmd = _radio->prepareCommand<PowerControlCommand>(this);
cmd->setRestart(); cmd->setRestart();
cmd->setTargetAddress(serial());
PowerCommand()->setLastPowerCommandSuccess(CMD_PENDING); PowerCommand()->setLastPowerCommandSuccess(CMD_PENDING);
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
@ -219,9 +211,8 @@ bool HM_Abstract::sendGridOnProFileParaRequest()
time_t now; time_t now;
time(&now); time(&now);
auto cmd = _radio->prepareCommand<GridOnProFilePara>(); auto cmd = _radio->prepareCommand<GridOnProFilePara>(this);
cmd->setTime(now); cmd->setTime(now);
cmd->setTargetAddress(serial());
_radio->enqueCommand(cmd); _radio->enqueCommand(cmd);
return true; return true;

View File

@ -127,6 +127,16 @@ bool InverterAbstract::getZeroYieldDayOnMidnight() const
return _zeroYieldDayOnMidnight; return _zeroYieldDayOnMidnight;
} }
void InverterAbstract::setClearEventlogOnMidnight(const bool enabled)
{
_clearEventlogOnMidnight = enabled;
}
bool InverterAbstract::getClearEventlogOnMidnight() const
{
return _clearEventlogOnMidnight;
}
bool InverterAbstract::sendChangeChannelRequest() bool InverterAbstract::sendChangeChannelRequest()
{ {
return false; return false;
@ -226,7 +236,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract& cmd)
if (cmd.getSendCount() <= cmd.getMaxResendCount()) { if (cmd.getSendCount() <= cmd.getMaxResendCount()) {
return FRAGMENT_ALL_MISSING_RESEND; return FRAGMENT_ALL_MISSING_RESEND;
} else { } else {
cmd.gotTimeout(*this); cmd.gotTimeout();
return FRAGMENT_ALL_MISSING_TIMEOUT; return FRAGMENT_ALL_MISSING_TIMEOUT;
} }
} }
@ -237,7 +247,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract& cmd)
if (_rxFragmentRetransmitCnt++ < cmd.getMaxRetransmitCount()) { if (_rxFragmentRetransmitCnt++ < cmd.getMaxRetransmitCount()) {
return _rxFragmentLastPacketId + 1; return _rxFragmentLastPacketId + 1;
} else { } else {
cmd.gotTimeout(*this); cmd.gotTimeout();
return FRAGMENT_RETRANSMIT_TIMEOUT; return FRAGMENT_RETRANSMIT_TIMEOUT;
} }
} }
@ -249,14 +259,14 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract& cmd)
if (_rxFragmentRetransmitCnt++ < cmd.getMaxRetransmitCount()) { if (_rxFragmentRetransmitCnt++ < cmd.getMaxRetransmitCount()) {
return i + 1; return i + 1;
} else { } else {
cmd.gotTimeout(*this); cmd.gotTimeout();
return FRAGMENT_RETRANSMIT_TIMEOUT; return FRAGMENT_RETRANSMIT_TIMEOUT;
} }
} }
} }
if (!cmd.handleResponse(*this, _rxFragmentBuffer, _rxFragmentMaxPacketId)) { if (!cmd.handleResponse(_rxFragmentBuffer, _rxFragmentMaxPacketId)) {
cmd.gotTimeout(*this); cmd.gotTimeout();
return FRAGMENT_HANDLE_ERROR; return FRAGMENT_HANDLE_ERROR;
} }

View File

@ -58,6 +58,9 @@ public:
void setZeroYieldDayOnMidnight(const bool enabled); void setZeroYieldDayOnMidnight(const bool enabled);
bool getZeroYieldDayOnMidnight() const; bool getZeroYieldDayOnMidnight() const;
void setClearEventlogOnMidnight(const bool enabled);
bool getClearEventlogOnMidnight() const;
void clearRxFragmentBuffer(); void clearRxFragmentBuffer();
void addRxFragment(const uint8_t fragment[], const uint8_t len); void addRxFragment(const uint8_t fragment[], const uint8_t len);
uint8_t verifyAllFragments(CommandAbstract& cmd); uint8_t verifyAllFragments(CommandAbstract& cmd);
@ -102,6 +105,7 @@ private:
bool _zeroValuesIfUnreachable = false; bool _zeroValuesIfUnreachable = false;
bool _zeroYieldDayOnMidnight = false; bool _zeroYieldDayOnMidnight = false;
bool _clearEventlogOnMidnight = false;
std::unique_ptr<AlarmLogParser> _alarmLogParser; std::unique_ptr<AlarmLogParser> _alarmLogParser;
std::unique_ptr<DevInfoParser> _devInfoParser; std::unique_ptr<DevInfoParser> _devInfoParser;

View File

@ -1,7 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022-2023 Thomas Basler and others * Copyright (C) 2022-2024 Thomas Basler and others
*/ */
/*
This parser is used to parse the response of 'AlarmDataCommand'.
Data structure:
* wcode:
* right 8 bit: Event ID
* bit 13: Start time = PM (12h has to be added to start time)
* bit 12: End time = PM (12h has to be added to start time)
* Start: 12h based start time of the event (PM indicator in wcode)
* End: 12h based start time of the event (PM indicator in wcode)
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
00 01 02 03 04 05 06 07 08 09 10 11
|<-------------- First log entry -------------->| |<->|
-----------------------------------------------------------------------------------------------------------------------------
95 80 14 82 66 80 14 33 28 01 00 01 80 01 00 01 91 EA 91 EA 00 00 00 00 00 8F 65 -- -- -- -- --
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ^^
ID Source Addr Target Addr Idx ? wcode ? Start End ? ? ? ? wcode CRC8
*/
#include "AlarmLogParser.h" #include "AlarmLogParser.h"
#include "../Hoymiles.h" #include "../Hoymiles.h"
#include <cstring> #include <cstring>

View File

@ -1,7 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022 - 2023 Thomas Basler and others * Copyright (C) 2022 - 2024 Thomas Basler and others
*/ */
/*
This parser is used to parse the response of 'DevInfoAllCommand' and 'DevInfoSimpleCommand'.
It contains version information of the hardware and firmware. It can also be used to determine
the exact inverter type.
Data structure (DevInfoAllCommand):
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
00 01 02 03 04 05 06 07 08 09 10 11 12 13
-------------------------------------------------------------------------------------------------------------------------------------------------
95 80 14 82 66 80 14 33 28 81 27 1C 07 E5 04 01 07 2D 00 01 00 00 00 00 DF DD 1E -- -- -- -- --
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^
ID Source Addr Target Addr Idx FW Version FW Year FW Month/Date FW Hour/Minute Bootloader ? ? CRC16 CRC8
Data structure (DevInfoSimpleCommand):
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
00 01 02 03 04 05 06 07 08 09 10 11 12 13
-------------------------------------------------------------------------------------------------------------------------------------------------
95 80 14 82 66 80 14 33 28 81 27 1C 10 12 71 01 01 00 0A 00 20 01 00 00 E5 F8 95
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^^^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^
ID Source Addr Target Addr Idx FW Version HW Part No. HW Version ? ? ? CRC16 CRC8
*/
#include "DevInfoParser.h" #include "DevInfoParser.h"
#include "../Hoymiles.h" #include "../Hoymiles.h"
#include <cstring> #include <cstring>

View File

@ -2,6 +2,23 @@
/* /*
* Copyright (C) 2023 - 2024 Thomas Basler and others * Copyright (C) 2023 - 2024 Thomas Basler and others
*/ */
/*
This parser is used to parse the response of 'GridOnProFilePara'.
It contains the whole grid profile of the inverter.
Data structure:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
00 01 02 03 04 05 06 07 08 09 10 11 12 13
|<---------- Returns till the end of the payload ---------->|
---------------------------------------------------------------------------------------------------------------------------------------------------------------
95 80 14 82 66 80 14 33 28 01 0A 00 20 01 00 0C 08 FC 07 A3 00 0F 09 E2 00 1E E6 -- -- -- -- --
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^
ID Source Addr Target Addr Idx Profile ID Profile Version Section ID Section Version Value Value Value Value CRC16 CRC8
The number of values depends on the respective section and its version. After the last value of a section follows the next section id.
*/
#include "GridProfileParser.h" #include "GridProfileParser.h"
#include "../Hoymiles.h" #include "../Hoymiles.h"
#include <cstring> #include <cstring>
@ -11,10 +28,10 @@
const std::array<const ProfileType_t, PROFILE_TYPE_COUNT> GridProfileParser::_profileTypes = { { const std::array<const ProfileType_t, PROFILE_TYPE_COUNT> GridProfileParser::_profileTypes = { {
{ 0x02, 0x00, "US - NA_IEEE1547_240V" }, { 0x02, 0x00, "US - NA_IEEE1547_240V" },
{ 0x03, 0x00, "DE - DE_VDE4105_2018" }, { 0x03, 0x00, "DE - DE_VDE4105_2018" },
{ 0x03, 0x01, "XX - unknown" }, { 0x03, 0x01, "DE - DE_VDE4105_2011" },
{ 0x0a, 0x00, "XX - EN 50549-1:2019" }, { 0x0a, 0x00, "XX - EN 50549-1:2019" },
{ 0x0c, 0x00, "AT - AT_TOR_Erzeuger_default" }, { 0x0c, 0x00, "AT - AT_TOR_Erzeuger_default" },
{ 0x0d, 0x04, "FR -" }, { 0x0d, 0x04, "XX - NF_EN_50549-1:2019" },
{ 0x10, 0x00, "ES - ES_RD1699" }, { 0x10, 0x00, "ES - ES_RD1699" },
{ 0x12, 0x00, "PL - EU_EN50438" }, { 0x12, 0x00, "PL - EU_EN50438" },
{ 0x29, 0x00, "NL - NL_NEN-EN50549-1_2019" }, { 0x29, 0x00, "NL - NL_NEN-EN50549-1_2019" },
@ -82,7 +99,7 @@ constexpr frozen::map<uint8_t, GridProfileItemDefinition_t, 0x42> itemDefinition
{ 0x1f, make_value("Start of Frequency Watt Droop (Fstart)", "Hz", 100) }, { 0x1f, make_value("Start of Frequency Watt Droop (Fstart)", "Hz", 100) },
{ 0x20, make_value("FW Droop Slope (Kpower_Freq)", "Pn%/Hz", 10) }, { 0x20, make_value("FW Droop Slope (Kpower_Freq)", "Pn%/Hz", 10) },
{ 0x21, make_value("Recovery Ramp Rate (RRR)", "Pn%/s", 100) }, { 0x21, make_value("Recovery Ramp Rate (RRR)", "Pn%/s", 100) },
{ 0x22, make_value("Recovery High Frequency (RVHF)", "Hz", 100) }, { 0x22, make_value("Recovery High Frequency (RVHF)", "Hz", 10) },
{ 0x23, make_value("Recovery Low Frequency (RVLF)", "Hz", 100) }, { 0x23, make_value("Recovery Low Frequency (RVLF)", "Hz", 100) },
{ 0x24, make_value("VW Function Activated", "bool", 1) }, { 0x24, make_value("VW Function Activated", "bool", 1) },
{ 0x25, make_value("Start of Voltage Watt Droop (Vstart)", "V", 10) }, { 0x25, make_value("Start of Voltage Watt Droop (Vstart)", "V", 10) },

View File

@ -1,7 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022 - 2023 Thomas Basler and others * Copyright (C) 2022 - 2024 Thomas Basler and others
*/ */
/*
This parser is used to parse the response of 'SystemConfigParaCommand'.
It contains the set inverter limit.
Data structure:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
00 01 02 03 04 05 06 07 08 09 10 11 12 13
---------------------------------------------------------------------------------------------------------------------------------
95 80 14 82 66 80 14 33 28 81 00 01 03 E8 00 00 03 E8 00 00 00 00 00 00 3C F8 2E -- -- -- -- --
^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^^^^ ^^
ID Source Addr Target Addr Idx ? Limit percent ? ? ? ? ? CRC16 CRC8
*/
#include "SystemConfigParaParser.h" #include "SystemConfigParaParser.h"
#include "../Hoymiles.h" #include "../Hoymiles.h"
#include <cstring> #include <cstring>

View File

@ -1,26 +0,0 @@
diff --color -ruN a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp
--- a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp
+++ b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.cpp
@@ -97,7 +97,7 @@
static inline bool _init_async_event_queue(){
if(!_async_queue){
- _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
+ _async_queue = xQueueCreate(CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE, sizeof(lwip_event_packet_t *));
if(!_async_queue){
return false;
}
diff --color -ruN a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h
--- a/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h
+++ b/.pio/libdeps/$$$env$$$/AsyncTCP-esphome/src/AsyncTCP.h
@@ -53,6 +53,10 @@
#define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2
#endif
+#ifndef CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE
+#define CONFIG_ASYNC_TCP_EVENT_QUEUE_SIZE 32
+#endif
+
class AsyncClient;
#define ASYNC_MAX_ACK_TIME 5000

View File

@ -21,7 +21,7 @@ Import("env")
platform = env.PioPlatform() platform = env.PioPlatform()
import sys import sys
from os.path import join from os.path import join, getsize
sys.path.append(join(platform.get_package_dir("tool-esptoolpy"))) sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
import esptool import esptool
@ -60,6 +60,14 @@ def esp32_create_combined_bin(source, target, env):
flash_size, flash_size,
] ]
# platformio estimates the amount of flash used to store the firmware. this
# estimate is not accurate. we perform a final check on the firmware bin
# size by comparing it against the respective partition size.
max_size = env.BoardConfig().get("upload.maximum_size", 1)
fw_size = getsize(firmware_name)
if (fw_size > max_size):
raise Exception("firmware binary too large: %d > %d" % (fw_size, max_size))
print(" Offset | File") print(" Offset | File")
for section in sections: for section in sections:
sect_adr, sect_file = section.split(" ", 1) sect_adr, sect_file = section.split(" ", 1)

View File

@ -19,7 +19,7 @@ extra_configs =
custom_ci_action = generic,generic_esp32,generic_esp32s3,generic_esp32s3_usb custom_ci_action = generic,generic_esp32,generic_esp32s3,generic_esp32s3_usb
framework = arduino framework = arduino
platform = espressif32@6.6.0 platform = espressif32@6.7.0
build_flags = build_flags =
-DPIOENV=\"$PIOENV\" -DPIOENV=\"$PIOENV\"
@ -38,9 +38,9 @@ build_unflags =
-std=gnu++11 -std=gnu++11
lib_deps = lib_deps =
mathieucarbou/ESP Async WebServer @ 2.9.5 mathieucarbou/ESP Async WebServer @ 2.10.8
bblanchon/ArduinoJson @ 7.0.4 bblanchon/ArduinoJson @ 7.0.4
https://github.com/bertmelis/espMqttClient.git#v1.6.0 https://github.com/bertmelis/espMqttClient.git#v1.7.0
nrf24/RF24 @ 1.4.8 nrf24/RF24 @ 1.4.8
olikraus/U8g2 @ 2.35.19 olikraus/U8g2 @ 2.35.19
buelowp/sunset @ 1.1.7 buelowp/sunset @ 1.1.7
@ -61,7 +61,7 @@ board_build.embed_files =
webapp_dist/js/app.js.gz webapp_dist/js/app.js.gz
webapp_dist/site.webmanifest webapp_dist/site.webmanifest
custom_patches = async_tcp custom_patches =
monitor_filters = esp32_exception_decoder, time, log2file, colorize monitor_filters = esp32_exception_decoder, time, log2file, colorize
monitor_speed = 115200 monitor_speed = 115200

View File

@ -128,6 +128,7 @@ bool ConfigurationClass::write()
inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold; inv["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
inv["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable; inv["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight; inv["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
inv["clear_eventlog"] = config.Inverter[i].ClearEventlogOnMidnight;
inv["yieldday_correction"] = config.Inverter[i].YieldDayCorrection; inv["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;
JsonArray channel = inv["channel"].to<JsonArray>(); JsonArray channel = inv["channel"].to<JsonArray>();
@ -302,6 +303,7 @@ bool ConfigurationClass::read()
config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD; config.Inverter[i].ReachableThreshold = inv["reachable_threshold"] | REACHABLE_THRESHOLD;
config.Inverter[i].ZeroRuntimeDataIfUnrechable = inv["zero_runtime"] | false; config.Inverter[i].ZeroRuntimeDataIfUnrechable = inv["zero_runtime"] | false;
config.Inverter[i].ZeroYieldDayOnMidnight = inv["zero_day"] | false; config.Inverter[i].ZeroYieldDayOnMidnight = inv["zero_day"] | false;
config.Inverter[i].ClearEventlogOnMidnight = inv["clear_eventlog"] | false;
config.Inverter[i].YieldDayCorrection = inv["yieldday_correction"] | false; config.Inverter[i].YieldDayCorrection = inv["yieldday_correction"] | false;
JsonArray channel = inv["channel"]; JsonArray channel = inv["channel"];

View File

@ -82,6 +82,7 @@ void InverterSettingsClass::init(Scheduler& scheduler)
inv->setReachableThreshold(config.Inverter[i].ReachableThreshold); inv->setReachableThreshold(config.Inverter[i].ReachableThreshold);
inv->setZeroValuesIfUnreachable(config.Inverter[i].ZeroRuntimeDataIfUnrechable); inv->setZeroValuesIfUnreachable(config.Inverter[i].ZeroRuntimeDataIfUnrechable);
inv->setZeroYieldDayOnMidnight(config.Inverter[i].ZeroYieldDayOnMidnight); inv->setZeroYieldDayOnMidnight(config.Inverter[i].ZeroYieldDayOnMidnight);
inv->setClearEventlogOnMidnight(config.Inverter[i].ClearEventlogOnMidnight);
inv->Statistics()->setYieldDayCorrection(config.Inverter[i].YieldDayCorrection); inv->Statistics()->setYieldDayCorrection(config.Inverter[i].YieldDayCorrection);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower); inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower);

View File

@ -25,20 +25,7 @@ MqttHandleInverterClass::MqttHandleInverterClass()
void MqttHandleInverterClass::init(Scheduler& scheduler) void MqttHandleInverterClass::init(Scheduler& scheduler)
{ {
using std::placeholders::_1; subscribeTopics();
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
using std::placeholders::_5;
using std::placeholders::_6;
const String topic = MqttSettings.getPrefix();
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
scheduler.addTask(_loopTask); scheduler.addTask(_loopTask);
_loopTask.setInterval(Configuration.get().Mqtt.PublishInterval * TASK_SECOND); _loopTask.setInterval(Configuration.get().Mqtt.PublishInterval * TASK_SECOND);
@ -247,3 +234,32 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
} }
} }
} }
void MqttHandleInverterClass::subscribeTopics()
{
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
using std::placeholders::_5;
using std::placeholders::_6;
const String topic = MqttSettings.getPrefix();
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
MqttSettings.subscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART), 0, std::bind(&MqttHandleInverterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
}
void MqttHandleInverterClass::unsubscribeTopics()
{
const String topic = MqttSettings.getPrefix();
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE));
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE));
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE));
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE));
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_POWER));
MqttSettings.unsubscribe(String(topic + "+/cmd/" + TOPIC_SUB_RESTART));
}

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright (C) 2022 - 2023 Thomas Basler and others * Copyright (C) 2022 - 2024 Thomas Basler and others
*/ */
#include "Utils.h" #include "Utils.h"
#include "Display_Graphic.h" #include "Display_Graphic.h"
#include "Led_Single.h" #include "Led_Single.h"
#include "MessageOutput.h" #include "MessageOutput.h"
#include "PinMapping.h"
#include <Esp.h> #include <Esp.h>
#include <LittleFS.h> #include <LittleFS.h>

View File

@ -55,6 +55,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold; obj["reachable_threshold"] = config.Inverter[i].ReachableThreshold;
obj["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable; obj["zero_runtime"] = config.Inverter[i].ZeroRuntimeDataIfUnrechable;
obj["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight; obj["zero_day"] = config.Inverter[i].ZeroYieldDayOnMidnight;
obj["clear_eventlog"] = config.Inverter[i].ClearEventlogOnMidnight;
obj["yieldday_correction"] = config.Inverter[i].YieldDayCorrection; obj["yieldday_correction"] = config.Inverter[i].YieldDayCorrection;
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial); auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
@ -213,20 +214,21 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
inverter.Serial = new_serial; inverter.Serial = new_serial;
strncpy(inverter.Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN); strncpy(inverter.Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);
inverter.Poll_Enable = root["poll_enable"] | true;
inverter.Poll_Enable_Night = root["poll_enable_night"] | true;
inverter.Command_Enable = root["command_enable"] | true;
inverter.Command_Enable_Night = root["command_enable_night"] | true;
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false;
inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false;
inverter.ClearEventlogOnMidnight = root["clear_eventlog"] | false;
inverter.YieldDayCorrection = root["yieldday_correction"] | false;
uint8_t arrayCount = 0; uint8_t arrayCount = 0;
for (JsonVariant channel : channelArray) { for (JsonVariant channel : channelArray) {
inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as<uint16_t>(); inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as<uint16_t>();
inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as<float>(); inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as<float>();
strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name)); strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name));
inverter.Poll_Enable = root["poll_enable"] | true;
inverter.Poll_Enable_Night = root["poll_enable_night"] | true;
inverter.Command_Enable = root["command_enable"] | true;
inverter.Command_Enable_Night = root["command_enable_night"] | true;
inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD;
inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false;
inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false;
inverter.YieldDayCorrection = root["yieldday_correction"] | false;
arrayCount++; arrayCount++;
} }
@ -254,6 +256,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
inv->setReachableThreshold(inverter.ReachableThreshold); inv->setReachableThreshold(inverter.ReachableThreshold);
inv->setZeroValuesIfUnreachable(inverter.ZeroRuntimeDataIfUnrechable); inv->setZeroValuesIfUnreachable(inverter.ZeroRuntimeDataIfUnrechable);
inv->setZeroYieldDayOnMidnight(inverter.ZeroYieldDayOnMidnight); inv->setZeroYieldDayOnMidnight(inverter.ZeroYieldDayOnMidnight);
inv->setClearEventlogOnMidnight(inverter.ClearEventlogOnMidnight);
inv->Statistics()->setYieldDayCorrection(inverter.YieldDayCorrection); inv->Statistics()->setYieldDayCorrection(inverter.YieldDayCorrection);
for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) {
inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower); inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower);

View File

@ -5,6 +5,7 @@
#include "WebApi_mqtt.h" #include "WebApi_mqtt.h"
#include "Configuration.h" #include "Configuration.h"
#include "MqttHandleHass.h" #include "MqttHandleHass.h"
#include "MqttHandleInverter.h"
#include "MqttSettings.h" #include "MqttSettings.h"
#include "WebApi.h" #include "WebApi.h"
#include "WebApi_errors.h" #include "WebApi_errors.h"
@ -76,7 +77,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
root["mqtt_client_cert"] = config.Mqtt.Tls.ClientCert; root["mqtt_client_cert"] = config.Mqtt.Tls.ClientCert;
root["mqtt_client_key"] = config.Mqtt.Tls.ClientKey; root["mqtt_client_key"] = config.Mqtt.Tls.ClientKey;
root["mqtt_lwt_topic"] = config.Mqtt.Lwt.Topic; root["mqtt_lwt_topic"] = config.Mqtt.Lwt.Topic;
root["mqtt_lwt_online"] = config.Mqtt.Lwt.Value_Online;; root["mqtt_lwt_online"] = config.Mqtt.Lwt.Value_Online;
root["mqtt_lwt_offline"] = config.Mqtt.Lwt.Value_Offline; root["mqtt_lwt_offline"] = config.Mqtt.Lwt.Value_Offline;
root["mqtt_lwt_qos"] = config.Mqtt.Lwt.Qos; root["mqtt_lwt_qos"] = config.Mqtt.Lwt.Qos;
root["mqtt_publish_interval"] = config.Mqtt.PublishInterval; root["mqtt_publish_interval"] = config.Mqtt.PublishInterval;
@ -272,7 +273,6 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as<String>().c_str(), sizeof(config.Mqtt.Hostname)); strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as<String>().c_str(), sizeof(config.Mqtt.Hostname));
strlcpy(config.Mqtt.Username, root["mqtt_username"].as<String>().c_str(), sizeof(config.Mqtt.Username)); strlcpy(config.Mqtt.Username, root["mqtt_username"].as<String>().c_str(), sizeof(config.Mqtt.Username));
strlcpy(config.Mqtt.Password, root["mqtt_password"].as<String>().c_str(), sizeof(config.Mqtt.Password)); strlcpy(config.Mqtt.Password, root["mqtt_password"].as<String>().c_str(), sizeof(config.Mqtt.Password));
strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Topic));
strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Topic)); strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Topic));
strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Online)); strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Online));
strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline)); strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline));
@ -285,6 +285,13 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>(); config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic)); strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic));
// Check if base topic was changed
if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str())) {
MqttHandleInverter.unsubscribeTopics();
strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Topic));
MqttHandleInverter.subscribeTopics();
}
WebApi.writeConfig(retMsg); WebApi.writeConfig(retMsg);
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);

View File

@ -7,11 +7,12 @@
#include "NetworkSettings.h" #include "NetworkSettings.h"
#include "PinMapping.h" #include "PinMapping.h"
#include "WebApi.h" #include "WebApi.h"
#include "__compiled_constants.h"
#include <AsyncJson.h> #include <AsyncJson.h>
#include <CpuTemperature.h>
#include <Hoymiles.h> #include <Hoymiles.h>
#include <LittleFS.h> #include <LittleFS.h>
#include <ResetReason.h> #include <ResetReason.h>
#include "__compiled_constants.h"
void WebApiSysstatusClass::init(AsyncWebServer& server, Scheduler& scheduler) void WebApiSysstatusClass::init(AsyncWebServer& server, Scheduler& scheduler)
{ {
@ -33,6 +34,7 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
root["sdkversion"] = ESP.getSdkVersion(); root["sdkversion"] = ESP.getSdkVersion();
root["cpufreq"] = ESP.getCpuFreqMHz(); root["cpufreq"] = ESP.getCpuFreqMHz();
root["cputemp"] = CpuTemperature.read();
root["heap_total"] = ESP.getHeapSize(); root["heap_total"] = ESP.getHeapSize();
root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap(); root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap();
@ -48,6 +50,7 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
root["chiprevision"] = ESP.getChipRevision(); root["chiprevision"] = ESP.getChipRevision();
root["chipmodel"] = ESP.getChipModel(); root["chipmodel"] = ESP.getChipModel();
root["chipcores"] = ESP.getChipCores(); root["chipcores"] = ESP.getChipCores();
root["flashsize"] = ESP.getFlashChipSize();
String reason; String reason;
reason = ResetReason::get_reset_reason_verbose(0); reason = ResetReason::get_reset_reason_verbose(0);

View File

@ -19,34 +19,34 @@
"pure-vue-chart": "^0.4.0", "pure-vue-chart": "^0.4.0",
"sortablejs": "^1.15.2", "sortablejs": "^1.15.2",
"spark-md5": "^3.0.2", "spark-md5": "^3.0.2",
"vue": "^3.4.27",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"vue": "^3.4.26",
"vue-google-charts": "^1.1.0", "vue-google-charts": "^1.1.0",
"vue3-calendar-heatmap": "^2.0.5",
"vue-i18n": "^9.13.1", "vue-i18n": "^9.13.1",
"vue-router": "^4.3.2", "vue-router": "^4.3.3"
"vue3-calendar-heatmap": "^2.0.5"
}, },
"devDependencies": { "devDependencies": {
"@intlify/unplugin-vue-i18n": "^4.0.0", "@intlify/unplugin-vue-i18n": "^4.0.0",
"@tsconfig/node18": "^18.2.4", "@tsconfig/node18": "^18.2.4",
"@types/bootstrap": "^5.2.10", "@types/bootstrap": "^5.2.10",
"@types/node": "^20.12.10", "@types/node": "^20.14.2",
"@types/pulltorefreshjs": "^0.1.7", "@types/pulltorefreshjs": "^0.1.7",
"@types/sortablejs": "^1.15.8", "@types/sortablejs": "^1.15.8",
"@types/spark-md5": "^3.0.4", "@types/spark-md5": "^3.0.4",
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-typescript": "^13.0.0", "@vue/eslint-config-typescript": "^13.0.0",
"@vue/tsconfig": "^0.5.1", "@vue/tsconfig": "^0.5.1",
"eslint": "^9.2.0", "eslint": "^9.4.0",
"eslint-plugin-vue": "^9.25.0", "eslint-plugin-vue": "^9.26.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"pulltorefreshjs": "^0.1.22", "pulltorefreshjs": "^0.1.22",
"sass": "^1.76.0", "sass": "^1.77.4",
"terser": "^5.31.0", "terser": "^5.31.1",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"vite": "^5.2.11", "vite": "^5.2.13",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-css-injected-by-js": "^3.5.1", "vite-plugin-css-injected-by-js": "^3.5.1",
"vue-tsc": "^2.0.16" "vue-tsc": "^2.0.21"
} }
} }

View File

@ -19,6 +19,17 @@
<th>{{ $t('hardwareinfo.CpuFrequency') }}</th> <th>{{ $t('hardwareinfo.CpuFrequency') }}</th>
<td>{{ systemStatus.cpufreq }} {{ $t('hardwareinfo.Mhz') }}</td> <td>{{ systemStatus.cpufreq }} {{ $t('hardwareinfo.Mhz') }}</td>
</tr> </tr>
<tr>
<th>{{ $t('hardwareinfo.CpuTemperature') }}</th>
<td>{{ $n(systemStatus.cputemp, 'celsius') }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.FlashSize') }}</th>
<td>
{{ $n(systemStatus.flashsize, 'byte') }}
({{ $n(systemStatus.flashsize / 1024 / 1024, 'megabyte') }})
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -65,8 +65,8 @@
"4009": "Wechselrichter Reihenfolge gespeichert!", "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ültiger Typ angegeben!",
"5004": "Ungültigen Inverter angegeben!", "5004": "Ungültiger Inverter angegeben!",
"6001": "Neustart durchgeführt!", "6001": "Neustart durchgeführt!",
"6002": "Neustart abgebrochen!", "6002": "Neustart abgebrochen!",
"7001": "MQTT-Server muss zwischen 1 und {max} Zeichen lang sein!", "7001": "MQTT-Server muss zwischen 1 und {max} Zeichen lang sein!",
@ -143,7 +143,7 @@
"LoadingInverter": "Warte auf Daten... (kann bis zu 10 Sekunden dauern)" "LoadingInverter": "Warte auf Daten... (kann bis zu 10 Sekunden dauern)"
}, },
"eventlog": { "eventlog": {
"Start": "Begin", "Start": "Beginn",
"Stop": "Ende", "Stop": "Ende",
"Id": "ID", "Id": "ID",
"Message": "Meldung" "Message": "Meldung"
@ -202,7 +202,9 @@
"ChipRevision": "Chip-Revision", "ChipRevision": "Chip-Revision",
"ChipCores": "Chip-Kerne", "ChipCores": "Chip-Kerne",
"CpuFrequency": "CPU-Frequenz", "CpuFrequency": "CPU-Frequenz",
"Mhz": "MHz" "Mhz": "MHz",
"CpuTemperature": "CPU-Temperatur",
"FlashSize": "Flash-Speichergröße"
}, },
"memoryinfo": { "memoryinfo": {
"MemoryInformation": "Speicherinformationen", "MemoryInformation": "Speicherinformationen",
@ -513,6 +515,7 @@
"ZeroRuntimeHint": "Nulle Laufzeit Daten (keine Ertragsdaten), wenn der Wechselrichter nicht erreichbar ist.", "ZeroRuntimeHint": "Nulle Laufzeit Daten (keine Ertragsdaten), wenn der Wechselrichter nicht erreichbar ist.",
"ZeroDay": "Nulle Tagesertrag um Mitternacht", "ZeroDay": "Nulle Tagesertrag um Mitternacht",
"ZeroDayHint": "Das funktioniert nur wenn der Wechselrichter nicht erreichbar ist. Wenn Daten aus dem Wechselrichter gelesen werden, werden deren Werte verwendet. (Ein Reset erfolgt nur beim Neustarten)", "ZeroDayHint": "Das funktioniert nur wenn der Wechselrichter nicht erreichbar ist. Wenn Daten aus dem Wechselrichter gelesen werden, werden deren Werte verwendet. (Ein Reset erfolgt nur beim Neustarten)",
"ClearEventlog": "Lösche Ereignisanzeige um Mitternacht",
"Cancel": "@:base.Cancel", "Cancel": "@:base.Cancel",
"Save": "@:base.Save", "Save": "@:base.Save",
"DeleteMsg": "Soll der Wechselrichter \"{name}\" mit der Seriennummer {serial} wirklich gelöscht werden?", "DeleteMsg": "Soll der Wechselrichter \"{name}\" mit der Seriennummer {serial} wirklich gelöscht werden?",
@ -590,9 +593,9 @@
"DefaultProfile": "(Standardeinstellungen)", "DefaultProfile": "(Standardeinstellungen)",
"ProfileHint": "Ihr Gerät reagiert möglicherweise nicht mehr, wenn Sie ein inkompatibles Profil wählen. In diesem Fall müssen Sie eine Löschung über das serielle Interface durchführen.", "ProfileHint": "Ihr Gerät reagiert möglicherweise nicht mehr, wenn Sie ein inkompatibles Profil wählen. In diesem Fall müssen Sie eine Löschung über das serielle Interface durchführen.",
"Display": "Display", "Display": "Display",
"PowerSafe": "Stromsparen aktivieren:", "PowerSafe": "Ausschalten wenn kein Inverter erreichbar:",
"PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt", "PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt",
"Screensaver": "Bildschirmschoner aktivieren:", "Screensaver": "OLED-Schutz gegen Einbrennen:",
"ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)", "ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)",
"DiagramMode": "Diagramm Modus:", "DiagramMode": "Diagramm Modus:",
"off": "Deaktiviert", "off": "Deaktiviert",

View File

@ -202,7 +202,9 @@
"ChipRevision": "Chip Revision", "ChipRevision": "Chip Revision",
"ChipCores": "Chip Cores", "ChipCores": "Chip Cores",
"CpuFrequency": "CPU Frequency", "CpuFrequency": "CPU Frequency",
"Mhz": "MHz" "Mhz": "MHz",
"CpuTemperature": "CPU Temperature",
"FlashSize": "Flash Memory Size"
}, },
"memoryinfo": { "memoryinfo": {
"MemoryInformation": "Memory Information", "MemoryInformation": "Memory Information",
@ -513,6 +515,7 @@
"ZeroRuntimeHint": "Zero runtime data (no yield data) if inverter becomes unreachable.", "ZeroRuntimeHint": "Zero runtime data (no yield data) if inverter becomes unreachable.",
"ZeroDay": "Zero daily yield at midnight", "ZeroDay": "Zero daily yield at midnight",
"ZeroDayHint": "This only works if the inverter is unreachable. If data is read from the inverter, it's values will be used. (Reset only occours on power cycle)", "ZeroDayHint": "This only works if the inverter is unreachable. If data is read from the inverter, it's values will be used. (Reset only occours on power cycle)",
"ClearEventlog": "Clear Eventlog at midnight",
"Cancel": "@:base.Cancel", "Cancel": "@:base.Cancel",
"Save": "@:base.Save", "Save": "@:base.Save",
"DeleteMsg": "Are you sure you want to delete the inverter \"{name}\" with serial number {serial}?", "DeleteMsg": "Are you sure you want to delete the inverter \"{name}\" with serial number {serial}?",
@ -590,9 +593,9 @@
"DefaultProfile": "(Default settings)", "DefaultProfile": "(Default settings)",
"ProfileHint": "Your device may stop responding if you select an incompatible profile. In this case, you must perform a deletion via the serial interface.", "ProfileHint": "Your device may stop responding if you select an incompatible profile. In this case, you must perform a deletion via the serial interface.",
"Display": "Display", "Display": "Display",
"PowerSafe": "Enable Power Save:", "PowerSafe": "Switch off if no solar:",
"PowerSafeHint": "Turn off the display if no inverter is producing.", "PowerSafeHint": "Turn off the display if no inverter is producing.",
"Screensaver": "Enable Screensaver:", "Screensaver": "OLED Anti burn-in:",
"ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)", "ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)",
"DiagramMode": "Diagram mode:", "DiagramMode": "Diagram mode:",
"off": "Off", "off": "Off",

View File

@ -202,7 +202,9 @@
"ChipRevision": "Révision de la puce", "ChipRevision": "Révision de la puce",
"ChipCores": "Nombre de cœurs", "ChipCores": "Nombre de cœurs",
"CpuFrequency": "Fréquence du CPU", "CpuFrequency": "Fréquence du CPU",
"Mhz": "MHz" "Mhz": "MHz",
"CpuTemperature": "CPU Temperature",
"FlashSize": "Taille de la mémoire flash"
}, },
"memoryinfo": { "memoryinfo": {
"MemoryInformation": "Informations sur la mémoire", "MemoryInformation": "Informations sur la mémoire",
@ -513,6 +515,7 @@
"ZeroRuntimeHint": "Zero runtime data (no yield data) if inverter becomes unreachable.", "ZeroRuntimeHint": "Zero runtime data (no yield data) if inverter becomes unreachable.",
"ZeroDay": "Zero daily yield at midnight", "ZeroDay": "Zero daily yield at midnight",
"ZeroDayHint": "This only works if the inverter is unreachable. If data is read from the inverter, it's values will be used. (Reset only occours on power cycle)", "ZeroDayHint": "This only works if the inverter is unreachable. If data is read from the inverter, it's values will be used. (Reset only occours on power cycle)",
"ClearEventlog": "Clear Eventlog at midnight",
"Cancel": "@:base.Cancel", "Cancel": "@:base.Cancel",
"Save": "@:base.Save", "Save": "@:base.Save",
"DeleteMsg": "Êtes-vous sûr de vouloir supprimer l'onduleur \"{name}\" avec le numéro de série \"{serial}\" ?", "DeleteMsg": "Êtes-vous sûr de vouloir supprimer l'onduleur \"{name}\" avec le numéro de série \"{serial}\" ?",
@ -590,9 +593,9 @@
"DefaultProfile": "(Réglages par défaut)", "DefaultProfile": "(Réglages par défaut)",
"ProfileHint": "Votre appareil peut cesser de répondre si vous sélectionnez un profil incompatible. Dans ce cas, vous devez effectuer une suppression via l'interface série.", "ProfileHint": "Votre appareil peut cesser de répondre si vous sélectionnez un profil incompatible. Dans ce cas, vous devez effectuer une suppression via l'interface série.",
"Display": "Affichage", "Display": "Affichage",
"PowerSafe": "Activer l'économiseur d'énergie", "PowerSafe": "Economiseur d'énergie",
"PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.", "PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.",
"Screensaver": "Activer l'écran de veille", "Screensaver": "OLED Anti burn-in",
"ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)", "ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)",
"DiagramMode": "Diagram mode:", "DiagramMode": "Diagram mode:",
"off": "Off", "off": "Off",

View File

@ -12,44 +12,23 @@ export const LOCALES = [
{ value: Locales.FR, caption: 'Français' }, { value: Locales.FR, caption: 'Français' },
] ]
export const dateTimeFormats: I18nOptions["datetimeFormats"] = { export const dateTimeFormats: I18nOptions["datetimeFormats"] = {};
[Locales.EN]: { export const numberFormats: I18nOptions["numberFormats"] = {};
'datetime': {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour12: false
}
},
[Locales.DE]: {
'datetime': {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour12: false
}
},
[Locales.FR]: {
'datetime': {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour12: false
}
}
};
export const numberFormats: I18nOptions["numberFormats"] = { LOCALES.forEach((locale) => {
[Locales.EN]: { dateTimeFormats[locale.value] = {
'datetime': {
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour12: false
}
};
numberFormats[locale.value] = {
decimal: { decimal: {
style: 'decimal', style: 'decimal',
}, },
@ -62,44 +41,19 @@ export const numberFormats: I18nOptions["numberFormats"] = {
percent: { percent: {
style: 'percent', style: 'percent',
}, },
kilobyte: { byte: {
style: 'unit', unit: 'kilobyte', style: 'unit', unit: 'byte',
},
},
[Locales.DE]: {
decimal: {
style: 'decimal',
},
decimalNoDigits: {
style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0
},
decimalTwoDigits: {
style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2
},
percent: {
style: 'percent',
}, },
kilobyte: { kilobyte: {
style: 'unit', unit: 'kilobyte', style: 'unit', unit: 'kilobyte',
}, },
}, megabyte: {
[Locales.FR]: { style: 'unit', unit: 'megabyte',
decimal: {
style: 'decimal',
}, },
decimalNoDigits: { celsius: {
style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0 style: 'unit', unit: 'celsius', maximumFractionDigits: 1,
}, },
decimalTwoDigits: { };
style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2 });
},
percent: {
style: 'percent',
},
kilobyte: {
style: 'unit', unit: 'kilobyte',
},
},
};
export const defaultLocale = Locales.EN; export const defaultLocale = Locales.EN;

View File

@ -17,6 +17,7 @@ export interface Inverter {
reachable_threshold: number; reachable_threshold: number;
zero_runtime: boolean; zero_runtime: boolean;
zero_day: boolean; zero_day: boolean;
clear_eventlog: boolean;
yieldday_correction: boolean; yieldday_correction: boolean;
channel: Array<InverterChannel>; channel: Array<InverterChannel>;
} }

View File

@ -4,6 +4,8 @@ export interface SystemStatus {
chiprevision: number; chiprevision: number;
chipcores: number; chipcores: number;
cpufreq: number; cpufreq: number;
cputemp: number;
flashsize: number;
// FirmwareInfo // FirmwareInfo
hostname: string; hostname: string;
sdkversion: string; sdkversion: string;

View File

@ -176,6 +176,8 @@
<InputElement :label="$t('inverteradmin.ZeroDay')" v-model="selectedInverterData.zero_day" type="checkbox" <InputElement :label="$t('inverteradmin.ZeroDay')" v-model="selectedInverterData.zero_day" type="checkbox"
:tooltip="$t('inverteradmin.ZeroDayHint')" wide /> :tooltip="$t('inverteradmin.ZeroDayHint')" wide />
<InputElement :label="$t('inverteradmin.ClearEventlog')" v-model="selectedInverterData.clear_eventlog" type="checkbox" wide />
<InputElement :label="$t('inverteradmin.YieldDayCorrection')" <InputElement :label="$t('inverteradmin.YieldDayCorrection')"
v-model="selectedInverterData.yieldday_correction" type="checkbox" v-model="selectedInverterData.yieldday_correction" type="checkbox"
:tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide /> :tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide />

View File

@ -149,15 +149,29 @@
dependencies: dependencies:
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": "@eslint-community/regexpp@^4.5.1":
version "4.10.0" version "4.8.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c"
integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==
"@eslint/eslintrc@^3.0.2": "@eslint-community/regexpp@^4.6.1":
version "3.0.2" version "4.6.2"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.0.2.tgz#36180f8e85bf34d2fe3ccc2261e8e204a411ab4e" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8"
integrity sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg== integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==
"@eslint/config-array@^0.15.1":
version "0.15.1"
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.15.1.tgz#1fa78b422d98f4e7979f2211a1fde137e26c7d61"
integrity sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==
dependencies:
"@eslint/object-schema" "^2.1.3"
debug "^4.3.1"
minimatch "^3.0.5"
"@eslint/eslintrc@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6"
integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==
dependencies: dependencies:
ajv "^6.12.4" ajv "^6.12.4"
debug "^4.3.2" debug "^4.3.2"
@ -169,34 +183,25 @@
minimatch "^3.1.2" minimatch "^3.1.2"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@eslint/js@9.2.0": "@eslint/js@9.4.0":
version "9.2.0" version "9.4.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.2.0.tgz#b0a9123e8e91a3d9a2eed3a04a6ed44fdab639aa" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.4.0.tgz#96a2edd37ec0551ce5f9540705be23951c008a0c"
integrity sha512-ESiIudvhoYni+MdsI8oD7skpprZ89qKocwRM2KEvhhBJ9nl5MRh7BXU5GTod7Mdygq+AUl+QzId6iWJKR/wABA== integrity sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==
"@humanwhocodes/config-array@^0.13.0": "@eslint/object-schema@^2.1.3":
version "0.13.0" version "2.1.3"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.3.tgz#e65ae80ee2927b4fd8c5c26b15ecacc2b2a6cc2a"
integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== integrity sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw==
dependencies:
"@humanwhocodes/object-schema" "^2.0.3"
debug "^4.3.1"
minimatch "^3.0.5"
"@humanwhocodes/module-importer@^1.0.1": "@humanwhocodes/module-importer@^1.0.1":
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^2.0.3": "@humanwhocodes/retry@^0.3.0":
version "2.0.3" version "0.3.0"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==
"@humanwhocodes/retry@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.2.3.tgz#c9aa036d1afa643f1250e83150f39efb3a15a631"
integrity sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==
"@intlify/bundle-utils@^8.0.0": "@intlify/bundle-utils@^8.0.0":
version "8.0.0" version "8.0.0"
@ -442,10 +447,10 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/node@^20.12.10": "@types/node@^20.14.2":
version "20.12.10" version "20.14.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.10.tgz#8f0c3f12b0f075eee1fe20c1afb417e9765bef76" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.2.tgz#a5f4d2bcb4b6a87bffcaa717718c5a0f208f4a18"
integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw== integrity sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==
dependencies: dependencies:
undici-types "~5.26.4" undici-types "~5.26.4"
@ -555,32 +560,33 @@
"@typescript-eslint/types" "7.2.0" "@typescript-eslint/types" "7.2.0"
eslint-visitor-keys "^3.4.1" eslint-visitor-keys "^3.4.1"
"@vitejs/plugin-vue@^5.0.4": "@vitejs/plugin-vue@^5.0.5":
version "5.0.4" version "5.0.5"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.5.tgz#e3dc11e427d4b818b7e3202766ad156e3d5e2eaa"
integrity sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ== integrity sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==
"@volar/language-core@2.2.1", "@volar/language-core@~2.2.0": "@volar/language-core@2.3.0", "@volar/language-core@~2.3.0-alpha.15":
version "2.2.1" version "2.3.0"
resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.2.1.tgz#bb4a28f93cd8598a2e2ca1c811ae113a848b5529" resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.3.0.tgz#ffb9b64c8b19d7f45b1fdcd9ae9d98d94bad7179"
integrity sha512-iHJAZKcYldZgyS8gx6DfIZApViVBeqbf6iPhqoZpG5A6F4zsZiFldKfwaKaBA3/wnOTWE2i8VUbXywI1WywCPg== integrity sha512-pvhL24WUh3VDnv7Yw5N1sjhPtdx7q9g+Wl3tggmnkMcyK8GcCNElF2zHiKznryn0DiUGk+eez/p2qQhz+puuHw==
dependencies: dependencies:
"@volar/source-map" "2.2.1" "@volar/source-map" "2.3.0"
"@volar/source-map@2.2.1": "@volar/source-map@2.3.0":
version "2.2.1" version "2.3.0"
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.2.1.tgz#d75b0c38659d3ea7e780d4251ac2b9436845ab97" resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.3.0.tgz#faf4df8f10ca40788f03c35eed3e2b7848110cc9"
integrity sha512-w1Bgpguhbp7YTr7VUFu6gb4iAZjeEPsOX4zpgiuvlldbzvIWDWy4t0jVifsIsxZ99HAu+c3swiME7wt+GeNqhA== integrity sha512-G/228aZjAOGhDjhlyZ++nDbKrS9uk+5DMaEstjvzglaAw7nqtDyhnQAsYzUg6BMP9BtwZ59RIw5HGePrutn00Q==
dependencies: dependencies:
muggle-string "^0.4.0" muggle-string "^0.4.0"
"@volar/typescript@~2.2.0": "@volar/typescript@~2.3.0-alpha.15":
version "2.2.1" version "2.3.0"
resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.2.1.tgz#21585b46cd61c9d63715642ee10418b144b12321" resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.3.0.tgz#00306942e95e2e22fed8daf73ec386cd72601ecf"
integrity sha512-Z/tqluR7Hz5/5dCqQp7wo9C/6tSv/IYl+tTzgzUt2NjTq95bKSsuO4E+V06D0c+3aP9x5S9jggLqw451hpnc6Q== integrity sha512-PtUwMM87WsKVeLJN33GSTUjBexlKfKgouWlOUIv7pjrOnTwhXHZNSmpc312xgXdTjQPpToK6KXSIcKu9sBQ5LQ==
dependencies: dependencies:
"@volar/language-core" "2.2.1" "@volar/language-core" "2.3.0"
path-browserify "^1.0.1" path-browserify "^1.0.1"
vscode-uri "^3.0.8"
"@vue/compiler-core@3.2.47": "@vue/compiler-core@3.2.47":
version "3.2.47" version "3.2.47"
@ -603,13 +609,13 @@
estree-walker "^2.0.2" estree-walker "^2.0.2"
source-map-js "^1.0.2" source-map-js "^1.0.2"
"@vue/compiler-core@3.4.26": "@vue/compiler-core@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.26.tgz#d507886520e83a6f8339ed55ed0b2b5d84b44b73" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.27.tgz#e69060f4b61429fe57976aa5872cfa21389e4d91"
integrity sha512-N9Vil6Hvw7NaiyFUFBPXrAyETIGlQ8KcFMkyk6hW1Cl6NvoqvP+Y8p1Eqvx+UdqsnrnI9+HMUEJegzia3mhXmQ== integrity sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==
dependencies: dependencies:
"@babel/parser" "^7.24.4" "@babel/parser" "^7.24.4"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
entities "^4.5.0" entities "^4.5.0"
estree-walker "^2.0.2" estree-walker "^2.0.2"
source-map-js "^1.2.0" source-map-js "^1.2.0"
@ -622,13 +628,13 @@
"@vue/compiler-core" "3.2.47" "@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47" "@vue/shared" "3.2.47"
"@vue/compiler-dom@3.4.26": "@vue/compiler-dom@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.26.tgz#acc7b788b48152d087d4bb9e655b795e3dbec554" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz#d51d35f40d00ce235d7afc6ad8b09dfd92b1cc1c"
integrity sha512-4CWbR5vR9fMg23YqFOhr6t6WB1Fjt62d6xdFPyj8pxrYub7d+OgZaObMsoxaF9yBUHPMiPFK303v61PwAuGvZA== integrity sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==
dependencies: dependencies:
"@vue/compiler-core" "3.4.26" "@vue/compiler-core" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
"@vue/compiler-dom@^3.4.0": "@vue/compiler-dom@^3.4.0":
version "3.4.21" version "3.4.21"
@ -649,16 +655,16 @@
optionalDependencies: optionalDependencies:
prettier "^1.18.2 || ^2.0.0" prettier "^1.18.2 || ^2.0.0"
"@vue/compiler-sfc@3.4.26": "@vue/compiler-sfc@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.26.tgz#c679f206829954c3c078d8a9be76d0098b8377ae" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz#399cac1b75c6737bf5440dc9cf3c385bb2959701"
integrity sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw== integrity sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==
dependencies: dependencies:
"@babel/parser" "^7.24.4" "@babel/parser" "^7.24.4"
"@vue/compiler-core" "3.4.26" "@vue/compiler-core" "3.4.27"
"@vue/compiler-dom" "3.4.26" "@vue/compiler-dom" "3.4.27"
"@vue/compiler-ssr" "3.4.26" "@vue/compiler-ssr" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.30.10" magic-string "^0.30.10"
postcss "^8.4.38" postcss "^8.4.38"
@ -688,13 +694,13 @@
"@vue/compiler-dom" "3.2.47" "@vue/compiler-dom" "3.2.47"
"@vue/shared" "3.2.47" "@vue/shared" "3.2.47"
"@vue/compiler-ssr@3.4.26": "@vue/compiler-ssr@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.26.tgz#22842d8adfff972d87bb798b8d496111f7f814b5" resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz#2a8ecfef1cf448b09be633901a9c020360472e3d"
integrity sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ== integrity sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==
dependencies: dependencies:
"@vue/compiler-dom" "3.4.26" "@vue/compiler-dom" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
"@vue/devtools-api@^6.5.0": "@vue/devtools-api@^6.5.0":
version "6.5.0" version "6.5.0"
@ -715,12 +721,12 @@
"@typescript-eslint/parser" "^7.1.1" "@typescript-eslint/parser" "^7.1.1"
vue-eslint-parser "^9.3.1" vue-eslint-parser "^9.3.1"
"@vue/language-core@2.0.16": "@vue/language-core@2.0.21":
version "2.0.16" version "2.0.21"
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.0.16.tgz#c059228e6a0a17b4505421da0e5747a4a04facbe" resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.0.21.tgz#882667d0c9f07bc884f163e75eed666234df77fe"
integrity sha512-Bc2sexRH99pznOph8mLw2BlRZ9edm7tW51kcBXgx8adAoOcZUWJj3UNSsdQ6H9Y8meGz7BoazVrVo/jUukIsPw== integrity sha512-vjs6KwnCK++kIXT+eI63BGpJHfHNVJcUCr3RnvJsccT3vbJnZV5IhHR2puEkoOkIbDdp0Gqi1wEnv3hEd3WsxQ==
dependencies: dependencies:
"@volar/language-core" "~2.2.0" "@volar/language-core" "~2.3.0-alpha.15"
"@vue/compiler-dom" "^3.4.0" "@vue/compiler-dom" "^3.4.0"
"@vue/shared" "^3.4.0" "@vue/shared" "^3.4.0"
computeds "^0.0.1" computeds "^0.0.1"
@ -739,37 +745,37 @@
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.25.7" magic-string "^0.25.7"
"@vue/reactivity@3.4.26": "@vue/reactivity@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.26.tgz#1191f543809d4c93e5b3e842ba83022350a3f205" resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.27.tgz#6ece72331bf719953f5eaa95ec60b2b8d49e3791"
integrity sha512-E/ynEAu/pw0yotJeLdvZEsp5Olmxt+9/WqzvKff0gE67tw73gmbx6tRkiagE/eH0UCubzSlGRebCbidB1CpqZQ== integrity sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==
dependencies: dependencies:
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
"@vue/runtime-core@3.4.26": "@vue/runtime-core@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.26.tgz#51ee971cb700370a67e5a510c4a84eff7491d658" resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.27.tgz#1b6e1d71e4604ba7442dd25ed22e4a1fc6adbbda"
integrity sha512-AFJDLpZvhT4ujUgZSIL9pdNcO23qVFh7zWCsNdGQBw8ecLNxOOnPcK9wTTIYCmBJnuPHpukOwo62a2PPivihqw== integrity sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==
dependencies: dependencies:
"@vue/reactivity" "3.4.26" "@vue/reactivity" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
"@vue/runtime-dom@3.4.26": "@vue/runtime-dom@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.26.tgz#179aa7c8dc964112e6d096bc8ec5f361111009a1" resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz#fe8d1ce9bbe8921d5dd0ad5c10df0e04ef7a5ee7"
integrity sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw== integrity sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==
dependencies: dependencies:
"@vue/runtime-core" "3.4.26" "@vue/runtime-core" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
csstype "^3.1.3" csstype "^3.1.3"
"@vue/server-renderer@3.4.26": "@vue/server-renderer@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.26.tgz#6d0c6b0366bfe0232579aea00e3ff6784e5a1c60" resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.27.tgz#3306176f37e648ba665f97dda3ce705687be63d2"
integrity sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw== integrity sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==
dependencies: dependencies:
"@vue/compiler-ssr" "3.4.26" "@vue/compiler-ssr" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
"@vue/shared@3.2.47": "@vue/shared@3.2.47":
version "3.2.47" version "3.2.47"
@ -781,10 +787,10 @@
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.21.tgz#de526a9059d0a599f0b429af7037cd0c3ed7d5a1" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.21.tgz#de526a9059d0a599f0b429af7037cd0c3ed7d5a1"
integrity sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g== integrity sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==
"@vue/shared@3.4.26": "@vue/shared@3.4.27":
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.26.tgz#f17854fb1faf889854aed4b23b60e86a8cab6403" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.27.tgz#f05e3cd107d157354bb4ae7a7b5fc9cf73c63b50"
integrity sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ== integrity sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==
"@vue/tsconfig@^0.5.1": "@vue/tsconfig@^0.5.1":
version "0.5.1" version "0.5.1"
@ -1262,10 +1268,10 @@ escodegen@^2.1.0:
optionalDependencies: optionalDependencies:
source-map "~0.6.1" source-map "~0.6.1"
eslint-plugin-vue@^9.25.0: eslint-plugin-vue@^9.26.0:
version "9.25.0" version "9.26.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.25.0.tgz#615cb7bb6d0e2140d21840b9aa51dce69e803e7a" resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz#bf7f5cce62c8f878059b91edae44d22974133af5"
integrity sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA== integrity sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==
dependencies: dependencies:
"@eslint-community/eslint-utils" "^4.4.0" "@eslint-community/eslint-utils" "^4.4.0"
globals "^13.24.0" globals "^13.24.0"
@ -1312,18 +1318,18 @@ eslint-visitor-keys@^4.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb"
integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==
eslint@^9.2.0: eslint@^9.4.0:
version "9.2.0" version "9.4.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.2.0.tgz#0700ebc99528753315d78090876911d3cdbf19fe" resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.4.0.tgz#79150c3610ae606eb131f1d648d5f43b3d45f3cd"
integrity sha512-0n/I88vZpCOzO+PQpt0lbsqmn9AsnsJAQseIqhZFI8ibQT0U1AkEKRxA3EVMos0BoHSXDQvCXY25TUjB5tr8Og== integrity sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==
dependencies: dependencies:
"@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1" "@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^3.0.2" "@eslint/config-array" "^0.15.1"
"@eslint/js" "9.2.0" "@eslint/eslintrc" "^3.1.0"
"@humanwhocodes/config-array" "^0.13.0" "@eslint/js" "9.4.0"
"@humanwhocodes/module-importer" "^1.0.1" "@humanwhocodes/module-importer" "^1.0.1"
"@humanwhocodes/retry" "^0.2.3" "@humanwhocodes/retry" "^0.3.0"
"@nodelib/fs.walk" "^1.2.8" "@nodelib/fs.walk" "^1.2.8"
ajv "^6.12.4" ajv "^6.12.4"
chalk "^4.0.0" chalk "^4.0.0"
@ -2381,10 +2387,10 @@ safe-regex-test@^1.0.0:
es-errors "^1.3.0" es-errors "^1.3.0"
is-regex "^1.1.4" is-regex "^1.1.4"
sass@^1.76.0: sass@^1.77.4:
version "1.76.0" version "1.77.4"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.76.0.tgz#fe15909500735ac154f0dc7386d656b62b03987d" resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.4.tgz#92059c7bfc56b827c56eb116778d157ec017a5cd"
integrity sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw== integrity sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==
dependencies: dependencies:
chokidar ">=3.0.0 <4.0.0" chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0" immutable "^4.0.0"
@ -2611,10 +2617,10 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
terser@^5.31.0: terser@^5.31.1:
version "5.31.0" version "5.31.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.0.tgz#06eef86f17007dbad4593f11a574c7f5eb02c6a1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.1.tgz#735de3c987dd671e95190e6b98cfe2f07f3cf0d4"
integrity sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg== integrity sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==
dependencies: dependencies:
"@jridgewell/source-map" "^0.3.3" "@jridgewell/source-map" "^0.3.3"
acorn "^8.8.2" acorn "^8.8.2"
@ -2775,10 +2781,10 @@ vite-plugin-css-injected-by-js@^3.5.1:
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.1.tgz#b9c568c21b131d08e31aa6d368ee39c9d6c1b6c1" resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.1.tgz#b9c568c21b131d08e31aa6d368ee39c9d6c1b6c1"
integrity sha512-9ioqwDuEBxW55gNoWFEDhfLTrVKXEEZgl5adhWmmqa88EQGKfTmexy4v1Rh0pAS6RhKQs2bUYQArprB32JpUZQ== integrity sha512-9ioqwDuEBxW55gNoWFEDhfLTrVKXEEZgl5adhWmmqa88EQGKfTmexy4v1Rh0pAS6RhKQs2bUYQArprB32JpUZQ==
vite@^5.2.11: vite@^5.2.13:
version "5.2.11" version "5.2.13"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.11.tgz#726ec05555431735853417c3c0bfb36003ca0cbd" resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.13.tgz#945ababcbe3d837ae2479c29f661cd20bc5e1a80"
integrity sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ== integrity sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==
dependencies: dependencies:
esbuild "^0.20.1" esbuild "^0.20.1"
postcss "^8.4.38" postcss "^8.4.38"
@ -2786,7 +2792,25 @@ vite@^5.2.11:
optionalDependencies: optionalDependencies:
fsevents "~2.3.3" fsevents "~2.3.3"
vue-eslint-parser@^9.3.1, vue-eslint-parser@^9.4.2: vscode-uri@^3.0.8:
version "3.0.8"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f"
integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
vue-eslint-parser@^9.3.1:
version "9.3.1"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz#429955e041ae5371df5f9e37ebc29ba046496182"
integrity sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==
dependencies:
debug "^4.3.4"
eslint-scope "^7.1.1"
eslint-visitor-keys "^3.3.0"
espree "^9.3.1"
esquery "^1.4.0"
lodash "^4.17.21"
semver "^7.3.6"
vue-eslint-parser@^9.4.2:
version "9.4.2" version "9.4.2"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz#02ffcce82042b082292f2d1672514615f0d95b6d" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz#02ffcce82042b082292f2d1672514615f0d95b6d"
integrity sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ== integrity sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==
@ -2813,10 +2837,10 @@ vue-i18n@^9.13.1:
"@intlify/shared" "9.13.1" "@intlify/shared" "9.13.1"
"@vue/devtools-api" "^6.5.0" "@vue/devtools-api" "^6.5.0"
vue-router@^4.3.2: vue-router@^4.3.3:
version "4.3.2" version "4.3.3"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.3.2.tgz#08096c7765dacc6832f58e35f7a081a8b34116a7" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.3.3.tgz#7505509d429a36694b12ba1f6530016c5ce5f6bf"
integrity sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q== integrity sha512-8Q+u+WP4N2SXY38FDcF2H1dUEbYVHVPtPCPZj/GTZx8RCbiB8AtJP9+YIxn4Vs0svMTNQcLIzka4GH7Utkx9xQ==
dependencies: dependencies:
"@vue/devtools-api" "^6.5.1" "@vue/devtools-api" "^6.5.1"
@ -2828,13 +2852,13 @@ vue-template-compiler@^2.7.14:
de-indent "^1.0.2" de-indent "^1.0.2"
he "^1.2.0" he "^1.2.0"
vue-tsc@^2.0.16: vue-tsc@^2.0.21:
version "2.0.16" version "2.0.21"
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.0.16.tgz#ba82c4cdac283e8e39e30e817c8c1c967e528358" resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.0.21.tgz#c574a2c20e8a5e5643af546c6051319cdf983239"
integrity sha512-/gHAWJa216PeEhfxtAToIbxdWgw01wuQzo48ZUqMYVEyNqDp+OYV9xMO5HaPS2P3Ls0+EsjguMZLY4cGobX4Ew== integrity sha512-E6x1p1HaHES6Doy8pqtm7kQern79zRtIewkf9fiv7Y43Zo4AFDS5hKi+iHi2RwEhqRmuiwliB1LCEFEGwvxQnw==
dependencies: dependencies:
"@volar/typescript" "~2.2.0" "@volar/typescript" "~2.3.0-alpha.15"
"@vue/language-core" "2.0.16" "@vue/language-core" "2.0.21"
semver "^7.5.4" semver "^7.5.4"
vue3-calendar-heatmap@^2.0.5: vue3-calendar-heatmap@^2.0.5:
@ -2850,16 +2874,16 @@ vue@^2.6.10:
"@vue/compiler-sfc" "2.7.16" "@vue/compiler-sfc" "2.7.16"
csstype "^3.1.0" csstype "^3.1.0"
vue@^3.4.26: vue@^3.4.27:
version "3.4.26" version "3.4.27"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.26.tgz#936c97e37672c737705d7bdfa62c31af18742269" resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.27.tgz#40b7d929d3e53f427f7f5945386234d2854cc2a1"
integrity sha512-bUIq/p+VB+0xrJubaemrfhk1/FiW9iX+pDV+62I/XJ6EkspAO9/DXEjbDFoe8pIfOZBqfk45i9BMc41ptP/uRg== integrity sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==
dependencies: dependencies:
"@vue/compiler-dom" "3.4.26" "@vue/compiler-dom" "3.4.27"
"@vue/compiler-sfc" "3.4.26" "@vue/compiler-sfc" "3.4.27"
"@vue/runtime-dom" "3.4.26" "@vue/runtime-dom" "3.4.27"
"@vue/server-renderer" "3.4.26" "@vue/server-renderer" "3.4.27"
"@vue/shared" "3.4.26" "@vue/shared" "3.4.27"
webpack-sources@^3.2.3: webpack-sources@^3.2.3:
version "3.2.3" version "3.2.3"

Binary file not shown.