Merge remote-tracking branch 'tbnobody/OpenDTU/master' into development
This commit is contained in:
commit
c72ae561c7
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -23,14 +23,14 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
run: git fetch --force --tags origin
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
@ -69,13 +69,13 @@ jobs:
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
|
||||
2
.github/workflows/cpplint.yml
vendored
2
.github/workflows/cpplint.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install dependencies
|
||||
|
||||
76
docs/DeviceProfiles/AhoyDTU-ESP32.json
Normal file
76
docs/DeviceProfiles/AhoyDTU-ESP32.json
Normal file
@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"name": "AhoyDTU ESP32 Display LED",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"led": {
|
||||
"led0": 25,
|
||||
"led1": 26
|
||||
},
|
||||
"display": {
|
||||
"type": 2,
|
||||
"data": 21,
|
||||
"clk": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32 Display",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"display": {
|
||||
"type": 2,
|
||||
"data": 21,
|
||||
"clk": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32 LED",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
},
|
||||
"led": {
|
||||
"led0": 25,
|
||||
"led1": 26
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AhoyDTU ESP32",
|
||||
"links": [
|
||||
{"name": "Information", "url": "https://ahoydtu.de/getting_started/"}
|
||||
],
|
||||
"nrf24": {
|
||||
"miso": 19,
|
||||
"mosi": 23,
|
||||
"clk": 18,
|
||||
"irq": 16,
|
||||
"en": 4,
|
||||
"cs": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
74
docs/DeviceProfiles/liligo_t-eth-lite_poe.json
Normal file
74
docs/DeviceProfiles/liligo_t-eth-lite_poe.json
Normal file
@ -0,0 +1,74 @@
|
||||
[
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE CMT",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"cmt": {
|
||||
"clk": 15,
|
||||
"cs": 32,
|
||||
"fcs": 33,
|
||||
"sdio": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE NRF24",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"nrf24": {
|
||||
"miso": 34,
|
||||
"mosi": 13,
|
||||
"clk": 14,
|
||||
"irq": 35,
|
||||
"en": 4,
|
||||
"cs": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "LILYGO T-ETH-Lite-POE NRF24 + Display",
|
||||
"links": [
|
||||
{"name": "Datasheet", "url": "https://www.lilygo.cc/products/t-eth-lite"}
|
||||
],
|
||||
"eth": {
|
||||
"enabled": true,
|
||||
"phy_addr": 0,
|
||||
"power": 12,
|
||||
"mdc": 23,
|
||||
"mdio": 18,
|
||||
"type": 2,
|
||||
"clk_mode": 0
|
||||
},
|
||||
"nrf24": {
|
||||
"miso": 34,
|
||||
"mosi": 13,
|
||||
"clk": 14,
|
||||
"irq": 35,
|
||||
"en": 4,
|
||||
"cs": 2
|
||||
},
|
||||
"display": {
|
||||
"type": 3,
|
||||
"data": 32,
|
||||
"clk": 33
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -11,4 +11,5 @@ public:
|
||||
static int getTimezoneOffset();
|
||||
static void restartDtu();
|
||||
static bool checkJsonAlloc(const DynamicJsonDocument& doc, const char* function, const uint16_t line);
|
||||
static void removeAllFiles();
|
||||
};
|
||||
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onConfigListGet(AsyncWebServerRequest* request);
|
||||
void onConfigUploadFinish(AsyncWebServerRequest* request);
|
||||
void onConfigUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -11,6 +11,4 @@ public:
|
||||
private:
|
||||
void onDeviceAdminGet(AsyncWebServerRequest* request);
|
||||
void onDeviceAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -10,6 +10,4 @@ public:
|
||||
|
||||
private:
|
||||
void onDevInfoStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -13,8 +13,6 @@ private:
|
||||
void onDtuAdminGet(AsyncWebServerRequest* request);
|
||||
void onDtuAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
|
||||
Task _applyDataTask;
|
||||
void applyDataTaskCb();
|
||||
};
|
||||
|
||||
@ -10,6 +10,4 @@ public:
|
||||
|
||||
private:
|
||||
void onEventlogStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -11,6 +11,4 @@ public:
|
||||
private:
|
||||
void onFirmwareUpdateFinish(AsyncWebServerRequest* request);
|
||||
void onFirmwareUpdateUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -11,6 +11,4 @@ public:
|
||||
private:
|
||||
void onGridProfileStatus(AsyncWebServerRequest* request);
|
||||
void onGridProfileRawdata(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onInverterEdit(AsyncWebServerRequest* request);
|
||||
void onInverterDelete(AsyncWebServerRequest* request);
|
||||
void onInverterOrder(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -11,6 +11,4 @@ public:
|
||||
private:
|
||||
void onLimitStatus(AsyncWebServerRequest* request);
|
||||
void onLimitPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -10,6 +10,4 @@ public:
|
||||
|
||||
private:
|
||||
void onRebootPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -15,6 +15,4 @@ private:
|
||||
void onMqttAdminGet(AsyncWebServerRequest* request);
|
||||
void onMqttAdminPost(AsyncWebServerRequest* request);
|
||||
String getTlsCertInfo(const char* cert);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -12,6 +12,4 @@ private:
|
||||
void onNetworkStatus(AsyncWebServerRequest* request);
|
||||
void onNetworkAdminGet(AsyncWebServerRequest* request);
|
||||
void onNetworkAdminPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -14,6 +14,4 @@ private:
|
||||
void onNtpAdminPost(AsyncWebServerRequest* request);
|
||||
void onNtpTimeGet(AsyncWebServerRequest* request);
|
||||
void onNtpTimePost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -11,6 +11,4 @@ public:
|
||||
private:
|
||||
void onPowerStatus(AsyncWebServerRequest* request);
|
||||
void onPowerPost(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -17,8 +17,6 @@ private:
|
||||
|
||||
void addPanelInfo(AsyncResponseStream* stream, const String& serial, const uint8_t idx, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
|
||||
enum MetricType_t {
|
||||
NONE = 0,
|
||||
GAUGE,
|
||||
|
||||
@ -13,6 +13,4 @@ private:
|
||||
void onSecurityPost(AsyncWebServerRequest* request);
|
||||
|
||||
void onAuthenticateGet(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -10,6 +10,4 @@ public:
|
||||
|
||||
private:
|
||||
void onSystemStatus(AsyncWebServerRequest* request);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
|
||||
@ -9,5 +9,5 @@ public:
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
AsyncWebServer* _server;
|
||||
void responseBinaryDataWithETagCache(AsyncWebServerRequest* request, const String &contentType, const String &contentEncoding, const uint8_t *content, size_t len);
|
||||
};
|
||||
|
||||
@ -10,7 +10,6 @@ public:
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
AsyncWebServer* _server;
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
Task _wsCleanupTask;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "Configuration.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Hoymiles.h>
|
||||
@ -12,17 +13,19 @@ public:
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void generateJsonResponse(JsonVariant& root);
|
||||
void addField(JsonObject& root, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic = "");
|
||||
void addTotalField(JsonObject& root, const String& name, const float value, const String& unit, const uint8_t digits);
|
||||
static void generateInverterCommonJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv);
|
||||
static void generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv);
|
||||
static void generateCommonJsonResponse(JsonVariant& root);
|
||||
|
||||
static void addField(JsonObject& root, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic = "");
|
||||
static void addTotalField(JsonObject& root, const String& name, const float value, const String& unit, const uint8_t digits);
|
||||
|
||||
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
AsyncWebSocket _ws;
|
||||
|
||||
uint32_t _lastWsPublish = 0;
|
||||
uint32_t _newestInverterTimestamp = 0;
|
||||
uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };
|
||||
|
||||
std::mutex _mutex;
|
||||
|
||||
|
||||
@ -239,8 +239,11 @@ CountryModeId_t HoymilesRadio_CMT::getCountryMode() const
|
||||
|
||||
void HoymilesRadio_CMT::setCountryMode(const CountryModeId_t mode)
|
||||
{
|
||||
_radio->setFrequencyBand(countryDefinition.at(mode).Band);
|
||||
_countryMode = mode;
|
||||
if (!_isInitialized) {
|
||||
return;
|
||||
}
|
||||
_radio->setFrequencyBand(countryDefinition.at(mode).Band);
|
||||
}
|
||||
|
||||
uint32_t HoymilesRadio_CMT::getInvBootFrequency() const
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_1CH.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_1CH::HMS_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_1CHv2.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 18, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_1CHv2::HMS_1CHv2(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_2CH.h"
|
||||
|
||||
@ -10,14 +10,14 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 4, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 8, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -29,10 +29,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_2CH::HMS_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMS_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 4, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 8, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 30, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 34, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 46, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 28, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 32, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 36, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 48, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 42, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 50, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 58, 2, 100, false, 2 },
|
||||
@ -43,10 +43,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 62, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 64, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMS_4CH::HMS_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMT_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 74, 2, 10, false, 1 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_UAC_1N, UNIT_V, 68, 2, 10, false, 1 },
|
||||
@ -52,10 +52,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 94, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 96, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMT_4CH::HMT_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "HMT_6CH.h"
|
||||
|
||||
@ -10,42 +10,42 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH4, FLD_UDC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH4, FLD_IDC, UNIT_A, 48, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH4, FLD_PDC, UNIT_W, 52, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH4, FLD_YT, UNIT_KWH, 56, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH4, FLD_YD, UNIT_WH, 64, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH4, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH4, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH4, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH4, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH5, FLD_UDC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH5, FLD_IDC, UNIT_A, 50, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH5, FLD_PDC, UNIT_W, 54, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH5, FLD_YT, UNIT_KWH, 60, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH5, FLD_YD, UNIT_WH, 66, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH5, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH5, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH5, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH5, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 74, 2, 10, false, 1 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_UAC_1N, UNIT_V, 68, 2, 10, false, 1 },
|
||||
@ -57,7 +57,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_AC, CH0, FLD_F, UNIT_HZ, 80, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PAC, UNIT_W, 82, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_Q, UNIT_VAR, 84, 2, 10, true, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 86, 2, 100, false, 2 }, // dummy
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, CALC_TOTAL_IAC, 0, CMD_CALC, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_1, UNIT_A, 86, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_2, UNIT_A, 88, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_IAC_3, UNIT_A, 90, 2, 100, false, 2 },
|
||||
@ -66,10 +66,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 94, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 96, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HMT_6CH::HMT_6CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// 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_1CH.h"
|
||||
|
||||
@ -10,7 +10,7 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
@ -22,10 +22,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_1CH::HM_1CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
// 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_2CH.h"
|
||||
|
||||
@ -11,14 +11,14 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 10, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
@ -30,10 +30,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_2CH::HM_2CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// 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_4CH.h"
|
||||
|
||||
@ -10,28 +10,28 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, CALC_UDC_CH, CH0, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, CALC_CH_UDC, CH0, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, CALC_UDC_CH, CH2, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, CALC_CH_UDC, CH2, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_CH_IRR, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 54, 2, 100, false, 2 },
|
||||
@ -43,10 +43,10 @@ static const byteAssign_t byteAssignment[] = {
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 58, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 60, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_INV, CH0, FLD_YD, UNIT_WH, CALC_TOTAL_YD, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_INV, CH0, FLD_YT, UNIT_KWH, CALC_TOTAL_YT, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_INV, CH0, FLD_PDC, UNIT_W, CALC_TOTAL_PDC, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EFF, UNIT_PCT, CALC_TOTAL_EFF, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
|
||||
HM_4CH::HM_4CH(HoymilesRadio* radio, const uint64_t serial)
|
||||
|
||||
@ -28,9 +28,11 @@ const devInfo_t devInfo[] = {
|
||||
{ { 0x10, 0x12, 0x30, ALL }, 1500, "HM-1500-4T" },
|
||||
{ { 0x10, 0x10, 0x10, 0x15 }, static_cast<uint16_t>(300 * 0.7), "HM-300-1T" }, // HM-300 factory limitted to 70%
|
||||
|
||||
{ { 0x10, 0x20, 0x11, ALL }, 300, "HMS-300-1T" }, // 00
|
||||
{ { 0x10, 0x20, 0x21, ALL }, 350, "HMS-350-1T" }, // 00
|
||||
{ { 0x10, 0x20, 0x41, ALL }, 400, "HMS-400-1T" }, // 00
|
||||
{ { 0x10, 0x10, 0x51, ALL }, 450, "HMS-450-1T" }, // 01
|
||||
{ { 0x10, 0x20, 0x51, ALL }, 450, "HMS-450-1T" }, // 03
|
||||
{ { 0x10, 0x10, 0x71, ALL }, 500, "HMS-500-1T" }, // 02
|
||||
{ { 0x10, 0x20, 0x71, ALL }, 500, "HMS-500-1T v2" }, // 02
|
||||
{ { 0x10, 0x21, 0x11, ALL }, 600, "HMS-600-2T" }, // 01
|
||||
@ -47,6 +49,7 @@ const devInfo_t devInfo[] = {
|
||||
|
||||
{ { 0x10, 0x32, 0x41, ALL }, 1600, "HMT-1600-4T" }, // 00
|
||||
{ { 0x10, 0x32, 0x51, ALL }, 1800, "HMT-1800-4T" }, // 00
|
||||
{ { 0x10, 0x32, 0x71, ALL }, 2000, "HMT-2000-4T" }, // 0
|
||||
|
||||
{ { 0x10, 0x33, 0x11, ALL }, 1800, "HMT-1800-6T" }, // 01
|
||||
{ { 0x10, 0x33, 0x31, ALL }, 2250, "HMT-2250-6T" } // 01
|
||||
|
||||
@ -5,12 +5,13 @@
|
||||
#include "StatisticsParser.h"
|
||||
#include "../Hoymiles.h"
|
||||
|
||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcUdcCh(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcIrradiation(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalYieldTotal(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalYieldDay(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcChUdc(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalPowerDc(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalEffiency(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcChIrradiation(StatisticsParser* iv, uint8_t arg0);
|
||||
static float calcTotalCurrentAc(StatisticsParser* iv, uint8_t arg0);
|
||||
|
||||
using func_t = float(StatisticsParser*, uint8_t);
|
||||
|
||||
@ -20,12 +21,13 @@ struct calcFunc_t {
|
||||
};
|
||||
|
||||
const calcFunc_t calcFunctions[] = {
|
||||
{ CALC_YT_CH0, &calcYieldTotalCh0 },
|
||||
{ CALC_YD_CH0, &calcYieldDayCh0 },
|
||||
{ CALC_UDC_CH, &calcUdcCh },
|
||||
{ CALC_PDC_CH0, &calcPowerDcCh0 },
|
||||
{ CALC_EFF_CH0, &calcEffiencyCh0 },
|
||||
{ CALC_IRR_CH, &calcIrradiation }
|
||||
{ CALC_TOTAL_YT, &calcTotalYieldTotal },
|
||||
{ CALC_TOTAL_YD, &calcTotalYieldDay },
|
||||
{ CALC_CH_UDC, &calcChUdc },
|
||||
{ CALC_TOTAL_PDC, &calcTotalPowerDc },
|
||||
{ CALC_TOTAL_EFF, &calcTotalEffiency },
|
||||
{ CALC_CH_IRR, &calcChIrradiation },
|
||||
{ CALC_TOTAL_IAC, &calcTotalCurrentAc }
|
||||
};
|
||||
|
||||
const FieldId_t runtimeFields[] = {
|
||||
@ -386,7 +388,7 @@ void StatisticsParser::resetYieldDayCorrection()
|
||||
}
|
||||
}
|
||||
|
||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalYieldTotal(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -395,7 +397,7 @@ static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
return yield;
|
||||
}
|
||||
|
||||
static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalYieldDay(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -405,12 +407,12 @@ static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
|
||||
// arg0 = channel of source
|
||||
static float calcUdcCh(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcChUdc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
return iv->getChannelFieldValue(TYPE_DC, static_cast<ChannelNum_t>(arg0), FLD_UDC);
|
||||
}
|
||||
|
||||
static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalPowerDc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float dcPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
@ -419,8 +421,7 @@ static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
return dcPower;
|
||||
}
|
||||
|
||||
// arg0 = channel
|
||||
static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcTotalEffiency(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float acPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_AC)) {
|
||||
@ -439,7 +440,7 @@ static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
|
||||
// arg0 = channel
|
||||
static float calcIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcChIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
if (nullptr != iv) {
|
||||
if (iv->getStringMaxPower(arg0) > 0)
|
||||
@ -447,3 +448,12 @@ static float calcIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static float calcTotalCurrentAc(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float acCurrent = 0;
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1);
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_2);
|
||||
acCurrent += iv->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_3);
|
||||
return acCurrent;
|
||||
}
|
||||
|
||||
@ -55,12 +55,13 @@ const char* const fields[] = { "Voltage", "Current", "Power", "YieldDay", "Yield
|
||||
|
||||
// indices to calculation functions, defined in hmInverter.h
|
||||
enum {
|
||||
CALC_YT_CH0 = 0,
|
||||
CALC_YD_CH0,
|
||||
CALC_UDC_CH,
|
||||
CALC_PDC_CH0,
|
||||
CALC_EFF_CH0,
|
||||
CALC_IRR_CH
|
||||
CALC_TOTAL_YT = 0,
|
||||
CALC_TOTAL_YD,
|
||||
CALC_CH_UDC,
|
||||
CALC_TOTAL_PDC,
|
||||
CALC_TOTAL_EFF,
|
||||
CALC_CH_IRR,
|
||||
CALC_TOTAL_IAC
|
||||
};
|
||||
enum { CMD_CALC = 0xffff };
|
||||
|
||||
|
||||
6
partitions_custom_16mb.csv
Normal file
6
partitions_custom_16mb.csv
Normal file
@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000
|
||||
otadata, data, ota, 0xE000, 0x2000
|
||||
app0, app, ota_0, 0x10000, 0x7E0000
|
||||
app1, app, ota_1, 0x7F0000, 0x7E0000
|
||||
spiffs, data, spiffs, 0xFD0000, 0x30000
|
||||
|
@ -36,9 +36,9 @@ build_unflags =
|
||||
-std=gnu++11
|
||||
|
||||
lib_deps =
|
||||
https://github.com/yubox-node-org/ESPAsyncWebServer
|
||||
mathieucarbou/ESP Async WebServer @ 2.7.0
|
||||
bblanchon/ArduinoJson @ ^6.21.5
|
||||
https://github.com/bertmelis/espMqttClient.git#v1.5.0
|
||||
https://github.com/bertmelis/espMqttClient.git#v1.6.0
|
||||
nrf24/RF24 @ ^1.4.8
|
||||
olikraus/U8g2 @ ^2.35.9
|
||||
buelowp/sunset @ ^1.1.7
|
||||
@ -54,7 +54,7 @@ extra_scripts =
|
||||
pre:pio-scripts/patch_apply.py
|
||||
post:pio-scripts/create_factory_bin.py
|
||||
|
||||
board_build.partitions = partitions_custom.csv
|
||||
board_build.partitions = partitions_custom_4mb.csv
|
||||
board_build.filesystem = littlefs
|
||||
board_build.embed_files =
|
||||
webapp_dist/index.html.gz
|
||||
@ -80,6 +80,16 @@ board = esp32dev
|
||||
build_flags = ${env.build_flags}
|
||||
|
||||
|
||||
[env:generic_esp32_16mb_psram]
|
||||
board = esp32dev
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = partitions_custom_16mb.csv
|
||||
board_upload.flash_size = 16MB
|
||||
build_flags = ${env.build_flags}
|
||||
-DBOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
|
||||
|
||||
[env:generic_esp32c3]
|
||||
board = esp32-c3-devkitc-02
|
||||
custom_patches = ${env.custom_patches},esp32c3
|
||||
|
||||
@ -81,14 +81,17 @@ void DatastoreClass::loop()
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_INV)) {
|
||||
if (cfg->Poll_Enable) {
|
||||
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
_totalAcYieldTotalEnabled += inv->Statistics()->getChannelFieldValue(TYPE_INV, c, FLD_YT);
|
||||
_totalAcYieldDayEnabled += inv->Statistics()->getChannelFieldValue(TYPE_INV, c, FLD_YD);
|
||||
|
||||
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YT));
|
||||
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_YD));
|
||||
_totalAcYieldTotalDigits = max<unsigned int>(_totalAcYieldTotalDigits, inv->Statistics()->getChannelFieldDigits(TYPE_INV, c, FLD_YT));
|
||||
_totalAcYieldDayDigits = max<unsigned int>(_totalAcYieldDayDigits, inv->Statistics()->getChannelFieldDigits(TYPE_INV, c, FLD_YD));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
if (inv->getEnablePolling()) {
|
||||
_totalAcPowerEnabled += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
_totalAcPowerDigits = max<unsigned int>(_totalAcPowerDigits, inv->Statistics()->getChannelFieldDigits(TYPE_AC, c, FLD_PAC));
|
||||
|
||||
@ -37,6 +37,7 @@ static const char* const i18n_meter_power_w[] = { "grid: %.0f W", "Netz: %.0
|
||||
static const char* const i18n_meter_power_kw[] = { "grid: %.1f kW", "Netz: %.1f kW", "reseau: %.1f kW" };
|
||||
static const char* const i18n_yield_today_wh[] = { "today: %4.0f Wh", "Heute: %4.0f Wh", "auj.: %4.0f Wh" };
|
||||
static const char* const i18n_yield_total_kwh[] = { "total: %.1f kWh", "Ges.: %.1f kWh", "total: %.1f kWh" };
|
||||
static const char* const i18n_yield_total_mwh[] = { "total: %.0f kWh", "Ges.: %.0f kWh", "total: %.0f kWh" };
|
||||
static const char* const i18n_date_format[] = { "%m/%d/%Y %H:%M", "%d.%m.%Y %H:%M", "%d/%m/%Y %H:%M" };
|
||||
|
||||
DisplayGraphicClass::DisplayGraphicClass()
|
||||
@ -115,27 +116,23 @@ void DisplayGraphicClass::printText(const char* text, const uint8_t line)
|
||||
if (!_isLarge) {
|
||||
dispX = (line == 0) ? 5 : 0;
|
||||
} else {
|
||||
switch (line) {
|
||||
case 0:
|
||||
if (_diagram_mode == DiagramMode_t::Small) {
|
||||
if (line == 0 && _diagram_mode == DiagramMode_t::Small) {
|
||||
// Center between left border and diagram
|
||||
dispX = (CHART_POSX - _display->getStrWidth(text)) / 2;
|
||||
} else {
|
||||
// Center on screen
|
||||
dispX = (_display->getDisplayWidth() - _display->getStrWidth(text)) / 2;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Center on screen
|
||||
dispX = (_display->getDisplayWidth() - _display->getStrWidth(text)) / 2;
|
||||
break;
|
||||
default:
|
||||
dispX = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispX += enableScreensaver ? (_mExtra % 7) : 0;
|
||||
if (enableScreensaver) {
|
||||
unsigned maxOffset = (_isLarge ? 8 : 6);
|
||||
unsigned period = 2 * maxOffset;
|
||||
unsigned step = _mExtra % period;
|
||||
int offset = (step <= maxOffset) ? step : (period - step);
|
||||
offset -= (_isLarge ? 5 : 0); // oscillate around center on large screens
|
||||
dispX += offset;
|
||||
}
|
||||
_display->drawStr(dispX, _lineOffsets[line], text);
|
||||
}
|
||||
|
||||
@ -248,7 +245,9 @@ void DisplayGraphicClass::loop()
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], Datastore.getTotalAcYieldDayEnabled());
|
||||
printText(_fmtText, 1);
|
||||
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_total_kwh[_display_language], Datastore.getTotalAcYieldTotalEnabled());
|
||||
const float watts = Datastore.getTotalAcYieldTotalEnabled();
|
||||
auto const format = (watts >= 1000) ? i18n_yield_total_mwh : i18n_yield_total_kwh;
|
||||
snprintf(_fmtText, sizeof(_fmtText), format[_display_language], watts);
|
||||
printText(_fmtText, 2);
|
||||
//<=======================
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ void MqttHandleHassClass::publishInverterField(std::shared_ptr<InverterAbstract>
|
||||
const String serial = inv->serialString();
|
||||
|
||||
String fieldName;
|
||||
if (type == TYPE_AC && fieldType.fieldId == FLD_PDC) {
|
||||
if (type == TYPE_INV && fieldType.fieldId == FLD_PDC) {
|
||||
fieldName = "PowerDC";
|
||||
} else {
|
||||
fieldName = inv->Statistics()->getChannelFieldName(type, channel, fieldType.fieldId);
|
||||
|
||||
@ -141,7 +141,7 @@ String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv,
|
||||
}
|
||||
|
||||
String chanName;
|
||||
if (type == TYPE_AC && fieldId == FLD_PDC) {
|
||||
if (type == TYPE_INV && fieldId == FLD_PDC) {
|
||||
chanName = "powerdc";
|
||||
} else {
|
||||
chanName = inv->Statistics()->getChannelFieldName(type, channel, fieldId);
|
||||
|
||||
@ -128,7 +128,7 @@ void MqttSettingsClass::performConnect()
|
||||
} else {
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setCredentials(config.Mqtt.Username, config.Mqtt.Password);
|
||||
}
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setWill(willTopic.c_str(), 2, config.Mqtt.Retain, config.Mqtt.Lwt.Value_Offline);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setWill(willTopic.c_str(), config.Mqtt.Lwt.Qos, config.Mqtt.Retain, config.Mqtt.Lwt.Value_Offline);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setClientId(clientId.c_str());
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->setCleanSession(config.Mqtt.CleanSession);
|
||||
static_cast<espMqttClientSecure*>(_mqttClient)->onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
#include "Display_Graphic.h"
|
||||
#include "Led_Single.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "PinMapping.h"
|
||||
#include <Esp.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
uint32_t Utils::getChipId()
|
||||
{
|
||||
@ -76,3 +78,17 @@ bool Utils::checkJsonAlloc(const DynamicJsonDocument& doc, const char* function,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Remove all files but the PINMAPPING_FILENAME
|
||||
void Utils::removeAllFiles()
|
||||
{
|
||||
auto root = LittleFS.open("/");
|
||||
auto file = root.getNextFileName();
|
||||
|
||||
while (file != "") {
|
||||
if (file != PINMAPPING_FILENAME) {
|
||||
LittleFS.remove(file);
|
||||
}
|
||||
file = root.getNextFileName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,12 +19,10 @@ void WebApiConfigClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
using std::placeholders::_5;
|
||||
using std::placeholders::_6;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/config/get", HTTP_GET, std::bind(&WebApiConfigClass::onConfigGet, this, _1));
|
||||
_server->on("/api/config/delete", HTTP_POST, std::bind(&WebApiConfigClass::onConfigDelete, this, _1));
|
||||
_server->on("/api/config/list", HTTP_GET, std::bind(&WebApiConfigClass::onConfigListGet, this, _1));
|
||||
_server->on("/api/config/upload", HTTP_POST,
|
||||
server.on("/api/config/get", HTTP_GET, std::bind(&WebApiConfigClass::onConfigGet, this, _1));
|
||||
server.on("/api/config/delete", HTTP_POST, std::bind(&WebApiConfigClass::onConfigDelete, this, _1));
|
||||
server.on("/api/config/list", HTTP_GET, std::bind(&WebApiConfigClass::onConfigListGet, this, _1));
|
||||
server.on("/api/config/upload", HTTP_POST,
|
||||
std::bind(&WebApiConfigClass::onConfigUploadFinish, this, _1),
|
||||
std::bind(&WebApiConfigClass::onConfigUpload, this, _1, _2, _3, _4, _5, _6));
|
||||
}
|
||||
@ -110,7 +108,7 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
LittleFS.remove(CONFIG_FILENAME);
|
||||
Utils::removeAllFiles();
|
||||
Utils::restartDtu();
|
||||
}
|
||||
|
||||
|
||||
@ -16,10 +16,8 @@ void WebApiDeviceClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/device/config", HTTP_GET, std::bind(&WebApiDeviceClass::onDeviceAdminGet, this, _1));
|
||||
_server->on("/api/device/config", HTTP_POST, std::bind(&WebApiDeviceClass::onDeviceAdminPost, this, _1));
|
||||
server.on("/api/device/config", HTTP_GET, std::bind(&WebApiDeviceClass::onDeviceAdminGet, this, _1));
|
||||
server.on("/api/device/config", HTTP_POST, std::bind(&WebApiDeviceClass::onDeviceAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
||||
|
||||
@ -12,9 +12,7 @@ void WebApiDevInfoClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/devinfo/status", HTTP_GET, std::bind(&WebApiDevInfoClass::onDevInfoStatus, this, _1));
|
||||
server.on("/api/devinfo/status", HTTP_GET, std::bind(&WebApiDevInfoClass::onDevInfoStatus, this, _1));
|
||||
}
|
||||
|
||||
void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -18,10 +18,8 @@ void WebApiDtuClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/dtu/config", HTTP_GET, std::bind(&WebApiDtuClass::onDtuAdminGet, this, _1));
|
||||
_server->on("/api/dtu/config", HTTP_POST, std::bind(&WebApiDtuClass::onDtuAdminPost, this, _1));
|
||||
server.on("/api/dtu/config", HTTP_GET, std::bind(&WebApiDtuClass::onDtuAdminGet, this, _1));
|
||||
server.on("/api/dtu/config", HTTP_POST, std::bind(&WebApiDtuClass::onDtuAdminPost, this, _1));
|
||||
|
||||
scheduler.addTask(_applyDataTask);
|
||||
}
|
||||
|
||||
@ -11,9 +11,7 @@ void WebApiEventlogClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/eventlog/status", HTTP_GET, std::bind(&WebApiEventlogClass::onEventlogStatus, this, _1));
|
||||
server.on("/api/eventlog/status", HTTP_GET, std::bind(&WebApiEventlogClass::onEventlogStatus, this, _1));
|
||||
}
|
||||
|
||||
void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -19,9 +19,7 @@ void WebApiFirmwareClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
using std::placeholders::_5;
|
||||
using std::placeholders::_6;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/firmware/update", HTTP_POST,
|
||||
server.on("/api/firmware/update", HTTP_POST,
|
||||
std::bind(&WebApiFirmwareClass::onFirmwareUpdateFinish, this, _1),
|
||||
std::bind(&WebApiFirmwareClass::onFirmwareUpdateUpload, this, _1, _2, _3, _4, _5, _6));
|
||||
}
|
||||
|
||||
@ -11,10 +11,8 @@ void WebApiGridProfileClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/gridprofile/status", HTTP_GET, std::bind(&WebApiGridProfileClass::onGridProfileStatus, this, _1));
|
||||
_server->on("/api/gridprofile/rawdata", HTTP_GET, std::bind(&WebApiGridProfileClass::onGridProfileRawdata, this, _1));
|
||||
server.on("/api/gridprofile/status", HTTP_GET, std::bind(&WebApiGridProfileClass::onGridProfileStatus, this, _1));
|
||||
server.on("/api/gridprofile/rawdata", HTTP_GET, std::bind(&WebApiGridProfileClass::onGridProfileRawdata, this, _1));
|
||||
}
|
||||
|
||||
void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -16,13 +16,11 @@ void WebApiInverterClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/inverter/list", HTTP_GET, std::bind(&WebApiInverterClass::onInverterList, this, _1));
|
||||
_server->on("/api/inverter/add", HTTP_POST, std::bind(&WebApiInverterClass::onInverterAdd, this, _1));
|
||||
_server->on("/api/inverter/edit", HTTP_POST, std::bind(&WebApiInverterClass::onInverterEdit, this, _1));
|
||||
_server->on("/api/inverter/del", HTTP_POST, std::bind(&WebApiInverterClass::onInverterDelete, this, _1));
|
||||
_server->on("/api/inverter/order", HTTP_POST, std::bind(&WebApiInverterClass::onInverterOrder, this, _1));
|
||||
server.on("/api/inverter/list", HTTP_GET, std::bind(&WebApiInverterClass::onInverterList, this, _1));
|
||||
server.on("/api/inverter/add", HTTP_POST, std::bind(&WebApiInverterClass::onInverterAdd, this, _1));
|
||||
server.on("/api/inverter/edit", HTTP_POST, std::bind(&WebApiInverterClass::onInverterEdit, this, _1));
|
||||
server.on("/api/inverter/del", HTTP_POST, std::bind(&WebApiInverterClass::onInverterDelete, this, _1));
|
||||
server.on("/api/inverter/order", HTTP_POST, std::bind(&WebApiInverterClass::onInverterOrder, this, _1));
|
||||
}
|
||||
|
||||
void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
|
||||
|
||||
@ -14,10 +14,8 @@ void WebApiLimitClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/limit/status", HTTP_GET, std::bind(&WebApiLimitClass::onLimitStatus, this, _1));
|
||||
_server->on("/api/limit/config", HTTP_POST, std::bind(&WebApiLimitClass::onLimitPost, this, _1));
|
||||
server.on("/api/limit/status", HTTP_GET, std::bind(&WebApiLimitClass::onLimitStatus, this, _1));
|
||||
server.on("/api/limit/config", HTTP_POST, std::bind(&WebApiLimitClass::onLimitPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -13,9 +13,7 @@ void WebApiMaintenanceClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/maintenance/reboot", HTTP_POST, std::bind(&WebApiMaintenanceClass::onRebootPost, this, _1));
|
||||
server.on("/api/maintenance/reboot", HTTP_POST, std::bind(&WebApiMaintenanceClass::onRebootPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
|
||||
|
||||
@ -19,11 +19,9 @@ void WebApiMqttClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/mqtt/status", HTTP_GET, std::bind(&WebApiMqttClass::onMqttStatus, this, _1));
|
||||
_server->on("/api/mqtt/config", HTTP_GET, std::bind(&WebApiMqttClass::onMqttAdminGet, this, _1));
|
||||
_server->on("/api/mqtt/config", HTTP_POST, std::bind(&WebApiMqttClass::onMqttAdminPost, this, _1));
|
||||
server.on("/api/mqtt/status", HTTP_GET, std::bind(&WebApiMqttClass::onMqttStatus, this, _1));
|
||||
server.on("/api/mqtt/config", HTTP_GET, std::bind(&WebApiMqttClass::onMqttAdminGet, this, _1));
|
||||
server.on("/api/mqtt/config", HTTP_POST, std::bind(&WebApiMqttClass::onMqttAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
||||
@ -85,7 +83,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
||||
root["mqtt_client_cert"] = config.Mqtt.Tls.ClientCert;
|
||||
root["mqtt_client_key"] = config.Mqtt.Tls.ClientKey;
|
||||
root["mqtt_lwt_topic"] = config.Mqtt.Lwt.Topic;
|
||||
root["mqtt_lwt_online"] = config.Mqtt.CleanSession;
|
||||
root["mqtt_lwt_online"] = config.Mqtt.Lwt.Value_Online;;
|
||||
root["mqtt_lwt_offline"] = config.Mqtt.Lwt.Value_Offline;
|
||||
root["mqtt_lwt_qos"] = config.Mqtt.Lwt.Qos;
|
||||
root["mqtt_publish_interval"] = config.Mqtt.PublishInterval;
|
||||
|
||||
@ -14,11 +14,9 @@ void WebApiNetworkClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/network/status", HTTP_GET, std::bind(&WebApiNetworkClass::onNetworkStatus, this, _1));
|
||||
_server->on("/api/network/config", HTTP_GET, std::bind(&WebApiNetworkClass::onNetworkAdminGet, this, _1));
|
||||
_server->on("/api/network/config", HTTP_POST, std::bind(&WebApiNetworkClass::onNetworkAdminPost, this, _1));
|
||||
server.on("/api/network/status", HTTP_GET, std::bind(&WebApiNetworkClass::onNetworkStatus, this, _1));
|
||||
server.on("/api/network/config", HTTP_GET, std::bind(&WebApiNetworkClass::onNetworkAdminGet, this, _1));
|
||||
server.on("/api/network/config", HTTP_POST, std::bind(&WebApiNetworkClass::onNetworkAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -15,13 +15,11 @@ void WebApiNtpClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/ntp/status", HTTP_GET, std::bind(&WebApiNtpClass::onNtpStatus, this, _1));
|
||||
_server->on("/api/ntp/config", HTTP_GET, std::bind(&WebApiNtpClass::onNtpAdminGet, this, _1));
|
||||
_server->on("/api/ntp/config", HTTP_POST, std::bind(&WebApiNtpClass::onNtpAdminPost, this, _1));
|
||||
_server->on("/api/ntp/time", HTTP_GET, std::bind(&WebApiNtpClass::onNtpTimeGet, this, _1));
|
||||
_server->on("/api/ntp/time", HTTP_POST, std::bind(&WebApiNtpClass::onNtpTimePost, this, _1));
|
||||
server.on("/api/ntp/status", HTTP_GET, std::bind(&WebApiNtpClass::onNtpStatus, this, _1));
|
||||
server.on("/api/ntp/config", HTTP_GET, std::bind(&WebApiNtpClass::onNtpAdminGet, this, _1));
|
||||
server.on("/api/ntp/config", HTTP_POST, std::bind(&WebApiNtpClass::onNtpAdminPost, this, _1));
|
||||
server.on("/api/ntp/time", HTTP_GET, std::bind(&WebApiNtpClass::onNtpTimeGet, this, _1));
|
||||
server.on("/api/ntp/time", HTTP_POST, std::bind(&WebApiNtpClass::onNtpTimePost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -12,10 +12,8 @@ void WebApiPowerClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/power/status", HTTP_GET, std::bind(&WebApiPowerClass::onPowerStatus, this, _1));
|
||||
_server->on("/api/power/config", HTTP_POST, std::bind(&WebApiPowerClass::onPowerPost, this, _1));
|
||||
server.on("/api/power/status", HTTP_GET, std::bind(&WebApiPowerClass::onPowerStatus, this, _1));
|
||||
server.on("/api/power/config", HTTP_POST, std::bind(&WebApiPowerClass::onPowerPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request)
|
||||
|
||||
@ -15,9 +15,7 @@ void WebApiPrometheusClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/prometheus/metrics", HTTP_GET, std::bind(&WebApiPrometheusClass::onPrometheusMetricsGet, this, _1));
|
||||
server.on("/api/prometheus/metrics", HTTP_GET, std::bind(&WebApiPrometheusClass::onPrometheusMetricsGet, this, _1));
|
||||
}
|
||||
|
||||
void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* request)
|
||||
@ -100,7 +98,7 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
addPanelInfo(stream, serial, i, inv, t, c);
|
||||
for (uint8_t f = 0; f < sizeof(_publishFields) / sizeof(_publishFields[0]); f++) {
|
||||
if (t == TYPE_AC && _publishFields[f].field == FLD_PDC) {
|
||||
if (t == TYPE_INV && _publishFields[f].field == FLD_PDC) {
|
||||
addField(stream, serial, i, inv, t, c, _publishFields[f].field, _metricTypes[_publishFields[f].type], "PowerDC");
|
||||
} else {
|
||||
addField(stream, serial, i, inv, t, c, _publishFields[f].field, _metricTypes[_publishFields[f].type]);
|
||||
|
||||
@ -13,11 +13,9 @@ void WebApiSecurityClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/security/config", HTTP_GET, std::bind(&WebApiSecurityClass::onSecurityGet, this, _1));
|
||||
_server->on("/api/security/config", HTTP_POST, std::bind(&WebApiSecurityClass::onSecurityPost, this, _1));
|
||||
_server->on("/api/security/authenticate", HTTP_GET, std::bind(&WebApiSecurityClass::onAuthenticateGet, this, _1));
|
||||
server.on("/api/security/config", HTTP_GET, std::bind(&WebApiSecurityClass::onSecurityGet, this, _1));
|
||||
server.on("/api/security/config", HTTP_POST, std::bind(&WebApiSecurityClass::onSecurityPost, this, _1));
|
||||
server.on("/api/security/authenticate", HTTP_GET, std::bind(&WebApiSecurityClass::onAuthenticateGet, this, _1));
|
||||
}
|
||||
|
||||
void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request)
|
||||
|
||||
@ -24,9 +24,7 @@ void WebApiSysstatusClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
_server = &server;
|
||||
|
||||
_server->on("/api/system/status", HTTP_GET, std::bind(&WebApiSysstatusClass::onSystemStatus, this, _1));
|
||||
server.on("/api/system/status", HTTP_GET, std::bind(&WebApiSysstatusClass::onSystemStatus, this, _1));
|
||||
}
|
||||
|
||||
void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
|
||||
@ -47,6 +45,8 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
|
||||
root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap();
|
||||
root["heap_max_block"] = ESP.getMaxAllocHeap();
|
||||
root["heap_min_free"] = ESP.getMinFreeHeap();
|
||||
root["psram_total"] = ESP.getPsramSize();
|
||||
root["psram_used"] = ESP.getPsramSize() - ESP.getFreePsram();
|
||||
root["sketch_total"] = ESP.getFreeSketchSpace();
|
||||
root["sketch_used"] = ESP.getSketchSize();
|
||||
root["littlefs_total"] = LittleFS.totalBytes();
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_webapp.h"
|
||||
#include <MD5Builder.h>
|
||||
|
||||
extern const uint8_t file_index_html_start[] asm("_binary_webapp_dist_index_html_gz_start");
|
||||
extern const uint8_t file_favicon_ico_start[] asm("_binary_webapp_dist_favicon_ico_start");
|
||||
@ -18,62 +19,22 @@ extern const uint8_t file_zones_json_end[] asm("_binary_webapp_dist_zones_json_g
|
||||
extern const uint8_t file_app_js_end[] asm("_binary_webapp_dist_js_app_js_gz_end");
|
||||
extern const uint8_t file_site_webmanifest_end[] asm("_binary_webapp_dist_site_webmanifest_end");
|
||||
|
||||
#ifdef AUTO_GIT_HASH
|
||||
#define ETAG_HTTP_HEADER_VAL "\"" AUTO_GIT_HASH "\"" // ETag value must be between quotes
|
||||
#endif
|
||||
|
||||
void WebApiWebappClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
void WebApiWebappClass::responseBinaryDataWithETagCache(AsyncWebServerRequest *request, const String &contentType, const String &contentEncoding, const uint8_t *content, size_t len)
|
||||
{
|
||||
_server = &server;
|
||||
auto md5 = MD5Builder();
|
||||
md5.begin();
|
||||
md5.add(const_cast<uint8_t *>(content), len);
|
||||
md5.calculate();
|
||||
|
||||
_server->on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "text/html", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
String expectedEtag;
|
||||
expectedEtag = "\"";
|
||||
expectedEtag += md5.toString();
|
||||
expectedEtag += "\"";
|
||||
|
||||
_server->onNotFound([](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "text/html", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/index.html", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "text/html", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "image/x-icon", file_favicon_ico_start, file_favicon_ico_end - file_favicon_ico_start);
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/favicon.png", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "image/png", file_favicon_png_start, file_favicon_png_end - file_favicon_png_start);
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/zones.json", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "application/json", file_zones_json_start, file_zones_json_end - file_zones_json_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/site.webmanifest", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "application/json", file_site_webmanifest_start, file_site_webmanifest_end - file_site_webmanifest_start);
|
||||
request->send(response);
|
||||
});
|
||||
|
||||
_server->on("/js/app.js", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
#ifdef ETAG_HTTP_HEADER_VAL
|
||||
// check client If-None-Match header vs ETag/AUTO_GIT_HASH
|
||||
bool eTagMatch = false;
|
||||
if (request->hasHeader("If-None-Match")) {
|
||||
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
||||
if (strncmp(ETAG_HTTP_HEADER_VAL, h->value().c_str(), strlen(ETAG_HTTP_HEADER_VAL)) == 0) {
|
||||
eTagMatch = true;
|
||||
}
|
||||
eTagMatch = h->value().equals(expectedEtag);
|
||||
}
|
||||
|
||||
// begin response 200 or 304
|
||||
@ -81,16 +42,55 @@ void WebApiWebappClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
if (eTagMatch) {
|
||||
response = request->beginResponse(304);
|
||||
} else {
|
||||
response = request->beginResponse_P(200, "text/javascript", file_app_js_start, file_app_js_end - file_app_js_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response = request->beginResponse_P(200, contentType, content, len);
|
||||
if (contentEncoding.length() > 0) {
|
||||
response->addHeader("Content-Encoding", contentEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP requires cache headers in 200 and 304 to be identical
|
||||
response->addHeader("Cache-Control", "public, must-revalidate");
|
||||
response->addHeader("ETag", ETAG_HTTP_HEADER_VAL);
|
||||
#else
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "text/javascript", file_app_js_start, file_app_js_end - file_app_js_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
#endif
|
||||
response->addHeader("ETag", expectedEtag);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void WebApiWebappClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
/*
|
||||
We don't validate the request header "Accept-Encoding" if gzip compression is supported!
|
||||
We just have the gzipped data available - so we ship them!
|
||||
*/
|
||||
|
||||
server.on("/", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "text/html", "gzip", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
});
|
||||
|
||||
server.onNotFound([&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "text/html", "gzip", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
});
|
||||
|
||||
server.on("/index.html", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "text/html", "gzip", file_index_html_start, file_index_html_end - file_index_html_start);
|
||||
});
|
||||
|
||||
server.on("/favicon.ico", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "image/x-icon", "", file_favicon_ico_start, file_favicon_ico_end - file_favicon_ico_start);
|
||||
});
|
||||
|
||||
server.on("/favicon.png", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "image/png", "", file_favicon_png_start, file_favicon_png_end - file_favicon_png_start);
|
||||
});
|
||||
|
||||
server.on("/zones.json", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "application/json", "gzip", file_zones_json_start, file_zones_json_end - file_zones_json_start);
|
||||
});
|
||||
|
||||
server.on("/site.webmanifest", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "application/json", "", file_site_webmanifest_start, file_site_webmanifest_end - file_site_webmanifest_start);
|
||||
});
|
||||
|
||||
server.on("/js/app.js", HTTP_GET, [&](AsyncWebServerRequest* request) {
|
||||
responseBinaryDataWithETagCache(request, "text/javascript", "gzip", file_app_js_start, file_app_js_end - file_app_js_start);
|
||||
});
|
||||
}
|
||||
|
||||
@ -16,8 +16,7 @@ WebApiWsConsoleClass::WebApiWsConsoleClass()
|
||||
|
||||
void WebApiWsConsoleClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
_server = &server;
|
||||
_server->addHandler(&_ws);
|
||||
server.addHandler(&_ws);
|
||||
MessageOutput.register_ws_output(&_ws);
|
||||
|
||||
scheduler.addTask(_wsCleanupTask);
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_ws_live.h"
|
||||
#include "Configuration.h"
|
||||
#include "Datastore.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "Utils.h"
|
||||
@ -31,10 +30,9 @@ void WebApiWsLiveClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
using std::placeholders::_5;
|
||||
using std::placeholders::_6;
|
||||
|
||||
_server = &server;
|
||||
_server->on("/api/livedata/status", HTTP_GET, std::bind(&WebApiWsLiveClass::onLivedataStatus, this, _1));
|
||||
server.on("/api/livedata/status", HTTP_GET, std::bind(&WebApiWsLiveClass::onLivedataStatus, this, _1));
|
||||
|
||||
_server->addHandler(&_ws);
|
||||
server.addHandler(&_ws);
|
||||
_ws.onEvent(std::bind(&WebApiWsLiveClass::onWebsocketEvent, this, _1, _2, _3, _4, _5, _6));
|
||||
|
||||
scheduler.addTask(_wsCleanupTask);
|
||||
@ -63,43 +61,6 @@ void WebApiWsLiveClass::sendDataTaskCb()
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t maxTimeStamp = 0;
|
||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||
auto inv = Hoymiles.getInverterByPos(i);
|
||||
maxTimeStamp = std::max<uint32_t>(maxTimeStamp, inv->Statistics()->getLastUpdate());
|
||||
}
|
||||
|
||||
// Update on every inverter change or at least after 10 seconds
|
||||
if (millis() - _lastWsPublish > (10 * 1000) || (maxTimeStamp != _newestInverterTimestamp)) {
|
||||
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
DynamicJsonDocument root(4200 * INV_MAX_COUNT);
|
||||
if (Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) {
|
||||
JsonVariant var = root;
|
||||
generateJsonResponse(var);
|
||||
|
||||
String buffer;
|
||||
serializeJson(root, buffer);
|
||||
|
||||
_ws.textAll(buffer);
|
||||
_newestInverterTimestamp = maxTimeStamp;
|
||||
}
|
||||
|
||||
} catch (const std::bad_alloc& bad_alloc) {
|
||||
MessageOutput.printf("Calling /api/livedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what());
|
||||
} catch (const std::exception& exc) {
|
||||
MessageOutput.printf("Unknown exception in /api/livedata/status. Reason: \"%s\".\r\n", exc.what());
|
||||
}
|
||||
|
||||
_lastWsPublish = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
{
|
||||
JsonArray invArray = root.createNestedArray("inverters");
|
||||
|
||||
// Loop all inverters
|
||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||
auto inv = Hoymiles.getInverterByPos(i);
|
||||
@ -107,64 +68,43 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject invObject = invArray.createNestedObject();
|
||||
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||
if (inv_cfg == nullptr) {
|
||||
const uint32_t lastUpdateInternal = inv->Statistics()->getLastUpdateFromInternal();
|
||||
if (!((lastUpdateInternal > 0 && lastUpdateInternal > _lastPublishStats[i]) || (millis() - _lastPublishStats[i] > (10 * 1000)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
invObject["serial"] = inv->serialString();
|
||||
invObject["name"] = inv->name();
|
||||
invObject["order"] = inv_cfg->Order;
|
||||
invObject["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
||||
invObject["poll_enabled"] = inv->getEnablePolling();
|
||||
invObject["reachable"] = inv->isReachable();
|
||||
invObject["producing"] = inv->isProducing();
|
||||
invObject["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
||||
if (inv->DevInfo()->getMaxPower() > 0) {
|
||||
invObject["limit_absolute"] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0;
|
||||
} else {
|
||||
invObject["limit_absolute"] = -1;
|
||||
}
|
||||
_lastPublishStats[i] = millis();
|
||||
|
||||
// Loop all channels
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
JsonObject chanTypeObj = invObject.createNestedObject(inv->Statistics()->getChannelTypeName(t));
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
if (t == TYPE_DC) {
|
||||
chanTypeObj[String(static_cast<uint8_t>(c))]["name"]["u"] = inv_cfg->channel[c].Name;
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
DynamicJsonDocument root(4096);
|
||||
if (!Utils::checkJsonAlloc(root, __FUNCTION__, __LINE__)) {
|
||||
continue;
|
||||
}
|
||||
addField(chanTypeObj, inv, t, c, FLD_PAC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_UAC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_IAC);
|
||||
if (t == TYPE_AC) {
|
||||
addField(chanTypeObj, inv, t, c, FLD_PDC, "Power DC");
|
||||
} else {
|
||||
addField(chanTypeObj, inv, t, c, FLD_PDC);
|
||||
}
|
||||
addField(chanTypeObj, inv, t, c, FLD_UDC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_IDC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_YD);
|
||||
addField(chanTypeObj, inv, t, c, FLD_YT);
|
||||
addField(chanTypeObj, inv, t, c, FLD_F);
|
||||
addField(chanTypeObj, inv, t, c, FLD_T);
|
||||
addField(chanTypeObj, inv, t, c, FLD_PF);
|
||||
addField(chanTypeObj, inv, t, c, FLD_Q);
|
||||
addField(chanTypeObj, inv, t, c, FLD_EFF);
|
||||
if (t == TYPE_DC && inv->Statistics()->getStringMaxPower(c) > 0) {
|
||||
addField(chanTypeObj, inv, t, c, FLD_IRR);
|
||||
chanTypeObj[String(c)][inv->Statistics()->getChannelFieldName(t, c, FLD_IRR)]["max"] = inv->Statistics()->getStringMaxPower(c);
|
||||
JsonVariant var = root;
|
||||
|
||||
auto invArray = var.createNestedArray("inverters");
|
||||
auto invObject = invArray.createNestedObject();
|
||||
|
||||
generateCommonJsonResponse(var);
|
||||
generateInverterCommonJsonResponse(invObject, inv);
|
||||
generateInverterChannelJsonResponse(invObject, inv);
|
||||
|
||||
String buffer;
|
||||
serializeJson(root, buffer);
|
||||
|
||||
_ws.textAll(buffer);
|
||||
|
||||
} catch (const std::bad_alloc& bad_alloc) {
|
||||
MessageOutput.printf("Calling /api/livedata/status has temporarily run out of resources. Reason: \"%s\".\r\n", bad_alloc.what());
|
||||
} catch (const std::exception& exc) {
|
||||
MessageOutput.printf("Unknown exception in /api/livedata/status. Reason: \"%s\".\r\n", exc.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
||||
invObject["events"] = inv->EventLog()->getEntryCount();
|
||||
} else {
|
||||
invObject["events"] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::generateCommonJsonResponse(JsonVariant& root)
|
||||
{
|
||||
JsonObject totalObj = root.createNestedObject("total");
|
||||
addTotalField(totalObj, "Power", Datastore.getTotalAcPowerEnabled(), "W", Datastore.getTotalAcPowerDigits());
|
||||
addTotalField(totalObj, "YieldDay", Datastore.getTotalAcYieldDayEnabled(), "Wh", Datastore.getTotalAcYieldDayDigits());
|
||||
@ -174,11 +114,7 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
struct tm timeinfo;
|
||||
hintObj["time_sync"] = !getLocalTime(&timeinfo, 5);
|
||||
hintObj["radio_problem"] = (Hoymiles.getRadioNrf()->isInitialized() && (!Hoymiles.getRadioNrf()->isConnected() || !Hoymiles.getRadioNrf()->isPVariant())) || (Hoymiles.getRadioCmt()->isInitialized() && (!Hoymiles.getRadioCmt()->isConnected()));
|
||||
if (!strcmp(Configuration.get().Security.Password, ACCESS_POINT_PASSWORD)) {
|
||||
hintObj["default_password"] = true;
|
||||
} else {
|
||||
hintObj["default_password"] = false;
|
||||
}
|
||||
hintObj["default_password"] = strcmp(Configuration.get().Security.Password, ACCESS_POINT_PASSWORD) == 0;
|
||||
|
||||
JsonObject vedirectObj = root.createNestedObject("vedirect");
|
||||
vedirectObj["enabled"] = Configuration.get().Vedirect.Enabled;
|
||||
@ -200,7 +136,73 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
JsonObject powerMeterObj = root.createNestedObject("power_meter");
|
||||
powerMeterObj["enabled"] = Configuration.get().PowerMeter.Enabled;
|
||||
addTotalField(powerMeterObj, "Power", PowerMeter.getPowerTotal(false), "W", 1);
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::generateInverterCommonJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv)
|
||||
{
|
||||
const INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||
if (inv_cfg == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
root["serial"] = inv->serialString();
|
||||
root["name"] = inv->name();
|
||||
root["order"] = inv_cfg->Order;
|
||||
root["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
||||
root["poll_enabled"] = inv->getEnablePolling();
|
||||
root["reachable"] = inv->isReachable();
|
||||
root["producing"] = inv->isProducing();
|
||||
root["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
||||
if (inv->DevInfo()->getMaxPower() > 0) {
|
||||
root["limit_absolute"] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0;
|
||||
} else {
|
||||
root["limit_absolute"] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::generateInverterChannelJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv)
|
||||
{
|
||||
const INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||
if (inv_cfg == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop all channels
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
JsonObject chanTypeObj = root.createNestedObject(inv->Statistics()->getChannelTypeName(t));
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
if (t == TYPE_DC) {
|
||||
chanTypeObj[String(static_cast<uint8_t>(c))]["name"]["u"] = inv_cfg->channel[c].Name;
|
||||
}
|
||||
addField(chanTypeObj, inv, t, c, FLD_PAC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_UAC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_IAC);
|
||||
if (t == TYPE_INV) {
|
||||
addField(chanTypeObj, inv, t, c, FLD_PDC, "Power DC");
|
||||
} else {
|
||||
addField(chanTypeObj, inv, t, c, FLD_PDC);
|
||||
}
|
||||
addField(chanTypeObj, inv, t, c, FLD_UDC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_IDC);
|
||||
addField(chanTypeObj, inv, t, c, FLD_YD);
|
||||
addField(chanTypeObj, inv, t, c, FLD_YT);
|
||||
addField(chanTypeObj, inv, t, c, FLD_F);
|
||||
addField(chanTypeObj, inv, t, c, FLD_T);
|
||||
addField(chanTypeObj, inv, t, c, FLD_PF);
|
||||
addField(chanTypeObj, inv, t, c, FLD_Q);
|
||||
addField(chanTypeObj, inv, t, c, FLD_EFF);
|
||||
if (t == TYPE_DC && inv->Statistics()->getStringMaxPower(c) > 0) {
|
||||
addField(chanTypeObj, inv, t, c, FLD_IRR);
|
||||
chanTypeObj[String(c)][inv->Statistics()->getChannelFieldName(t, c, FLD_IRR)]["max"] = inv->Statistics()->getStringMaxPower(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
||||
root["events"] = inv->EventLog()->getEntryCount();
|
||||
} else {
|
||||
root["events"] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::addField(JsonObject& root, std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const FieldId_t fieldId, String topic)
|
||||
@ -244,10 +246,38 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request)
|
||||
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4200 * INV_MAX_COUNT);
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096);
|
||||
auto& root = response->getRoot();
|
||||
|
||||
generateJsonResponse(root);
|
||||
JsonArray invArray = root.createNestedArray("inverters");
|
||||
|
||||
uint64_t serial = 0;
|
||||
if (request->hasParam("inv")) {
|
||||
String s = request->getParam("inv")->value();
|
||||
serial = strtoll(s.c_str(), NULL, 16);
|
||||
}
|
||||
|
||||
if (serial > 0) {
|
||||
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||
if (inv != nullptr) {
|
||||
JsonObject invObject = invArray.createNestedObject();
|
||||
generateInverterCommonJsonResponse(invObject, inv);
|
||||
generateInverterChannelJsonResponse(invObject, inv);
|
||||
}
|
||||
} else {
|
||||
// Loop all inverters
|
||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||
auto inv = Hoymiles.getInverterByPos(i);
|
||||
if (inv == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject invObject = invArray.createNestedObject();
|
||||
generateInverterCommonJsonResponse(invObject, inv);
|
||||
}
|
||||
}
|
||||
|
||||
generateCommonJsonResponse(root);
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@ -34,9 +34,13 @@
|
||||
#include <Arduino.h>
|
||||
#include <LittleFS.h>
|
||||
#include <TaskScheduler.h>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Move all dynamic allocations >512byte to psram (if available)
|
||||
heap_caps_malloc_extmem_enable(512);
|
||||
|
||||
// Initialize serial output
|
||||
Serial.begin(SERIAL_BAUDRATE);
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
|
||||
@ -18,8 +18,8 @@
|
||||
"mitt": "^3.0.1",
|
||||
"sortablejs": "^1.15.2",
|
||||
"spark-md5": "^3.0.2",
|
||||
"vue": "^3.4.15",
|
||||
"vue-i18n": "^9.9.0",
|
||||
"vue": "^3.4.19",
|
||||
"vue-i18n": "^9.9.1",
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -27,23 +27,23 @@
|
||||
"@rushstack/eslint-patch": "^1.7.2",
|
||||
"@tsconfig/node18": "^18.2.2",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@types/node": "^20.11.7",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/pulltorefreshjs": "^0.1.7",
|
||||
"@types/sortablejs": "^1.15.7",
|
||||
"@types/spark-md5": "^3.0.4",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-vue": "^9.20.1",
|
||||
"eslint-plugin-vue": "^9.21.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pulltorefreshjs": "^0.1.22",
|
||||
"sass": "^1.70.0",
|
||||
"terser": "^5.27.0",
|
||||
"sass": "^1.71.0",
|
||||
"terser": "^5.27.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.12",
|
||||
"vite": "^5.1.3",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.3.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.4.0",
|
||||
"vue-tsc": "^1.8.27"
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
<tbody>
|
||||
<FsInfo :name="$t('memoryinfo.Heap')" :total="systemStatus.heap_total"
|
||||
:used="systemStatus.heap_used" />
|
||||
<FsInfo :name="$t('memoryinfo.PsRam')" :total="systemStatus.psram_total"
|
||||
:used="systemStatus.psram_used" />
|
||||
<FsInfo :name="$t('memoryinfo.LittleFs')" :total="systemStatus.littlefs_total"
|
||||
:used="systemStatus.littlefs_used" />
|
||||
<FsInfo :name="$t('memoryinfo.Sketch')" :total="systemStatus.sketch_total"
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" ref="navbarCollapse" id="navbarNavAltMarkup">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<ul class="navbar-nav navbar-nav-scroll d-flex me-auto flex-sm-fill">
|
||||
<li class="nav-item">
|
||||
<router-link @click="onClick" class="nav-link" to="/">{{ $t('menu.LiveView') }}</router-link>
|
||||
</li>
|
||||
@ -114,8 +114,7 @@
|
||||
<li class="nav-item">
|
||||
<router-link @click="onClick" class="nav-link" to="/about">{{ $t('menu.About') }}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav flex-row flex-wrap ms-md-auto">
|
||||
<li class="flex-sm-fill"></li>
|
||||
<ThemeSwitcher class="me-2" />
|
||||
<form class="d-flex" role="search">
|
||||
<LocaleSwitcher class="me-2" />
|
||||
|
||||
@ -50,13 +50,13 @@
|
||||
"1001": "Einstellungen gespeichert!",
|
||||
"1002": "Keine Werte gefunden!",
|
||||
"1003": "Daten zu groß!",
|
||||
"1004": "Fehler beim interpretieren der Daten!",
|
||||
"1004": "Fehler beim Interpretieren der Daten!",
|
||||
"1005": "Benötigte Werte fehlen!",
|
||||
"1006": "Schreiben fehlgeschlagen!",
|
||||
"2001": "Die Seriennummer darf nicht 0 sein!",
|
||||
"2002": "Das Abfraginterval muss größer als 0 sein!",
|
||||
"2003": "Ungültige Sendeleistung angegeben!",
|
||||
"2004": "Die Frequenz muss zwischen {min} und {max} kHz liegen und ein vielfaches von 250kHz betragen!",
|
||||
"2004": "Die Frequenz muss zwischen {min} und {max} kHz liegen und ein Vielfaches von 250kHz betragen!",
|
||||
"2005": "Ungültige Landesauswahl!",
|
||||
"3001": "Nichts gelöscht!",
|
||||
"3002": "Konfiguration zurückgesetzt. Starte jetzt neu...",
|
||||
@ -145,7 +145,8 @@
|
||||
"Ok": "Ok",
|
||||
"Unknown": "Unbekannt",
|
||||
"ShowGridProfile": "Zeige Grid Profil",
|
||||
"GridProfile": "Grid Profil"
|
||||
"GridProfile": "Grid Profil",
|
||||
"LoadingInverter": "Warte auf Daten... (kann bis zu 10 Sekunden dauern)"
|
||||
},
|
||||
"vedirecthome": {
|
||||
"SerialNumber": "Seriennummer: ",
|
||||
@ -214,7 +215,7 @@
|
||||
"GridprofileSupportLong": "Weitere Informationen sind <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">hier</a> zu finden."
|
||||
},
|
||||
"systeminfo": {
|
||||
"SystemInfo": "System Informationen",
|
||||
"SystemInfo": "Systeminformationen",
|
||||
"VersionError": "Fehler beim Abrufen von Versionsinformationen",
|
||||
"VersionNew": "Neue Version verfügbar! Zeige Änderungen!",
|
||||
"VersionOk": "Aktuell!"
|
||||
@ -252,6 +253,7 @@
|
||||
"Used": "Benutzt",
|
||||
"Size": "Größe",
|
||||
"Heap": "Heap",
|
||||
"PsRam": "PSRAM",
|
||||
"LittleFs": "LittleFs",
|
||||
"Sketch": "Sketch"
|
||||
},
|
||||
@ -266,7 +268,7 @@
|
||||
"RadioInformation": "Funkmodulinformationen",
|
||||
"Status": "{module} Status",
|
||||
"ChipStatus": "{module} Chip-Status",
|
||||
"ChipType": "{module} Chip-Type",
|
||||
"ChipType": "{module} Chip-Typ",
|
||||
"Connected": "verbunden",
|
||||
"NotConnected": "nicht verbunden",
|
||||
"Configured": "konfiguriert",
|
||||
@ -335,18 +337,18 @@
|
||||
"Server": "@:ntpinfo.Server",
|
||||
"Port": "Port",
|
||||
"Username": "Benutzername",
|
||||
"BaseTopic": "Basis Topic",
|
||||
"BaseTopic": "Basis-Topic",
|
||||
"PublishInterval": "Veröffentlichungsintervall",
|
||||
"Seconds": "{sec} Sekunden",
|
||||
"CleanSession": "CleanSession Flag",
|
||||
"Retain": "Retain",
|
||||
"Tls": "TLS",
|
||||
"RootCertifcateInfo": "Root CA-Zertifikat-Informationen",
|
||||
"TlsCertLogin": "Anmeldung mit TLS Zertifikat",
|
||||
"TlsCertLogin": "Anmeldung mit TLS-Zertifikat",
|
||||
"ClientCertifcateInfo": "Client Zertifikat-Informationen",
|
||||
"HassSummary": "Home Assistant MQTT-Auto-Discovery Konfigurationszusammenfassung",
|
||||
"Expire": "Ablaufen",
|
||||
"IndividualPanels": "Einzelne Paneele",
|
||||
"IndividualPanels": "Einzelne Panels",
|
||||
"RuntimeSummary": "Laufzeitzusammenfassung",
|
||||
"ConnectionStatus": "Verbindungsstatus",
|
||||
"Connected": "verbunden",
|
||||
@ -367,7 +369,7 @@
|
||||
"Console": "Konsole",
|
||||
"VirtualDebugConsole": "Virtuelle Debug-Konsole",
|
||||
"EnableAutoScroll": "Automatisches Scrollen aktivieren",
|
||||
"ClearConsole": "Konsole löschen",
|
||||
"ClearConsole": "Konsole leeren",
|
||||
"CopyToClipboard": "In die Zwischenablage kopieren"
|
||||
},
|
||||
"inverterchannelinfo": {
|
||||
@ -427,7 +429,7 @@
|
||||
"country_1": "Nordamerika ({min}MHz - {max}MHz)",
|
||||
"country_2": "Brasilien ({min}MHz - {max}MHz)",
|
||||
"CmtFrequency": "CMT2300A Frequenz:",
|
||||
"CmtFrequencyHint": "Stelle sicher, dass du nur Frequenzen verwendet werden welche im entsprechenden Land erlaubt sind! Nach einer Frequenzänderung kann es bis zu 15min dauern bis eine Verbindung hergestellt wird.",
|
||||
"CmtFrequencyHint": "Stelle sicher, dass nur Frequenzen verwendet werden, welche im entsprechenden Land erlaubt sind! Nach einer Frequenzänderung kann es bis zu 15min dauern bis eine Verbindung hergestellt wird.",
|
||||
"CmtFrequencyWarning": "Die gewählte Frequenz liegt außerhalb des zulässigen Bereichs in der gewählten Region/dem Land. Vergewissere dich, dass mit dieser Auswahl keine lokalen Regularien verletzt werden.",
|
||||
"MHz": "{mhz} MHz",
|
||||
"dBm": "{dbm} dBm",
|
||||
@ -461,7 +463,7 @@
|
||||
"NAUTICAL": "Nautische Dämmerung (102°)",
|
||||
"CIVIL": "Bürgerliche Dämmerung (96°)",
|
||||
"ASTONOMICAL": "Astronomische Dämmerung (108°)",
|
||||
"ManualTimeSynchronization": "Manuelle Zeitsynchronization",
|
||||
"ManualTimeSynchronization": "Manuelle Zeitsynchronisation",
|
||||
"CurrentOpenDtuTime": "Aktuelle OpenDTU-Zeit:",
|
||||
"CurrentLocalTime": "Aktuelle lokale Zeit:",
|
||||
"SynchronizeTime": "Zeit synchronisieren",
|
||||
@ -514,7 +516,7 @@
|
||||
"ClientKey": "TLS Client-Key:",
|
||||
"LwtParameters": "LWT-Parameter",
|
||||
"LwtTopic": "LWT-Topic:",
|
||||
"LwtTopicHint": "LWT-Topic, wird der Basis Topic angehängt",
|
||||
"LwtTopicHint": "LWT-Topic, wird der Basis-Topic angehängt",
|
||||
"LwtOnline": "LWT-Online-Nachricht:",
|
||||
"LwtOnlineHint": "Nachricht, die im LWT-Topic veröffentlicht wird, wenn OpenDTU online ist",
|
||||
"LwtOffline": "LWT-Offline-Nachricht:",
|
||||
@ -528,7 +530,7 @@
|
||||
"HassPrefixTopicHint": "The prefix for the discovery topic",
|
||||
"HassRetain": "Retain Flag aktivieren",
|
||||
"HassExpire": "Ablauffunktion aktivieren",
|
||||
"HassIndividual": "Einzelne Paneele"
|
||||
"HassIndividual": "Einzelne Panels"
|
||||
},
|
||||
"vedirectadmin": {
|
||||
"VedirectSettings": "VE.Direct Einstellungen",
|
||||
@ -656,13 +658,13 @@
|
||||
"Advanced": "Erweitert",
|
||||
"InverterSerial": "Wechselrichter Seriennummer:",
|
||||
"InverterName": "Wechselrichter Name:",
|
||||
"InverterNameHint": "Hier kann ein eigener Namen für den Wechselrichter angeben werden.",
|
||||
"InverterStatus": "Empfangen / senden",
|
||||
"InverterNameHint": "Hier kann ein eigener Name für den Wechselrichter angeben werden.",
|
||||
"InverterStatus": "empfangen / senden",
|
||||
"PollEnable": "Daten abrufen",
|
||||
"PollEnableNight": "Daten auch nachts abrufen",
|
||||
"CommandEnable": "Befehle senden",
|
||||
"CommandEnableNight": "Befehle auch nachts senden",
|
||||
"StringName": "Name String {num}:",
|
||||
"StringName": "Stringname {num}:",
|
||||
"StringNameHint": "Hier kann ein eigener Name für den entsprechenden Port des Wechselrichters angegeben werden.",
|
||||
"StringMaxPower": "Max. Leistung String {num}:",
|
||||
"StringMaxPowerHint": "Eingabe der maximalen Leistung der angeschlossenen Solarmodule.",
|
||||
@ -717,12 +719,14 @@
|
||||
"Back": "Zurück",
|
||||
"Retry": "Wiederholen",
|
||||
"OtaStatus": "OTA-Status",
|
||||
"OtaSuccess": "Das Hochladen der Firmware war erfolgreich. Das Gerät wurde automatisch neu gestartet. Wenn das Gerät wieder erreichbar ist wird die automatisch Oberfläche neu geladen.",
|
||||
"OtaSuccess": "Das Hochladen der Firmware war erfolgreich. Das Gerät wurde automatisch neu gestartet. Wenn das Gerät wieder erreichbar ist, wird die Oberfläche automatisch neu geladen.",
|
||||
"FirmwareUpload": "Firmware hochladen",
|
||||
"UploadProgress": "Hochlade-Fortschritt"
|
||||
},
|
||||
"about": {
|
||||
"AboutOpendtu": "Über OpenDTU",
|
||||
"Documentation": "Dokumentation",
|
||||
"DocumentationBody": "Die Firmware- und Hardware-Dokumentation ist hier zu finden: <a href=\"https://www.opendtu.solar\" target=\"_blank\">https://www.opendtu.solar</a>",
|
||||
"ProjectOrigin": "Projekt Ursprung",
|
||||
"ProjectOriginBody1": "Das Projekt wurde aus <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">dieser Diskussion (mikrocontroller.net)</a> heraus gestartet.",
|
||||
"ProjectOriginBody2": "Das Hoymiles-Protokoll wurde durch die freiwilligen Bemühungen vieler Teilnehmer entschlüsselt. OpenDTU wurde unter anderem auf der Grundlage dieser Arbeit entwickelt. Das Projekt ist unter einer Open-Source-Lizenz lizenziert (<a href=\"https://www.gnu.de/documents/gpl-2.0.de.html\" target=\"_blank\">GNU General Public License version 2</a>).",
|
||||
|
||||
@ -145,7 +145,8 @@
|
||||
"Ok": "Ok",
|
||||
"Unknown": "Unknown",
|
||||
"ShowGridProfile": "Show Grid Profile",
|
||||
"GridProfile": "Grid Profile"
|
||||
"GridProfile": "Grid Profile",
|
||||
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)"
|
||||
},
|
||||
"vedirecthome": {
|
||||
"SerialNumber": "Serial Number: ",
|
||||
@ -253,6 +254,7 @@
|
||||
"Used": "Used",
|
||||
"Size": "Size",
|
||||
"Heap": "Heap",
|
||||
"PsRam": "PSRAM",
|
||||
"LittleFs": "LittleFs",
|
||||
"Sketch": "Sketch"
|
||||
},
|
||||
@ -729,6 +731,8 @@
|
||||
},
|
||||
"about": {
|
||||
"AboutOpendtu": "About OpenDTU",
|
||||
"Documentation": "Documentation",
|
||||
"DocumentationBody": "The firmware and hardware documentation can be found here: <a href=\"https://www.opendtu.solar\" target=\"_blank\">https://www.opendtu.solar</a>",
|
||||
"ProjectOrigin": "Project Origin",
|
||||
"ProjectOriginBody1": "This project was started from <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">this discussion. (Mikrocontroller.net)</a>",
|
||||
"ProjectOriginBody2": "The Hoymiles protocol was decrypted through the voluntary efforts of many participants. OpenDTU, among others, was developed based on this work. The project is licensed under an Open Source License (<a href=\"https://www.gnu.de/documents/gpl-2.0.de.html\" target=\"_blank\">GNU General Public License version 2</a>).",
|
||||
|
||||
@ -145,7 +145,43 @@
|
||||
"Ok": "OK",
|
||||
"Unknown": "Inconnu",
|
||||
"ShowGridProfile": "Show Grid Profile",
|
||||
"GridProfile": "Grid Profile"
|
||||
"GridProfile": "Grid Profile",
|
||||
"LoadingInverter": "Waiting for data... (can take up to 10 seconds)"
|
||||
},
|
||||
"vedirecthome": {
|
||||
"SerialNumber": "Serial Number: ",
|
||||
"FirmwareNumber": "Firmware Number: ",
|
||||
"DataAge": "Data Age: ",
|
||||
"Seconds": "{val} seconds",
|
||||
"DeviceInfo": "Device Info",
|
||||
"Property": "Property",
|
||||
"Value": "Value",
|
||||
"Unit": "Unit",
|
||||
"LoadOutputState": "Load output state",
|
||||
"StateOfOperation": "State of operation",
|
||||
"TrackerOperationMode": "Tracker operation mode",
|
||||
"OffReason": "Off reason",
|
||||
"ErrorCode": "Error code",
|
||||
"DaySequenceNumber": "Day sequence number (0..364)",
|
||||
"Battery": "Output (Battery)",
|
||||
"output": {
|
||||
"P": "Power (calculated)",
|
||||
"V": "Voltage",
|
||||
"I": "Current",
|
||||
"E": "Efficiency (calculated)"
|
||||
},
|
||||
"Panel": "Input (Solar Panels)",
|
||||
"input": {
|
||||
"PPV": "Power",
|
||||
"VPV": "Voltage",
|
||||
"IPV": "Current (calculated)",
|
||||
"YieldToday": "Yield today",
|
||||
"YieldYesterday": "Yield yesterday",
|
||||
"YieldTotal": "Yield total (user resettable counter)",
|
||||
"MaximumPowerToday": "Maximum power today",
|
||||
"MaximumPowerYesterday": "Maximum power yesterday"
|
||||
},
|
||||
"PowerLimiterState": "Power limiter state [off (charging), solar passthrough, on battery]"
|
||||
},
|
||||
"vedirecthome": {
|
||||
"SerialNumber": "Serial Number: ",
|
||||
@ -252,6 +288,7 @@
|
||||
"Used": "Utilisée",
|
||||
"Size": "Taille",
|
||||
"Heap": "Heap",
|
||||
"PsRam": "PSRAM",
|
||||
"LittleFs": "LittleFs",
|
||||
"Sketch": "Sketch"
|
||||
},
|
||||
@ -687,6 +724,8 @@
|
||||
},
|
||||
"about": {
|
||||
"AboutOpendtu": "À propos d'OpenDTU",
|
||||
"Documentation": "Documentation",
|
||||
"DocumentationBody": "The firmware and hardware documentation can be found here: <a href=\"https://www.opendtu.solar\" target=\"_blank\">https://www.opendtu.solar</a>",
|
||||
"ProjectOrigin": "Origine du projet",
|
||||
"ProjectOriginBody1": "Ce projet a été démarré suite à cette discussion <a href=\"https://www.mikrocontroller.net/topic/525778\" target=\"_blank\">(Mikrocontroller.net)</a>.",
|
||||
"ProjectOriginBody2": "Le protocole Hoymiles a été décrypté grâce aux efforts volontaires de nombreux participants. OpenDTU, entre autres, a été développé sur la base de ce travail. Le projet est sous licence Open Source (<a href=\"https://www.gnu.de/documents/gpl-2.0.de.html\" target=\"_blank\">GNU General Public License version 2</a>).",
|
||||
|
||||
@ -26,6 +26,8 @@ export interface SystemStatus {
|
||||
heap_min_free: number;
|
||||
littlefs_total: number;
|
||||
littlefs_used: number;
|
||||
psram_total: number;
|
||||
psram_used: number;
|
||||
sketch_total: number;
|
||||
sketch_used: number;
|
||||
// RadioInfo
|
||||
|
||||
@ -2,15 +2,31 @@
|
||||
<BasePage :title="$t('about.AboutOpendtu')">
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<h2 class="accordion-header" id="headingDocumentation">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
data-bs-target="#collapseDocumentation" aria-expanded="true" aria-controls="collapseOne">
|
||||
<span class="badge text-bg-secondary">
|
||||
<BIconInfoCircle class="fs-4" />
|
||||
</span> {{ $t('about.Documentation') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseDocumentation" class="accordion-collapse collapse show" aria-labelledby="headingDocumentation"
|
||||
data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<p class="fw-normal" v-html="$t('about.DocumentationBody')"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
||||
<span class="badge text-bg-secondary">
|
||||
<BIconInfoCircle class="fs-4" />
|
||||
</span> {{ $t('about.ProjectOrigin') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne"
|
||||
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne"
|
||||
data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<p class="fw-normal" v-html="$t('about.ProjectOriginBody1')"></p>
|
||||
|
||||
@ -103,6 +103,7 @@
|
||||
<div class="card-body">
|
||||
<div class="row flex-row-reverse flex-wrap-reverse g-3">
|
||||
<template v-for="chanType in [{obj: inverter.INV, name: 'INV'}, {obj: inverter.AC, name: 'AC'}, {obj: inverter.DC, name: 'DC'}].reverse()">
|
||||
<template v-if="chanType.obj != null">
|
||||
<template v-for="channel in Object.keys(chanType.obj).sort().reverse().map(x=>+x)" :key="channel">
|
||||
<template v-if="(chanType.name != 'DC') ||
|
||||
(chanType.name == 'DC' && getSumIrridiation(inverter) == 0) ||
|
||||
@ -116,7 +117,16 @@
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<BootstrapAlert class="m-3" :show="!inverter.hasOwnProperty('INV')">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<div class="spinner-border m-1" role="status">
|
||||
<span class="visually-hidden">{{ $t('home.LoadingInverter') }}</span>
|
||||
</div>
|
||||
<span>{{ $t('home.LoadingInverter') }}</span>
|
||||
</div>
|
||||
</BootstrapAlert>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -450,7 +460,16 @@ export default defineComponent({
|
||||
this.socket.onmessage = (event) => {
|
||||
console.log(event);
|
||||
if (event.data != "{}") {
|
||||
this.liveData = JSON.parse(event.data);
|
||||
const newData = JSON.parse(event.data);
|
||||
Object.assign(this.liveData.total, newData.total);
|
||||
Object.assign(this.liveData.hints, newData.hints);
|
||||
|
||||
const foundIdx = this.liveData.inverters.findIndex((element) => element.serial == newData.inverters[0].serial);
|
||||
if (foundIdx == -1) {
|
||||
Object.assign(this.liveData.inverters, newData.inverters);
|
||||
} else {
|
||||
Object.assign(this.liveData.inverters[foundIdx], newData.inverters[0]);
|
||||
}
|
||||
this.dataLoading = false;
|
||||
this.heartCheck(); // Reset heartbeat detection
|
||||
} else {
|
||||
|
||||
270
webapp/yarn.lock
270
webapp/yarn.lock
@ -17,10 +17,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8"
|
||||
integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==
|
||||
|
||||
"@babel/parser@^7.23.6":
|
||||
version "7.23.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b"
|
||||
integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==
|
||||
"@babel/parser@^7.23.9":
|
||||
version "7.23.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.9.tgz#7b903b6149b0f8fa7ad564af646c4c38a77fc44b"
|
||||
integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==
|
||||
|
||||
"@esbuild/android-arm64@0.19.5":
|
||||
version "0.19.5"
|
||||
@ -211,20 +211,20 @@
|
||||
source-map-js "^1.0.1"
|
||||
yaml-eslint-parser "^1.2.2"
|
||||
|
||||
"@intlify/core-base@9.9.0":
|
||||
version "9.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.9.0.tgz#edc55a5e3dbbf8dbbbf656529ed27832c4c4f522"
|
||||
integrity sha512-C7UXPymDIOlMGSNjAhNLtKgzITc/8BjINK5gNKXg8GiWCTwL6n3MWr55czksxn8RM5wTMz0qcLOFT+adtaVQaA==
|
||||
"@intlify/core-base@9.9.1":
|
||||
version "9.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.9.1.tgz#97ff0a98bf416c3f895e2a4fbcb0da353326b71a"
|
||||
integrity sha512-qsV15dg7jNX2faBRyKMgZS8UcFJViWEUPLdzZ9UR0kQZpFVeIpc0AG7ZOfeP7pX2T9SQ5jSiorq/tii9nkkafA==
|
||||
dependencies:
|
||||
"@intlify/message-compiler" "9.9.0"
|
||||
"@intlify/shared" "9.9.0"
|
||||
"@intlify/message-compiler" "9.9.1"
|
||||
"@intlify/shared" "9.9.1"
|
||||
|
||||
"@intlify/message-compiler@9.9.0":
|
||||
version "9.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.9.0.tgz#7952759329e7af0388afbce7a984820bbeff82eb"
|
||||
integrity sha512-yDU/jdUm9KuhEzYfS+wuyja209yXgdl1XFhMlKtXEgSFTxz4COZQCRXXbbH8JrAjMsaJ7bdoPSLsKlY6mXG2iA==
|
||||
"@intlify/message-compiler@9.9.1":
|
||||
version "9.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.9.1.tgz#4cd9c5a408be27784928e4cd57a77ea6ddb17e56"
|
||||
integrity sha512-zTvP6X6HeumHOXuAE1CMMsV6tTX+opKMOxO1OHTCg5N5Sm/F7d8o2jdT6W6L5oHUsJ/vvkGefHIs7Q3hfowmsA==
|
||||
dependencies:
|
||||
"@intlify/shared" "9.9.0"
|
||||
"@intlify/shared" "9.9.1"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
"@intlify/message-compiler@^9.4.0":
|
||||
@ -240,10 +240,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.4.0.tgz#4a78d462fc82433db900981e12eb5b1aae3d6085"
|
||||
integrity sha512-AFqymip2kToqA0B6KZPg5jSrdcVHoli9t/VhGKE2iiMq9utFuMoGdDC/JOCIZgwxo6aXAk86QyU2XtzEoMuZ6A==
|
||||
|
||||
"@intlify/shared@9.9.0":
|
||||
version "9.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.9.0.tgz#56907633c0f7b2d50f53269d31e88e7b24d39187"
|
||||
integrity sha512-1ECUyAHRrzOJbOizyGufYP2yukqGrWXtkmTu4PcswVnWbkcjzk3YQGmJ0bLkM7JZ0ZYAaohLGdYvBYnTOGYJ9g==
|
||||
"@intlify/shared@9.9.1":
|
||||
version "9.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.9.1.tgz#b602d012b35f6c336b29a8098296dfac96a005f5"
|
||||
integrity sha512-b3Pta1nwkz5rGq434v0psHwEwHGy1pYCttfcM22IE//K9owbpkEvFptx9VcuRAxjQdrO2If249cmDDjBu5wMDA==
|
||||
|
||||
"@intlify/unplugin-vue-i18n@^2.0.0":
|
||||
version "2.0.0"
|
||||
@ -435,10 +435,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
|
||||
integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
|
||||
|
||||
"@types/node@^20.11.7":
|
||||
version "20.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.7.tgz#cb49aedd758c978c30806d0c38b520ed2a3df6e0"
|
||||
integrity sha512-GPmeN1C3XAyV5uybAf4cMLWT9fDWcmQhZVtMFu7OR32WjrqGG+Wnk2V1d0bmtUyE/Zy1QJ9BxyiTih9z8Oks8A==
|
||||
"@types/node@^20.11.19":
|
||||
version "20.11.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195"
|
||||
integrity sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
@ -552,10 +552,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
||||
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
||||
|
||||
"@vitejs/plugin-vue@^5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.3.tgz#164b36653910d27c130cf6c945b4bd9bde5bcbee"
|
||||
integrity sha512-b8S5dVS40rgHdDrw+DQi/xOM9ed+kSRZzfm1T74bMmBDCd8XO87NKlFYInzCtwvtWwXZvo1QxE2OSspTATWrbA==
|
||||
"@vitejs/plugin-vue@^5.0.4":
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37"
|
||||
integrity sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==
|
||||
|
||||
"@volar/language-core@1.11.1", "@volar/language-core@~1.11.1":
|
||||
version "1.11.1"
|
||||
@ -599,13 +599,13 @@
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
"@vue/compiler-core@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.15.tgz#be20d1bbe19626052500b48969302cb6f396d36e"
|
||||
integrity sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==
|
||||
"@vue/compiler-core@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.19.tgz#3161b1ede69da00f3ce8155dfab907a3eaa0515e"
|
||||
integrity sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.23.6"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@babel/parser" "^7.23.9"
|
||||
"@vue/shared" "3.4.19"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.0.2"
|
||||
@ -618,13 +618,13 @@
|
||||
"@vue/compiler-core" "3.2.47"
|
||||
"@vue/shared" "3.2.47"
|
||||
|
||||
"@vue/compiler-dom@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz#753f5ed55f78d33dff04701fad4d76ff0cf81ee5"
|
||||
integrity sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==
|
||||
"@vue/compiler-dom@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz#2457e57e978f431e3b5fd11fc50a3e92d5816f9a"
|
||||
integrity sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/compiler-core" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
"@vue/compiler-dom@^3.3.0":
|
||||
version "3.3.2"
|
||||
@ -634,18 +634,18 @@
|
||||
"@vue/compiler-core" "3.3.2"
|
||||
"@vue/shared" "3.3.2"
|
||||
|
||||
"@vue/compiler-sfc@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz#4e5811e681955fcec886cebbec483f6ae463a64b"
|
||||
integrity sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==
|
||||
"@vue/compiler-sfc@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.19.tgz#33b238ded6d63e51f6a7048b742626f6007df129"
|
||||
integrity sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.23.6"
|
||||
"@vue/compiler-core" "3.4.15"
|
||||
"@vue/compiler-dom" "3.4.15"
|
||||
"@vue/compiler-ssr" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@babel/parser" "^7.23.9"
|
||||
"@vue/compiler-core" "3.4.19"
|
||||
"@vue/compiler-dom" "3.4.19"
|
||||
"@vue/compiler-ssr" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.30.5"
|
||||
magic-string "^0.30.6"
|
||||
postcss "^8.4.33"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
@ -673,13 +673,13 @@
|
||||
"@vue/compiler-dom" "3.2.47"
|
||||
"@vue/shared" "3.2.47"
|
||||
|
||||
"@vue/compiler-ssr@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz#a910a5b89ba4f0a776e40b63d69bdae2f50616cf"
|
||||
integrity sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==
|
||||
"@vue/compiler-ssr@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.19.tgz#1f8ee06005ebbaa354f8783fad84e9f7ea4a69c2"
|
||||
integrity sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/compiler-dom" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
"@vue/devtools-api@^6.5.0":
|
||||
version "6.5.0"
|
||||
@ -721,37 +721,37 @@
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.25.7"
|
||||
|
||||
"@vue/reactivity@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.15.tgz#ad9d9b83f5398d2e8660ad5cfc0f171e7679a9a1"
|
||||
integrity sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==
|
||||
"@vue/reactivity@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.19.tgz#8cf335d97d07881d8184cb23289289dc18b03f60"
|
||||
integrity sha512-+VcwrQvLZgEclGZRHx4O2XhyEEcKaBi50WbxdVItEezUf4fqRh838Ix6amWTdX0CNb/b6t3Gkz3eOebfcSt+UA==
|
||||
dependencies:
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
"@vue/runtime-core@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.15.tgz#f81e2fd2108ea41a6d5c61c2462b11dfb754fdf0"
|
||||
integrity sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==
|
||||
"@vue/runtime-core@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.19.tgz#ef10357fdf3afdf68523b55424541000105e2aeb"
|
||||
integrity sha512-/Z3tFwOrerJB/oyutmJGoYbuoadphDcJAd5jOuJE86THNZji9pYjZroQ2NFsZkTxOq0GJbb+s2kxTYToDiyZzw==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/reactivity" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
"@vue/runtime-dom@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz#108ef86aa7334ead5d6b9c56a7d93679e1e45406"
|
||||
integrity sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==
|
||||
"@vue/runtime-dom@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.19.tgz#079141e31d9f47515b9595f29843d51011f88739"
|
||||
integrity sha512-IyZzIDqfNCF0OyZOauL+F4yzjMPN2rPd8nhqPP2N1lBn3kYqJpPHHru+83Rkvo2lHz5mW+rEeIMEF9qY3PB94g==
|
||||
dependencies:
|
||||
"@vue/runtime-core" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/runtime-core" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/server-renderer@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.15.tgz#34438f998e6f6370fac78883a75efe136631957f"
|
||||
integrity sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==
|
||||
"@vue/server-renderer@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.19.tgz#e6f8ff5268d0758766ca9835375218924d5f0eb6"
|
||||
integrity sha512-eAj2p0c429RZyyhtMRnttjcSToch+kTWxFPHlzGMkR28ZbF1PDlTcmGmlDxccBuqNd9iOQ7xPRPAGgPVj+YpQw==
|
||||
dependencies:
|
||||
"@vue/compiler-ssr" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/compiler-ssr" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
"@vue/shared@3.2.47":
|
||||
version "3.2.47"
|
||||
@ -763,10 +763,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.2.tgz#774cd9b4635ce801b70a3fc3713779a5ef5d77c3"
|
||||
integrity sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ==
|
||||
|
||||
"@vue/shared@3.4.15":
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.15.tgz#e7d2ea050c667480cb5e1a6df2ac13bcd03a8f30"
|
||||
integrity sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==
|
||||
"@vue/shared@3.4.19":
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.19.tgz#28105147811bcf1e6612bf1c9ab0c6d91ada019c"
|
||||
integrity sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==
|
||||
|
||||
"@vue/tsconfig@^0.5.1":
|
||||
version "0.5.1"
|
||||
@ -1146,17 +1146,17 @@ escodegen@^2.0.0:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-plugin-vue@^9.20.1:
|
||||
version "9.20.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.20.1.tgz#7ed78846898574b2cd26939f28b0b87798a7b528"
|
||||
integrity sha512-GyCs8K3lkEvoyC1VV97GJhP1SvqsKCiWGHnbn0gVUYiUhaH2+nB+Dv1uekv1THFMPbBfYxukrzQdltw950k+LQ==
|
||||
eslint-plugin-vue@^9.21.1:
|
||||
version "9.21.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.21.1.tgz#da5629efa48527cec98278dca0daa90fada4caf7"
|
||||
integrity sha512-XVtI7z39yOVBFJyi8Ljbn7kY9yHzznKXL02qQYn+ta63Iy4A9JFBw6o4OSB9hyD2++tVT+su9kQqetUyCCwhjw==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
natural-compare "^1.4.0"
|
||||
nth-check "^2.1.1"
|
||||
postcss-selector-parser "^6.0.13"
|
||||
semver "^7.5.4"
|
||||
vue-eslint-parser "^9.4.0"
|
||||
vue-eslint-parser "^9.4.2"
|
||||
xml-name-validator "^4.0.0"
|
||||
|
||||
eslint-scope@^7.1.1:
|
||||
@ -1834,10 +1834,10 @@ magic-string@^0.30.0:
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.4.13"
|
||||
|
||||
magic-string@^0.30.5:
|
||||
version "0.30.5"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9"
|
||||
integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==
|
||||
magic-string@^0.30.6:
|
||||
version "0.30.7"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505"
|
||||
integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.4.15"
|
||||
|
||||
@ -2128,19 +2128,19 @@ postcss@^8.1.10:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
postcss@^8.4.32:
|
||||
version "8.4.32"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
|
||||
integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==
|
||||
postcss@^8.4.33:
|
||||
version "8.4.33"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
|
||||
integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
postcss@^8.4.33:
|
||||
version "8.4.33"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
|
||||
integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
|
||||
postcss@^8.4.35:
|
||||
version "8.4.35"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7"
|
||||
integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.0.0"
|
||||
@ -2257,10 +2257,10 @@ safe-regex-test@^1.0.0:
|
||||
get-intrinsic "^1.1.3"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
sass@^1.70.0:
|
||||
version "1.70.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.70.0.tgz#761197419d97b5358cb25f9dd38c176a8a270a75"
|
||||
integrity sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==
|
||||
sass@^1.71.0:
|
||||
version "1.71.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.71.0.tgz#b3085759b9b2ab503a977aecb7e91153bf941117"
|
||||
integrity sha512-HKKIKf49Vkxlrav3F/w6qRuPcmImGVbIXJ2I3Kg0VMA+3Bav+8yE9G5XmP5lMj6nl4OlqbPftGAscNaNu28b8w==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
@ -2450,10 +2450,10 @@ supports-preserve-symlinks-flag@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
terser@^5.27.0:
|
||||
version "5.27.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.27.0.tgz#70108689d9ab25fef61c4e93e808e9fd092bf20c"
|
||||
integrity sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==
|
||||
terser@^5.27.1:
|
||||
version "5.27.1"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.27.1.tgz#b0092975ea1b379d166088a1a57e32f0839d84a2"
|
||||
integrity sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.3"
|
||||
acorn "^8.8.2"
|
||||
@ -2565,18 +2565,18 @@ vite-plugin-compression@^0.5.1:
|
||||
debug "^4.3.3"
|
||||
fs-extra "^10.0.0"
|
||||
|
||||
vite-plugin-css-injected-by-js@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.1.tgz#26b41f108c5554ee728359bdec01c68c93a48547"
|
||||
integrity sha512-PjM/X45DR3/V1K1fTRs8HtZHEQ55kIfdrn+dzaqNBFrOYO073SeSNCxp4j7gSYhV9NffVHaEnOL4myoko0ePAg==
|
||||
vite-plugin-css-injected-by-js@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.4.0.tgz#b09a571ab50744623736a4b056ecc85d7516311a"
|
||||
integrity sha512-wS5+UYtJXQ/vNornsqTQxOLBVO/UjXU54ZsYMeX0mj2OrbStMQ4GLgvneVDQGPwyGJcm/ntBPawc2lA7xx+Lpg==
|
||||
|
||||
vite@^5.0.12:
|
||||
version "5.0.12"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47"
|
||||
integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==
|
||||
vite@^5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.3.tgz#dd072653a80225702265550a4700561740dfde55"
|
||||
integrity sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==
|
||||
dependencies:
|
||||
esbuild "^0.19.3"
|
||||
postcss "^8.4.32"
|
||||
postcss "^8.4.35"
|
||||
rollup "^4.2.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.3"
|
||||
@ -2594,10 +2594,10 @@ vue-eslint-parser@^9.3.1:
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-eslint-parser@^9.4.0:
|
||||
version "9.4.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.0.tgz#dfd22302e2992fe45748a76553cef7afa5bdde27"
|
||||
integrity sha512-7KsNBb6gHFA75BtneJsoK/dbZ281whUIwFYdQxA68QrCrGMXYzUMbPDHGcOQ0OocIVKrWSKWXZ4mL7tonCXoUw==
|
||||
vue-eslint-parser@^9.4.2:
|
||||
version "9.4.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz#02ffcce82042b082292f2d1672514615f0d95b6d"
|
||||
integrity sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
eslint-scope "^7.1.1"
|
||||
@ -2607,13 +2607,13 @@ vue-eslint-parser@^9.4.0:
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-i18n@^9.9.0:
|
||||
version "9.9.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.9.0.tgz#20d348fa7e37fc88e4c84f69781b2f1215c7769f"
|
||||
integrity sha512-xQ5SxszUAqK5n84N+uUyHH/PiQl9xZ24FOxyAaNonmOQgXeN+rD9z/6DStOpOxNFQn4Cgcquot05gZc+CdOujA==
|
||||
vue-i18n@^9.9.1:
|
||||
version "9.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.9.1.tgz#3c2fdf3c9db430572a1246439d541d01e2795c06"
|
||||
integrity sha512-xyQ4VspLdNSPTKBFBPWa1tvtj+9HuockZwgFeD2OhxxXuC2CWeNvV4seu2o9+vbQOyQbhAM5Ez56oxUrrnTWdw==
|
||||
dependencies:
|
||||
"@intlify/core-base" "9.9.0"
|
||||
"@intlify/shared" "9.9.0"
|
||||
"@intlify/core-base" "9.9.1"
|
||||
"@intlify/shared" "9.9.1"
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
|
||||
vue-router@^4.2.5:
|
||||
@ -2640,16 +2640,16 @@ vue-tsc@^1.8.27:
|
||||
"@vue/language-core" "1.8.27"
|
||||
semver "^7.5.4"
|
||||
|
||||
vue@^3.4.15:
|
||||
version "3.4.15"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.15.tgz#91f979844ffca9239dff622ba4c79c5d5524b88c"
|
||||
integrity sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==
|
||||
vue@^3.4.19:
|
||||
version "3.4.19"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.19.tgz#f9ae0a44db86628548736ff04152830726a97263"
|
||||
integrity sha512-W/7Fc9KUkajFU8dBeDluM4sRGc/aa4YJnOYck8dkjgZoXtVsn3OeTGni66FV1l3+nvPA7VBFYtPioaGKUmEADw==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.4.15"
|
||||
"@vue/compiler-sfc" "3.4.15"
|
||||
"@vue/runtime-dom" "3.4.15"
|
||||
"@vue/server-renderer" "3.4.15"
|
||||
"@vue/shared" "3.4.15"
|
||||
"@vue/compiler-dom" "3.4.19"
|
||||
"@vue/compiler-sfc" "3.4.19"
|
||||
"@vue/runtime-dom" "3.4.19"
|
||||
"@vue/server-renderer" "3.4.19"
|
||||
"@vue/shared" "3.4.19"
|
||||
|
||||
webpack-sources@^3.2.3:
|
||||
version "3.2.3"
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user