Feature: First very basic support to read the grid profile
The parser is still missing and requires community support to collect data.
This commit is contained in:
parent
1acefd8b8c
commit
9ac6dd6e8d
@ -7,6 +7,7 @@
|
|||||||
#include "WebApi_dtu.h"
|
#include "WebApi_dtu.h"
|
||||||
#include "WebApi_eventlog.h"
|
#include "WebApi_eventlog.h"
|
||||||
#include "WebApi_firmware.h"
|
#include "WebApi_firmware.h"
|
||||||
|
#include "WebApi_gridprofile.h"
|
||||||
#include "WebApi_inverter.h"
|
#include "WebApi_inverter.h"
|
||||||
#include "WebApi_limit.h"
|
#include "WebApi_limit.h"
|
||||||
#include "WebApi_maintenance.h"
|
#include "WebApi_maintenance.h"
|
||||||
@ -43,6 +44,7 @@ private:
|
|||||||
WebApiDtuClass _webApiDtu;
|
WebApiDtuClass _webApiDtu;
|
||||||
WebApiEventlogClass _webApiEventlog;
|
WebApiEventlogClass _webApiEventlog;
|
||||||
WebApiFirmwareClass _webApiFirmware;
|
WebApiFirmwareClass _webApiFirmware;
|
||||||
|
WebApiGridProfileClass _webApiGridprofile;
|
||||||
WebApiInverterClass _webApiInverter;
|
WebApiInverterClass _webApiInverter;
|
||||||
WebApiLimitClass _webApiLimit;
|
WebApiLimitClass _webApiLimit;
|
||||||
WebApiMaintenanceClass _webApiMaintenance;
|
WebApiMaintenanceClass _webApiMaintenance;
|
||||||
|
|||||||
15
include/WebApi_gridprofile.h
Normal file
15
include/WebApi_gridprofile.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
class WebApiGridProfileClass {
|
||||||
|
public:
|
||||||
|
void init(AsyncWebServer* server);
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onGridProfileStatus(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
|
AsyncWebServer* _server;
|
||||||
|
};
|
||||||
@ -100,6 +100,11 @@ void HoymilesClass::loop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch grid profile
|
||||||
|
if (iv->Statistics()->getLastUpdate() > 0 && iv->GridProfile()->getLastUpdate() == 0) {
|
||||||
|
iv->sendGridOnProFileParaRequest();
|
||||||
|
}
|
||||||
|
|
||||||
if (++inverterPos >= getNumInverters()) {
|
if (++inverterPos >= getNumInverters()) {
|
||||||
inverterPos = 0;
|
inverterPos = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
40
lib/Hoymiles/src/commands/GridOnProFilePara.cpp
Normal file
40
lib/Hoymiles/src/commands/GridOnProFilePara.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
|
*/
|
||||||
|
#include "GridOnProFilePara.h"
|
||||||
|
#include "Hoymiles.h"
|
||||||
|
#include "inverters/InverterAbstract.h"
|
||||||
|
|
||||||
|
GridOnProFilePara::GridOnProFilePara(uint64_t target_address, uint64_t router_address, time_t time)
|
||||||
|
: MultiDataCommand(target_address, router_address)
|
||||||
|
{
|
||||||
|
setTime(time);
|
||||||
|
setDataType(0x02);
|
||||||
|
setTimeout(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
String GridOnProFilePara::getCommandName()
|
||||||
|
{
|
||||||
|
return "GridOnProFilePara";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GridOnProFilePara::handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id)
|
||||||
|
{
|
||||||
|
// Check CRC of whole payload
|
||||||
|
if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move all fragments into target buffer
|
||||||
|
uint8_t offs = 0;
|
||||||
|
inverter->GridProfile()->beginAppendFragment();
|
||||||
|
inverter->GridProfile()->clearBuffer();
|
||||||
|
for (uint8_t i = 0; i < max_fragment_id; i++) {
|
||||||
|
inverter->GridProfile()->appendFragment(offs, fragment[i].fragment, fragment[i].len);
|
||||||
|
offs += (fragment[i].len);
|
||||||
|
}
|
||||||
|
inverter->GridProfile()->endAppendFragment();
|
||||||
|
inverter->GridProfile()->setLastUpdate(millis());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
13
lib/Hoymiles/src/commands/GridOnProFilePara.h
Normal file
13
lib/Hoymiles/src/commands/GridOnProFilePara.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MultiDataCommand.h"
|
||||||
|
|
||||||
|
class GridOnProFilePara : public MultiDataCommand {
|
||||||
|
public:
|
||||||
|
explicit GridOnProFilePara(uint64_t target_address = 0, uint64_t router_address = 0, time_t time = 0);
|
||||||
|
|
||||||
|
virtual String getCommandName();
|
||||||
|
|
||||||
|
virtual bool handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id);
|
||||||
|
};
|
||||||
@ -8,6 +8,7 @@
|
|||||||
* AlarmDataCommand
|
* AlarmDataCommand
|
||||||
* DevInfoAllCommand
|
* DevInfoAllCommand
|
||||||
* DevInfoSimpleCommand
|
* DevInfoSimpleCommand
|
||||||
|
* GridOnProFilePara
|
||||||
* RealTimeRunDataCommand
|
* RealTimeRunDataCommand
|
||||||
* SystemConfigParaCommand
|
* SystemConfigParaCommand
|
||||||
* ParaSetCommand
|
* ParaSetCommand
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "commands/AlarmDataCommand.h"
|
#include "commands/AlarmDataCommand.h"
|
||||||
#include "commands/DevInfoAllCommand.h"
|
#include "commands/DevInfoAllCommand.h"
|
||||||
#include "commands/DevInfoSimpleCommand.h"
|
#include "commands/DevInfoSimpleCommand.h"
|
||||||
|
#include "commands/GridOnProFilePara.h"
|
||||||
#include "commands/PowerControlCommand.h"
|
#include "commands/PowerControlCommand.h"
|
||||||
#include "commands/RealTimeRunDataCommand.h"
|
#include "commands/RealTimeRunDataCommand.h"
|
||||||
#include "commands/SystemConfigParaCommand.h"
|
#include "commands/SystemConfigParaCommand.h"
|
||||||
@ -203,3 +204,25 @@ bool HM_Abstract::resendPowerControlRequest()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HM_Abstract::sendGridOnProFileParaRequest()
|
||||||
|
{
|
||||||
|
if (!getEnablePolling()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm timeinfo;
|
||||||
|
if (!getLocalTime(&timeinfo, 5)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
auto cmd = _radio->prepareCommand<GridOnProFilePara>();
|
||||||
|
cmd->setTime(now);
|
||||||
|
cmd->setTargetAddress(serial());
|
||||||
|
_radio->enqueCommand(cmd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public:
|
|||||||
bool sendPowerControlRequest(bool turnOn);
|
bool sendPowerControlRequest(bool turnOn);
|
||||||
bool sendRestartControlRequest();
|
bool sendRestartControlRequest();
|
||||||
bool resendPowerControlRequest();
|
bool resendPowerControlRequest();
|
||||||
|
bool sendGridOnProFileParaRequest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t _lastAlarmLogCnt = 0;
|
uint8_t _lastAlarmLogCnt = 0;
|
||||||
|
|||||||
@ -20,6 +20,7 @@ InverterAbstract::InverterAbstract(HoymilesRadio* radio, uint64_t serial)
|
|||||||
|
|
||||||
_alarmLogParser.reset(new AlarmLogParser());
|
_alarmLogParser.reset(new AlarmLogParser());
|
||||||
_devInfoParser.reset(new DevInfoParser());
|
_devInfoParser.reset(new DevInfoParser());
|
||||||
|
_gridProfileParser.reset(new GridProfileParser());
|
||||||
_powerCommandParser.reset(new PowerCommandParser());
|
_powerCommandParser.reset(new PowerCommandParser());
|
||||||
_statisticsParser.reset(new StatisticsParser());
|
_statisticsParser.reset(new StatisticsParser());
|
||||||
_systemConfigParaParser.reset(new SystemConfigParaParser());
|
_systemConfigParaParser.reset(new SystemConfigParaParser());
|
||||||
@ -146,6 +147,11 @@ DevInfoParser* InverterAbstract::DevInfo()
|
|||||||
return _devInfoParser.get();
|
return _devInfoParser.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GridProfileParser* InverterAbstract::GridProfile()
|
||||||
|
{
|
||||||
|
return _gridProfileParser.get();
|
||||||
|
}
|
||||||
|
|
||||||
PowerCommandParser* InverterAbstract::PowerCommand()
|
PowerCommandParser* InverterAbstract::PowerCommand()
|
||||||
{
|
{
|
||||||
return _powerCommandParser.get();
|
return _powerCommandParser.get();
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "../commands/ActivePowerControlCommand.h"
|
#include "../commands/ActivePowerControlCommand.h"
|
||||||
#include "../parser/AlarmLogParser.h"
|
#include "../parser/AlarmLogParser.h"
|
||||||
#include "../parser/DevInfoParser.h"
|
#include "../parser/DevInfoParser.h"
|
||||||
|
#include "../parser/GridProfileParser.h"
|
||||||
#include "../parser/PowerCommandParser.h"
|
#include "../parser/PowerCommandParser.h"
|
||||||
#include "../parser/StatisticsParser.h"
|
#include "../parser/StatisticsParser.h"
|
||||||
#include "../parser/SystemConfigParaParser.h"
|
#include "../parser/SystemConfigParaParser.h"
|
||||||
@ -71,11 +72,13 @@ public:
|
|||||||
virtual bool sendRestartControlRequest() = 0;
|
virtual bool sendRestartControlRequest() = 0;
|
||||||
virtual bool resendPowerControlRequest() = 0;
|
virtual bool resendPowerControlRequest() = 0;
|
||||||
virtual bool sendChangeChannelRequest();
|
virtual bool sendChangeChannelRequest();
|
||||||
|
virtual bool sendGridOnProFileParaRequest() = 0;
|
||||||
|
|
||||||
HoymilesRadio* getRadio();
|
HoymilesRadio* getRadio();
|
||||||
|
|
||||||
AlarmLogParser* EventLog();
|
AlarmLogParser* EventLog();
|
||||||
DevInfoParser* DevInfo();
|
DevInfoParser* DevInfo();
|
||||||
|
GridProfileParser* GridProfile();
|
||||||
PowerCommandParser* PowerCommand();
|
PowerCommandParser* PowerCommand();
|
||||||
StatisticsParser* Statistics();
|
StatisticsParser* Statistics();
|
||||||
SystemConfigParaParser* SystemConfigPara();
|
SystemConfigParaParser* SystemConfigPara();
|
||||||
@ -102,6 +105,7 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<AlarmLogParser> _alarmLogParser;
|
std::unique_ptr<AlarmLogParser> _alarmLogParser;
|
||||||
std::unique_ptr<DevInfoParser> _devInfoParser;
|
std::unique_ptr<DevInfoParser> _devInfoParser;
|
||||||
|
std::unique_ptr<GridProfileParser> _gridProfileParser;
|
||||||
std::unique_ptr<PowerCommandParser> _powerCommandParser;
|
std::unique_ptr<PowerCommandParser> _powerCommandParser;
|
||||||
std::unique_ptr<StatisticsParser> _statisticsParser;
|
std::unique_ptr<StatisticsParser> _statisticsParser;
|
||||||
std::unique_ptr<SystemConfigParaParser> _systemConfigParaParser;
|
std::unique_ptr<SystemConfigParaParser> _systemConfigParaParser;
|
||||||
|
|||||||
57
lib/Hoymiles/src/parser/GridProfileParser.cpp
Normal file
57
lib/Hoymiles/src/parser/GridProfileParser.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
|
*/
|
||||||
|
#include "GridProfileParser.h"
|
||||||
|
#include "../Hoymiles.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#define HOY_SEMAPHORE_TAKE() \
|
||||||
|
do { \
|
||||||
|
} while (xSemaphoreTake(_xSemaphore, portMAX_DELAY) != pdPASS)
|
||||||
|
#define HOY_SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore)
|
||||||
|
|
||||||
|
GridProfileParser::GridProfileParser()
|
||||||
|
: Parser()
|
||||||
|
{
|
||||||
|
_xSemaphore = xSemaphoreCreateMutex();
|
||||||
|
HOY_SEMAPHORE_GIVE(); // release before first use
|
||||||
|
clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GridProfileParser::clearBuffer()
|
||||||
|
{
|
||||||
|
memset(_payloadGridProfile, 0, GRID_PROFILE_SIZE);
|
||||||
|
_gridProfileLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GridProfileParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t len)
|
||||||
|
{
|
||||||
|
if (offset + len > GRID_PROFILE_SIZE) {
|
||||||
|
Hoymiles.getMessageOutput()->printf("FATAL: (%s, %d) grid profile packet too large for buffer\r\n", __FILE__, __LINE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(&_payloadGridProfile[offset], payload, len);
|
||||||
|
_gridProfileLength += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GridProfileParser::beginAppendFragment()
|
||||||
|
{
|
||||||
|
HOY_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GridProfileParser::endAppendFragment()
|
||||||
|
{
|
||||||
|
HOY_SEMAPHORE_GIVE();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> GridProfileParser::getRawData()
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> ret;
|
||||||
|
HOY_SEMAPHORE_TAKE();
|
||||||
|
for (uint8_t i = 0; i < GRID_PROFILE_SIZE; i++) {
|
||||||
|
ret.push_back(_payloadGridProfile[i]);
|
||||||
|
}
|
||||||
|
HOY_SEMAPHORE_GIVE();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
24
lib/Hoymiles/src/parser/GridProfileParser.h
Normal file
24
lib/Hoymiles/src/parser/GridProfileParser.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma once
|
||||||
|
#include "Parser.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#define GRID_PROFILE_SIZE 141
|
||||||
|
|
||||||
|
class GridProfileParser : public Parser {
|
||||||
|
public:
|
||||||
|
GridProfileParser();
|
||||||
|
void clearBuffer();
|
||||||
|
void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len);
|
||||||
|
|
||||||
|
void beginAppendFragment();
|
||||||
|
void endAppendFragment();
|
||||||
|
|
||||||
|
std::vector<uint8_t> getRawData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t _payloadGridProfile[GRID_PROFILE_SIZE] = {};
|
||||||
|
uint8_t _gridProfileLength = 0;
|
||||||
|
|
||||||
|
SemaphoreHandle_t _xSemaphore;
|
||||||
|
};
|
||||||
@ -23,6 +23,7 @@ void WebApiClass::init()
|
|||||||
_webApiDtu.init(&_server);
|
_webApiDtu.init(&_server);
|
||||||
_webApiEventlog.init(&_server);
|
_webApiEventlog.init(&_server);
|
||||||
_webApiFirmware.init(&_server);
|
_webApiFirmware.init(&_server);
|
||||||
|
_webApiGridprofile.init(&_server);
|
||||||
_webApiInverter.init(&_server);
|
_webApiInverter.init(&_server);
|
||||||
_webApiLimit.init(&_server);
|
_webApiLimit.init(&_server);
|
||||||
_webApiMaintenance.init(&_server);
|
_webApiMaintenance.init(&_server);
|
||||||
@ -48,6 +49,7 @@ void WebApiClass::loop()
|
|||||||
_webApiDtu.loop();
|
_webApiDtu.loop();
|
||||||
_webApiEventlog.loop();
|
_webApiEventlog.loop();
|
||||||
_webApiFirmware.loop();
|
_webApiFirmware.loop();
|
||||||
|
_webApiGridprofile.loop();
|
||||||
_webApiInverter.loop();
|
_webApiInverter.loop();
|
||||||
_webApiLimit.loop();
|
_webApiLimit.loop();
|
||||||
_webApiMaintenance.loop();
|
_webApiMaintenance.loop();
|
||||||
|
|||||||
49
src/WebApi_gridprofile.cpp
Normal file
49
src/WebApi_gridprofile.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
|
*/
|
||||||
|
#include "WebApi_gridprofile.h"
|
||||||
|
#include "WebApi.h"
|
||||||
|
#include <AsyncJson.h>
|
||||||
|
#include <Hoymiles.h>
|
||||||
|
|
||||||
|
void WebApiGridProfileClass::init(AsyncWebServer* server)
|
||||||
|
{
|
||||||
|
using std::placeholders::_1;
|
||||||
|
|
||||||
|
_server = server;
|
||||||
|
|
||||||
|
_server->on("/api/gridprofile/status", HTTP_GET, std::bind(&WebApiGridProfileClass::onGridProfileStatus, this, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiGridProfileClass::loop()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiGridProfileClass::onGridProfileStatus(AsyncWebServerRequest* request)
|
||||||
|
{
|
||||||
|
if (!WebApi.checkCredentialsReadonly(request)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096);
|
||||||
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
|
uint64_t serial = 0;
|
||||||
|
if (request->hasParam("inv")) {
|
||||||
|
String s = request->getParam("inv")->value();
|
||||||
|
serial = strtoll(s.c_str(), NULL, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||||
|
|
||||||
|
if (inv != nullptr) {
|
||||||
|
auto raw = root.createNestedArray("raw");
|
||||||
|
auto data = inv->GridProfile()->getRawData();
|
||||||
|
|
||||||
|
copyArray(&data[0], data.size(), raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
50
webapp/src/components/GridProfile.vue
Normal file
50
webapp/src/components/GridProfile.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<BootstrapAlert :show="!hasValidData">
|
||||||
|
<h4 class="alert-heading">
|
||||||
|
<BIconInfoSquare class="fs-2" /> {{ $t('gridprofile.NoInfo') }}
|
||||||
|
</h4>{{ $t('gridprofile.NoInfoLong') }}
|
||||||
|
</BootstrapAlert>
|
||||||
|
|
||||||
|
<template v-if="hasValidData">
|
||||||
|
<BootstrapAlert :show="true" variant="danger">
|
||||||
|
<h4 class="info-heading">
|
||||||
|
<BIconInfoSquare class="fs-2" /> {{ $t('gridprofile.GridprofileSupport') }}
|
||||||
|
</h4><div v-html="$t('gridprofile.GridprofileSupportLong')"></div>
|
||||||
|
</BootstrapAlert>
|
||||||
|
<samp >
|
||||||
|
{{ rawContent() }}
|
||||||
|
</samp>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
||||||
|
import type { GridProfileStatus } from "@/types/GridProfileStatus";
|
||||||
|
import { BIconInfoSquare } from 'bootstrap-icons-vue';
|
||||||
|
import { defineComponent, type PropType } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
BootstrapAlert,
|
||||||
|
BIconInfoSquare,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
gridProfileList: { type: Object as PropType<GridProfileStatus>, required: true },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rawContent() {
|
||||||
|
return () => {
|
||||||
|
return this.gridProfileList.raw.map(function (x) {
|
||||||
|
let y = x.toString(16); // to hex
|
||||||
|
y = ("00" + y).substr(-2); // zero-pad to 2-digits
|
||||||
|
return y
|
||||||
|
}).join(' ');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasValidData() {
|
||||||
|
return this.gridProfileList.raw.reduce((sum, x) => sum + x, 0) > 0;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -126,7 +126,9 @@
|
|||||||
"Failure": "Fehlgeschlagen",
|
"Failure": "Fehlgeschlagen",
|
||||||
"Pending": "Ausstehend",
|
"Pending": "Ausstehend",
|
||||||
"Ok": "Ok",
|
"Ok": "Ok",
|
||||||
"Unknown": "Unbekannt"
|
"Unknown": "Unbekannt",
|
||||||
|
"ShowGridProfile": "Zeige Grid Profil",
|
||||||
|
"GridProfile": "Grid Profil"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Begin",
|
"Start": "Begin",
|
||||||
@ -149,6 +151,12 @@
|
|||||||
"HardwarePartNumber": "Hardware-Teilenummer",
|
"HardwarePartNumber": "Hardware-Teilenummer",
|
||||||
"HardwareVersion": "Hardware-Version"
|
"HardwareVersion": "Hardware-Version"
|
||||||
},
|
},
|
||||||
|
"gridprofile": {
|
||||||
|
"NoInfo": "@:devinfo.NoInfo",
|
||||||
|
"NoInfoLong": "@:devinfo.NoInfoLong",
|
||||||
|
"GridprofileSupport": "Unterstütze die Entwicklung",
|
||||||
|
"GridprofileSupportLong": "Weitere Informationen sind <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">hier</a> zu finden."
|
||||||
|
},
|
||||||
"systeminfo": {
|
"systeminfo": {
|
||||||
"SystemInfo": "System Informationen",
|
"SystemInfo": "System Informationen",
|
||||||
"VersionError": "Fehler beim Abrufen von Versionsinformationen",
|
"VersionError": "Fehler beim Abrufen von Versionsinformationen",
|
||||||
|
|||||||
@ -126,7 +126,9 @@
|
|||||||
"Failure": "Failure",
|
"Failure": "Failure",
|
||||||
"Pending": "Pending",
|
"Pending": "Pending",
|
||||||
"Ok": "Ok",
|
"Ok": "Ok",
|
||||||
"Unknown": "Unknown"
|
"Unknown": "Unknown",
|
||||||
|
"ShowGridProfile": "Show Grid Profile",
|
||||||
|
"GridProfile": "Grid Profile"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Start",
|
"Start": "Start",
|
||||||
@ -149,6 +151,12 @@
|
|||||||
"HardwarePartNumber": "Hardware Part Number",
|
"HardwarePartNumber": "Hardware Part Number",
|
||||||
"HardwareVersion": "Hardware Version"
|
"HardwareVersion": "Hardware Version"
|
||||||
},
|
},
|
||||||
|
"gridprofile": {
|
||||||
|
"NoInfo": "@:devinfo.NoInfo",
|
||||||
|
"NoInfoLong": "@:devinfo.NoInfoLong",
|
||||||
|
"GridprofileSupport": "Support the development",
|
||||||
|
"GridprofileSupportLong": "Please see <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">here</a> for further information."
|
||||||
|
},
|
||||||
"systeminfo": {
|
"systeminfo": {
|
||||||
"SystemInfo": "System Info",
|
"SystemInfo": "System Info",
|
||||||
"VersionError": "Error fetching version information",
|
"VersionError": "Error fetching version information",
|
||||||
|
|||||||
@ -126,7 +126,9 @@
|
|||||||
"Failure": "Échec",
|
"Failure": "Échec",
|
||||||
"Pending": "En attente",
|
"Pending": "En attente",
|
||||||
"Ok": "OK",
|
"Ok": "OK",
|
||||||
"Unknown": "Inconnu"
|
"Unknown": "Inconnu",
|
||||||
|
"ShowGridProfile": "Show Grid Profile",
|
||||||
|
"GridProfile": "Grid Profile"
|
||||||
},
|
},
|
||||||
"eventlog": {
|
"eventlog": {
|
||||||
"Start": "Départ",
|
"Start": "Départ",
|
||||||
@ -149,6 +151,12 @@
|
|||||||
"HardwarePartNumber": "Numéro d'article matériel",
|
"HardwarePartNumber": "Numéro d'article matériel",
|
||||||
"HardwareVersion": "Version du matériel"
|
"HardwareVersion": "Version du matériel"
|
||||||
},
|
},
|
||||||
|
"gridprofile": {
|
||||||
|
"NoInfo": "@:devinfo.NoInfo",
|
||||||
|
"NoInfoLong": "@:devinfo.NoInfoLong",
|
||||||
|
"GridprofileSupport": "Support the development",
|
||||||
|
"GridprofileSupportLong": "Please see <a href=\"https://github.com/tbnobody/OpenDTU/wiki/Grid-Profile-Parser\" target=\"_blank\">here</a> for further information."
|
||||||
|
},
|
||||||
"systeminfo": {
|
"systeminfo": {
|
||||||
"SystemInfo": "Informations sur le système",
|
"SystemInfo": "Informations sur le système",
|
||||||
"VersionError": "Erreur de récupération des informations de version",
|
"VersionError": "Erreur de récupération des informations de version",
|
||||||
|
|||||||
3
webapp/src/types/GridProfileStatus.ts
Normal file
3
webapp/src/types/GridProfileStatus.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface GridProfileStatus {
|
||||||
|
raw: Array<number>;
|
||||||
|
}
|
||||||
@ -78,6 +78,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group me-2" role="group">
|
||||||
|
<button type="button" class="btn btn-sm btn-info"
|
||||||
|
@click="onShowGridProfile(inverter.serial)" v-tooltip :title="$t('home.ShowGridProfile')">
|
||||||
|
<BIconOutlet style="font-size:24px;" />
|
||||||
|
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button v-if="inverter.events >= 0" type="button"
|
<button v-if="inverter.events >= 0" type="button"
|
||||||
class="btn btn-sm btn-secondary position-relative"
|
class="btn btn-sm btn-secondary position-relative"
|
||||||
@ -167,6 +175,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal" id="gridProfileView" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{ $t('home.GridProfile') }}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="text-center" v-if="gridProfileLoading">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<GridProfile v-if="!gridProfileLoading" :gridProfileList="gridProfileList" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" @click="onHideGridProfile"
|
||||||
|
data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal" id="limitSettingView" ref="limitSettingView" tabindex="-1">
|
<div class="modal" id="limitSettingView" ref="limitSettingView" tabindex="-1">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -321,11 +354,13 @@ import BasePage from '@/components/BasePage.vue';
|
|||||||
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
||||||
import DevInfo from '@/components/DevInfo.vue';
|
import DevInfo from '@/components/DevInfo.vue';
|
||||||
import EventLog from '@/components/EventLog.vue';
|
import EventLog from '@/components/EventLog.vue';
|
||||||
|
import GridProfile from '@/components/GridProfile.vue';
|
||||||
import HintView from '@/components/HintView.vue';
|
import HintView from '@/components/HintView.vue';
|
||||||
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
||||||
import InverterTotalInfo from '@/components/InverterTotalInfo.vue';
|
import InverterTotalInfo from '@/components/InverterTotalInfo.vue';
|
||||||
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
||||||
import type { EventlogItems } from '@/types/EventlogStatus';
|
import type { EventlogItems } from '@/types/EventlogStatus';
|
||||||
|
import type { GridProfileStatus } from '@/types/GridProfileStatus';
|
||||||
import type { LimitConfig } from '@/types/LimitConfig';
|
import type { LimitConfig } from '@/types/LimitConfig';
|
||||||
import type { LimitStatus } from '@/types/LimitStatus';
|
import type { LimitStatus } from '@/types/LimitStatus';
|
||||||
import type { Inverter, LiveData } from '@/types/LiveDataStatus';
|
import type { Inverter, LiveData } from '@/types/LiveDataStatus';
|
||||||
@ -337,6 +372,7 @@ import {
|
|||||||
BIconCpu,
|
BIconCpu,
|
||||||
BIconExclamationCircleFill,
|
BIconExclamationCircleFill,
|
||||||
BIconJournalText,
|
BIconJournalText,
|
||||||
|
BIconOutlet,
|
||||||
BIconPower,
|
BIconPower,
|
||||||
BIconSpeedometer,
|
BIconSpeedometer,
|
||||||
BIconToggleOff,
|
BIconToggleOff,
|
||||||
@ -351,6 +387,7 @@ export default defineComponent({
|
|||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
DevInfo,
|
DevInfo,
|
||||||
EventLog,
|
EventLog,
|
||||||
|
GridProfile,
|
||||||
HintView,
|
HintView,
|
||||||
InverterChannelInfo,
|
InverterChannelInfo,
|
||||||
InverterTotalInfo,
|
InverterTotalInfo,
|
||||||
@ -359,6 +396,7 @@ export default defineComponent({
|
|||||||
BIconCpu,
|
BIconCpu,
|
||||||
BIconExclamationCircleFill,
|
BIconExclamationCircleFill,
|
||||||
BIconJournalText,
|
BIconJournalText,
|
||||||
|
BIconOutlet,
|
||||||
BIconPower,
|
BIconPower,
|
||||||
BIconSpeedometer,
|
BIconSpeedometer,
|
||||||
BIconToggleOff,
|
BIconToggleOff,
|
||||||
@ -381,6 +419,9 @@ export default defineComponent({
|
|||||||
devInfoView: {} as bootstrap.Modal,
|
devInfoView: {} as bootstrap.Modal,
|
||||||
devInfoList: {} as DevInfoStatus,
|
devInfoList: {} as DevInfoStatus,
|
||||||
devInfoLoading: true,
|
devInfoLoading: true,
|
||||||
|
gridProfileView: {} as bootstrap.Modal,
|
||||||
|
gridProfileList: {} as GridProfileStatus,
|
||||||
|
gridProfileLoading: true,
|
||||||
|
|
||||||
limitSettingView: {} as bootstrap.Modal,
|
limitSettingView: {} as bootstrap.Modal,
|
||||||
limitSettingLoading: true,
|
limitSettingLoading: true,
|
||||||
@ -421,6 +462,7 @@ export default defineComponent({
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.eventLogView = new bootstrap.Modal('#eventView');
|
this.eventLogView = new bootstrap.Modal('#eventView');
|
||||||
this.devInfoView = new bootstrap.Modal('#devInfoView');
|
this.devInfoView = new bootstrap.Modal('#devInfoView');
|
||||||
|
this.gridProfileView = new bootstrap.Modal('#gridProfileView');
|
||||||
this.limitSettingView = new bootstrap.Modal('#limitSettingView');
|
this.limitSettingView = new bootstrap.Modal('#limitSettingView');
|
||||||
this.powerSettingView = new bootstrap.Modal('#powerSettingView');
|
this.powerSettingView = new bootstrap.Modal('#powerSettingView');
|
||||||
|
|
||||||
@ -562,6 +604,20 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.devInfoView.show();
|
this.devInfoView.show();
|
||||||
},
|
},
|
||||||
|
onHideGridProfile() {
|
||||||
|
this.devInfoView.hide();
|
||||||
|
},
|
||||||
|
onShowGridProfile(serial: number) {
|
||||||
|
this.gridProfileLoading = true;
|
||||||
|
fetch("/api/gridprofile/status?inv=" + serial, { headers: authHeader() })
|
||||||
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
|
.then((data) => {
|
||||||
|
this.gridProfileList = data;
|
||||||
|
this.gridProfileLoading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gridProfileView.show();
|
||||||
|
},
|
||||||
onHideLimitSettings() {
|
onHideLimitSettings() {
|
||||||
this.showAlertLimit = false;
|
this.showAlertLimit = false;
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user