Merge 438773f803 into 653efb41a2
This commit is contained in:
commit
d18d818e1a
@ -35,6 +35,8 @@
|
||||
#define DEV_MAX_MAPPING_NAME_STRLEN 63
|
||||
#define LOCALE_STRLEN 2
|
||||
|
||||
#define INTEGRATIONS_GOE_MAX_HOSTNAME_STRLEN 128
|
||||
|
||||
struct CHANNEL_CONFIG_T {
|
||||
uint16_t MaxChannelPower;
|
||||
char Name[CHAN_MAX_NAME_STRLEN];
|
||||
@ -161,6 +163,14 @@ struct CONFIG_T {
|
||||
|
||||
INVERTER_CONFIG_T Inverter[INV_MAX_COUNT];
|
||||
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
|
||||
|
||||
struct {
|
||||
// go-e Controller
|
||||
bool GoeControllerEnabled;
|
||||
bool GoeControllerPublishHomeCategory;
|
||||
char GoeControllerHostname[INTEGRATIONS_GOE_MAX_HOSTNAME_STRLEN + 1];
|
||||
uint32_t GoeControllerUpdateInterval;
|
||||
} Integrations;
|
||||
};
|
||||
|
||||
class ConfigurationClass {
|
||||
|
||||
23
include/IntegrationsGoeController.h
Normal file
23
include/IntegrationsGoeController.h
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include "NetworkSettings.h"
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class IntegrationsGoeControllerClass {
|
||||
public:
|
||||
IntegrationsGoeControllerClass();
|
||||
void init(Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void loop();
|
||||
void NetworkEvent(network_event event);
|
||||
|
||||
Task _loopTask;
|
||||
|
||||
bool _networkConnected = false;
|
||||
HTTPClient _http;
|
||||
};
|
||||
|
||||
extern IntegrationsGoeControllerClass IntegrationsGoeController;
|
||||
@ -10,6 +10,7 @@
|
||||
#include "WebApi_firmware.h"
|
||||
#include "WebApi_gridprofile.h"
|
||||
#include "WebApi_i18n.h"
|
||||
#include "WebApi_integrations.h"
|
||||
#include "WebApi_inverter.h"
|
||||
#include "WebApi_limit.h"
|
||||
#include "WebApi_maintenance.h"
|
||||
@ -68,6 +69,7 @@ private:
|
||||
WebApiWebappClass _webApiWebapp;
|
||||
WebApiWsConsoleClass _webApiWsConsole;
|
||||
WebApiWsLiveClass _webApiWsLive;
|
||||
WebApiIntegrationsClass _webApiIntegrations;
|
||||
};
|
||||
|
||||
extern WebApiClass WebApi;
|
||||
|
||||
@ -94,4 +94,8 @@ enum WebApiError {
|
||||
|
||||
HardwareBase = 12000,
|
||||
HardwarePinMappingLength,
|
||||
|
||||
IntegrationsBase = 13000,
|
||||
IntegrationsGoeControllerHostnameLength,
|
||||
IntegrationsGoeControllerUpdateInterval,
|
||||
};
|
||||
|
||||
14
include/WebApi_integrations.h
Normal file
14
include/WebApi_integrations.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
|
||||
class WebApiIntegrationsClass {
|
||||
public:
|
||||
void init(AsyncWebServer& server, Scheduler& scheduler);
|
||||
|
||||
private:
|
||||
void onIntegrationsAdminGet(AsyncWebServerRequest* request);
|
||||
void onIntegrationsAdminPost(AsyncWebServerRequest* request);
|
||||
};
|
||||
@ -110,3 +110,8 @@
|
||||
#define MAX_INVERTER_LIMIT 2250
|
||||
|
||||
#define LANG_PACK_SUFFIX ".lang.json"
|
||||
|
||||
#define INTEGRATIONS_GOE_CTRL_HOSTNAME ""
|
||||
#define INTEGRATIONS_GOE_CTRL_ENABLED false
|
||||
#define INTEGRATIONS_GOE_CTRL_ENABLE_HOME_CATEGORY false
|
||||
#define INTEGRATIONS_GOE_CTRL_UPDATE_INTERVAL 3U
|
||||
|
||||
@ -151,6 +151,12 @@ bool ConfigurationClass::write()
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject integrations = doc["integrations"].to<JsonObject>();
|
||||
integrations["goe_ctrl_hostname"] = config.Integrations.GoeControllerHostname;
|
||||
integrations["goe_ctrl_enabled"] = config.Integrations.GoeControllerEnabled;
|
||||
integrations["goe_ctrl_publish_home_category"] = config.Integrations.GoeControllerPublishHomeCategory;
|
||||
integrations["goe_ctrl_update_interval"] = config.Integrations.GoeControllerUpdateInterval;
|
||||
|
||||
if (!Utils::checkJsonAlloc(doc, __FUNCTION__, __LINE__)) {
|
||||
return false;
|
||||
}
|
||||
@ -327,6 +333,12 @@ bool ConfigurationClass::read()
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject integrations = doc["integrations"];
|
||||
strlcpy(config.Integrations.GoeControllerHostname, integrations["goe_ctrl_hostname"] | INTEGRATIONS_GOE_CTRL_HOSTNAME, sizeof(config.Integrations.GoeControllerHostname));
|
||||
config.Integrations.GoeControllerEnabled = integrations["goe_ctrl_enabled"] | INTEGRATIONS_GOE_CTRL_ENABLED;
|
||||
config.Integrations.GoeControllerPublishHomeCategory = integrations["goe_ctrl_publish_home_category"] | INTEGRATIONS_GOE_CTRL_ENABLE_HOME_CATEGORY;
|
||||
config.Integrations.GoeControllerUpdateInterval = integrations["goe_ctrl_update_interval"] | INTEGRATIONS_GOE_CTRL_UPDATE_INTERVAL;
|
||||
|
||||
f.close();
|
||||
|
||||
// Check for default DTU serial
|
||||
|
||||
94
src/IntegrationsGoeController.cpp
Normal file
94
src/IntegrationsGoeController.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "IntegrationsGoeController.h"
|
||||
#include "Configuration.h"
|
||||
#include "Datastore.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "NetworkSettings.h"
|
||||
#include <Hoymiles.h>
|
||||
|
||||
IntegrationsGoeControllerClass IntegrationsGoeController;
|
||||
|
||||
IntegrationsGoeControllerClass::IntegrationsGoeControllerClass()
|
||||
: _loopTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&IntegrationsGoeControllerClass::loop, this))
|
||||
{
|
||||
}
|
||||
|
||||
void IntegrationsGoeControllerClass::init(Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
NetworkSettings.onEvent(std::bind(&IntegrationsGoeControllerClass::NetworkEvent, this, _1));
|
||||
|
||||
scheduler.addTask(_loopTask);
|
||||
_loopTask.setInterval(Configuration.get().Integrations.GoeControllerUpdateInterval * TASK_SECOND);
|
||||
_loopTask.enable();
|
||||
}
|
||||
|
||||
void IntegrationsGoeControllerClass::NetworkEvent(network_event event)
|
||||
{
|
||||
switch (event) {
|
||||
case network_event::NETWORK_GOT_IP:
|
||||
_networkConnected = true;
|
||||
break;
|
||||
case network_event::NETWORK_DISCONNECTED:
|
||||
_networkConnected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationsGoeControllerClass::loop()
|
||||
{
|
||||
const auto& integrationsConfig = Configuration.get().Integrations;
|
||||
|
||||
const bool reachable = Datastore.getIsAllEnabledReachable();
|
||||
|
||||
_loopTask.setInterval((reachable ? integrationsConfig.GoeControllerUpdateInterval : std::min(integrationsConfig.GoeControllerUpdateInterval, 5U)) * TASK_SECOND);
|
||||
|
||||
if (!integrationsConfig.GoeControllerEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_networkConnected || !Hoymiles.isAllRadioIdle()) {
|
||||
_loopTask.forceNextIteration();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto value = reachable ? Datastore.getTotalAcPowerEnabled() : 0;
|
||||
|
||||
// home, grid, car, relais, solar
|
||||
// ecp is an array of numbers or null: [{power}, null, null, null, {power}]
|
||||
// setting the home category to the power should be configurable
|
||||
// url is this: http://{hostname}/api/set?ecp=
|
||||
|
||||
auto url = "http://" + String(integrationsConfig.GoeControllerHostname) + "/api/set?ecp=";
|
||||
|
||||
url += "[";
|
||||
url += integrationsConfig.GoeControllerPublishHomeCategory ? String(value) : "null";
|
||||
url += ",null,null,null,";
|
||||
url += value;
|
||||
url += "]";
|
||||
|
||||
const auto timeout = std::max(2U, std::min(integrationsConfig.GoeControllerUpdateInterval-1, 3U)) * 1000U;
|
||||
|
||||
_http.setConnectTimeout(timeout);
|
||||
_http.setTimeout(timeout);
|
||||
_http.setReuse(true);
|
||||
_http.begin(url);
|
||||
|
||||
int httpCode = _http.GET();
|
||||
|
||||
if (httpCode > 0) {
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
MessageOutput.println("go-e Controller updated");
|
||||
} else {
|
||||
MessageOutput.printf("HTTP error: %d\n", httpCode);
|
||||
}
|
||||
} else {
|
||||
MessageOutput.println("HTTP error");
|
||||
}
|
||||
}
|
||||
@ -292,7 +292,7 @@ void NetworkSettingsClass::applyConfig()
|
||||
MessageOutput.print("existing credentials... ");
|
||||
WiFi.begin();
|
||||
}
|
||||
MessageOutput.println("done");
|
||||
MessageOutput.println("done. Connecting to " + String(Configuration.get().WiFi.Ssid));
|
||||
setStaticIp();
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ void WebApiClass::init(Scheduler& scheduler)
|
||||
_webApiWebapp.init(_server, scheduler);
|
||||
_webApiWsConsole.init(_server, scheduler);
|
||||
_webApiWsLive.init(_server, scheduler);
|
||||
_webApiIntegrations.init(_server, scheduler);
|
||||
|
||||
_server.begin();
|
||||
}
|
||||
|
||||
94
src/WebApi_integrations.cpp
Normal file
94
src/WebApi_integrations.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2022-2024 Thomas Basler and others
|
||||
*/
|
||||
#include "WebApi_integrations.h"
|
||||
#include "Configuration.h"
|
||||
#include "WebApi.h"
|
||||
#include "WebApi_errors.h"
|
||||
#include "helper.h"
|
||||
#include <AsyncJson.h>
|
||||
|
||||
void WebApiIntegrationsClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
|
||||
server.on("/api/integrations/config", HTTP_GET, std::bind(&WebApiIntegrationsClass::onIntegrationsAdminGet, this, _1));
|
||||
server.on("/api/integrations/config", HTTP_POST, std::bind(&WebApiIntegrationsClass::onIntegrationsAdminPost, this, _1));
|
||||
}
|
||||
|
||||
void WebApiIntegrationsClass::onIntegrationsAdminGet(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (!WebApi.checkCredentials(request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||
auto& root = response->getRoot();
|
||||
const CONFIG_T& config = Configuration.get();
|
||||
|
||||
root["goe_ctrl_hostname"] = config.Integrations.GoeControllerHostname;
|
||||
root["goe_ctrl_enabled"] = config.Integrations.GoeControllerEnabled;
|
||||
root["goe_ctrl_publish_home_category"] = config.Integrations.GoeControllerPublishHomeCategory;
|
||||
root["goe_ctrl_update_interval"] = config.Integrations.GoeControllerUpdateInterval;
|
||||
|
||||
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void WebApiIntegrationsClass::onIntegrationsAdminPost(AsyncWebServerRequest* request)
|
||||
{
|
||||
if (!WebApi.checkCredentials(request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||
JsonDocument root;
|
||||
if (!WebApi.parseRequestData(request, response, root)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& retMsg = response->getRoot();
|
||||
|
||||
if (!(root["goe_ctrl_hostname"].is<String>()
|
||||
&& root["goe_ctrl_enabled"].is<bool>()
|
||||
&& root["goe_ctrl_publish_home_category"].is<bool>()
|
||||
&& root["goe_ctrl_update_interval"].is<uint32_t>())) {
|
||||
retMsg["message"] = "Values are missing!";
|
||||
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root["goe_ctrl_enabled"].as<bool>()) {
|
||||
if (root["goe_ctrl_hostname"].as<String>().length() == 0 || root["goe_ctrl_hostname"].as<String>().length() > INTEGRATIONS_GOE_MAX_HOSTNAME_STRLEN) {
|
||||
retMsg["message"] = "go-e Controller hostname must between 1 and " STR(INTEGRATIONS_GOE_MAX_HOSTNAME_STRLEN) " characters long!";
|
||||
retMsg["code"] = WebApiError::IntegrationsGoeControllerHostnameLength;
|
||||
retMsg["param"]["max"] = INTEGRATIONS_GOE_MAX_HOSTNAME_STRLEN;
|
||||
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root["goe_ctrl_update_interval"].as<uint32_t>() < 3 || root["goe_ctrl_update_interval"].as<uint32_t>() > 65535) {
|
||||
retMsg["message"] = "go-e Controller update interval must between 3 and 65535!";
|
||||
retMsg["code"] = WebApiError::IntegrationsGoeControllerUpdateInterval;
|
||||
retMsg["param"]["min"] = 3;
|
||||
retMsg["param"]["max"] = 65535;
|
||||
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto guard = Configuration.getWriteGuard();
|
||||
auto& config = guard.getConfig();
|
||||
|
||||
config.Integrations.GoeControllerEnabled = root["goe_ctrl_enabled"].as<bool>();
|
||||
config.Integrations.GoeControllerPublishHomeCategory = root["goe_ctrl_publish_home_category"].as<bool>();
|
||||
config.Integrations.GoeControllerUpdateInterval = root["goe_ctrl_update_interval"].as<uint32_t>();
|
||||
strlcpy(config.Integrations.GoeControllerHostname, root["goe_ctrl_hostname"].as<String>().c_str(), sizeof(config.Integrations.GoeControllerHostname));
|
||||
}
|
||||
|
||||
WebApi.writeConfig(retMsg);
|
||||
|
||||
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
#include "Configuration.h"
|
||||
#include "Datastore.h"
|
||||
#include "Display_Graphic.h"
|
||||
#include "IntegrationsGoeController.h"
|
||||
#include "I18n.h"
|
||||
#include "InverterSettings.h"
|
||||
#include "Led_Single.h"
|
||||
@ -121,6 +122,11 @@ void setup()
|
||||
MqttHandleHass.init(scheduler);
|
||||
MessageOutput.println("done");
|
||||
|
||||
// Initialize go-e Integration
|
||||
MessageOutput.print("Initialize go-e Integration... ");
|
||||
IntegrationsGoeController.init(scheduler);
|
||||
MessageOutput.println("done");
|
||||
|
||||
// Initialize WebApi
|
||||
MessageOutput.print("Initialize WebApi... ");
|
||||
WebApi.init(scheduler);
|
||||
|
||||
1
webapp/.nvmrc
Normal file
1
webapp/.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
22.9.0
|
||||
@ -47,5 +47,8 @@
|
||||
"vite-plugin-css-injected-by-js": "^3.5.2",
|
||||
"vue-tsc": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=21.1.0"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
:class="[wide ? 'col-sm-4' : 'col-sm-2', isCheckbox ? 'form-check-label' : 'col-form-label']"
|
||||
>
|
||||
{{ label }}
|
||||
<BIconInfoCircle v-if="tooltip !== undefined" v-tooltip :title="tooltip" />
|
||||
<BIconInfoCircle v-if="tooltip !== undefined" v-tooltip :title="tooltip" class="ms-1" />
|
||||
</label>
|
||||
<div :class="[wide ? 'col-sm-8' : 'col-sm-10']">
|
||||
<div v-if="!isTextarea" :class="{ 'form-check form-switch': isCheckbox, 'input-group': postfix || prefix }">
|
||||
|
||||
@ -73,6 +73,11 @@
|
||||
$t('menu.DeviceManager')
|
||||
}}</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link @click="onClick" class="dropdown-item" to="/settings/integrations">{{
|
||||
$t('menu.Integrations')
|
||||
}}</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<hr class="dropdown-divider" />
|
||||
</li>
|
||||
|
||||
@ -113,7 +113,9 @@
|
||||
"10002": "Authentifizierung erfolgreich!",
|
||||
"11001": "@:apiresponse.2001",
|
||||
"11002": "@:apiresponse:5004",
|
||||
"12001": "Profil muss zwischen 1 und {max} Zeichen lang sein!"
|
||||
"12001": "Profil muss zwischen 1 und {max} Zeichen lang sein!",
|
||||
"13001": "Hostname muss zwischen 1 und {max} Zeichen lang sein!",
|
||||
"13002": "Aktualisierungsintervall muss zwischen {min} und {max} Sekunden liegen!"
|
||||
},
|
||||
"home": {
|
||||
"LiveData": "Live-Daten",
|
||||
@ -668,6 +670,18 @@
|
||||
"EqualBrightness": "Gleiche Helligkeit",
|
||||
"LedBrightness": "LED {led} Helligkeit ({brightness})"
|
||||
},
|
||||
"integrationsadmin": {
|
||||
"IntegrationSettings": "Integrationseinstellungen",
|
||||
"Save": "@:base.Save",
|
||||
"Cancel": "@:base.Cancel",
|
||||
"goecontroller": "go-e Controller",
|
||||
"goecontrollerEnabled": "go-e Controller aktivieren",
|
||||
"goecontrollerEnabledHint": "Aktiviere die go-e Controller-Integration. Dadurch wird der 'ecp' API-Key gesetzt, um dem Controller mitzuteilen, wie viel Solarenergie produziert wird.",
|
||||
"goecontrollerHostname": "Hostname",
|
||||
"goecontrollerUpdateInterval": "Aktualisierungsintervall",
|
||||
"goecontrollerEnableHomeCategory": "Heim-Kategorie aktivieren",
|
||||
"goecontrollerEnableHomeCategoryHint": "Setze auch den Wert für die Heim-Kategorie. Auf diese Weise kannst du den korrekten Verbrauch deines Hauses haben, wenn dein Wechselrichter auch in der Heim-Kategorie enthalten ist."
|
||||
},
|
||||
"pininfo": {
|
||||
"Category": "Kategorie",
|
||||
"Name": "Name",
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
"SecuritySettings": "Security Settings",
|
||||
"DTUSettings": "DTU Settings",
|
||||
"DeviceManager": "Device-Manager",
|
||||
"Integrations": "Integrations",
|
||||
"ConfigManagement": "Config Management",
|
||||
"FirmwareUpgrade": "Firmware Upgrade",
|
||||
"DeviceReboot": "Device Reboot",
|
||||
@ -113,7 +114,9 @@
|
||||
"10002": "Authentication successful!",
|
||||
"11001": "@:apiresponse.2001",
|
||||
"11002": "@:apiresponse:5004",
|
||||
"12001": "Profil must between 1 and {max} characters long!"
|
||||
"12001": "Profil must between 1 and {max} characters long!",
|
||||
"13001": "Hostname must between 1 and {max} characters long!",
|
||||
"13002": "Update interval must between {min} and {max} seconds!"
|
||||
},
|
||||
"home": {
|
||||
"LiveData": "Live Data",
|
||||
@ -668,6 +671,18 @@
|
||||
"EqualBrightness": "Equal brightness",
|
||||
"LedBrightness": "LED {led} brightness ({brightness})"
|
||||
},
|
||||
"integrationsadmin": {
|
||||
"IntegrationSettings": "Integration Settings",
|
||||
"Save": "@:base.Save",
|
||||
"Cancel": "@:base.Cancel",
|
||||
"goecontroller": "go-e Controller",
|
||||
"goecontrollerEnabled": "Enable go-e Controller",
|
||||
"goecontrollerEnabledHint": "Enable the go-e controller integration. This will set the 'ecp' api-key to let the controller know how much solar energy is produced",
|
||||
"goecontrollerHostname": "Hostname",
|
||||
"goecontrollerUpdateInterval": "Update Interval",
|
||||
"goecontrollerEnableHomeCategory": "Enable Home Category",
|
||||
"goecontrollerEnableHomeCategoryHint": "Also set the value for the home category. This way you can have the correct consumption of your home if your inverter is also included in the home category."
|
||||
},
|
||||
"pininfo": {
|
||||
"Category": "Category",
|
||||
"Name": "Name",
|
||||
|
||||
@ -113,7 +113,9 @@
|
||||
"10002": "Authentification réussie !",
|
||||
"11001": "@:apiresponse.2001",
|
||||
"11002": "@:apiresponse:5004",
|
||||
"12001": "Le profil doit comporter entre 1 et {max} caractères !"
|
||||
"12001": "Le profil doit comporter entre 1 et {max} caractères !",
|
||||
"13001": "Hostname must between 1 and {max} characters long!",
|
||||
"13002": "Update interval must between {min} and {max} seconds!"
|
||||
},
|
||||
"home": {
|
||||
"LiveData": "Données en direct",
|
||||
@ -650,6 +652,18 @@
|
||||
"EqualBrightness": "Même luminosité",
|
||||
"LedBrightness": "LED {led} luminosité ({brightness})"
|
||||
},
|
||||
"integrationsadmin": {
|
||||
"IntegrationSettings": "Integration Settings",
|
||||
"Save": "@:base.Save",
|
||||
"Cancel": "@:base.Cancel",
|
||||
"goecontroller": "go-e Controller",
|
||||
"goecontrollerEnabled": "Enable go-e Controller",
|
||||
"goecontrollerEnabledHint": "Enable the go-e controller integration. This will set the 'ecp' api-key to let the controller know how much solar energy is produced",
|
||||
"goecontrollerHostname": "Hostname",
|
||||
"goecontrollerUpdateInterval": "Update Interval",
|
||||
"goecontrollerEnableHomeCategory": "Enable Home Category",
|
||||
"goecontrollerEnableHomeCategoryHint": "Also set the value for the home category. This way you can have the correct consumption of your home if your inverter is also included in the home category."
|
||||
},
|
||||
"pininfo": {
|
||||
"Category": "Catégorie",
|
||||
"Name": "Nom",
|
||||
|
||||
@ -18,6 +18,7 @@ import NtpInfoView from '@/views/NtpInfoView.vue';
|
||||
import SecurityAdminView from '@/views/SecurityAdminView.vue';
|
||||
import SystemInfoView from '@/views/SystemInfoView.vue';
|
||||
import WaitRestartView from '@/views/WaitRestartView.vue';
|
||||
import IntegrationsAdminView from '@/views/IntegrationsAdminView.vue';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
|
||||
const router = createRouter({
|
||||
@ -106,6 +107,11 @@ const router = createRouter({
|
||||
name: 'Device Manager',
|
||||
component: DeviceAdminView,
|
||||
},
|
||||
{
|
||||
path: '/settings/integrations',
|
||||
name: 'Integrations',
|
||||
component: IntegrationsAdminView,
|
||||
},
|
||||
{
|
||||
path: '/firmware/upgrade',
|
||||
name: 'Firmware Upgrade',
|
||||
|
||||
6
webapp/src/types/IntegrationsConfig.ts
Normal file
6
webapp/src/types/IntegrationsConfig.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface IntegrationsConfig {
|
||||
goe_ctrl_enabled: boolean;
|
||||
goe_ctrl_hostname: string;
|
||||
goe_ctrl_publish_home_category: boolean;
|
||||
goe_ctrl_update_interval: number;
|
||||
}
|
||||
109
webapp/src/views/IntegrationsAdminView.vue
Normal file
109
webapp/src/views/IntegrationsAdminView.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<BasePage :title="$t('integrationsadmin.IntegrationSettings')" :isLoading="dataLoading">
|
||||
<BootstrapAlert v-model="showAlert" dismissible :variant="alertType">
|
||||
{{ alertMessage }}
|
||||
</BootstrapAlert>
|
||||
|
||||
<form @submit="saveIntegrationsConfig">
|
||||
<CardElement :text="$t('integrationsadmin.goecontroller')" textVariant="text-bg-primary">
|
||||
<InputElement
|
||||
:label="$t('integrationsadmin.goecontrollerEnabled')"
|
||||
v-model="integrationsConfig.goe_ctrl_enabled"
|
||||
type="checkbox"
|
||||
wide
|
||||
:tooltip="$t('integrationsadmin.goecontrollerEnabledHint')"
|
||||
/>
|
||||
|
||||
<InputElement
|
||||
v-show="integrationsConfig.goe_ctrl_enabled"
|
||||
:label="$t('integrationsadmin.goecontrollerEnableHomeCategory')"
|
||||
v-model="integrationsConfig.goe_ctrl_publish_home_category"
|
||||
type="checkbox"
|
||||
wide
|
||||
:tooltip="$t('integrationsadmin.goecontrollerEnableHomeCategoryHint')"
|
||||
/>
|
||||
|
||||
<InputElement
|
||||
v-show="integrationsConfig.goe_ctrl_enabled"
|
||||
:label="$t('integrationsadmin.goecontrollerHostname')"
|
||||
v-model="integrationsConfig.goe_ctrl_hostname"
|
||||
type="text"
|
||||
placeholder="go-econtroller_XXXXXX"
|
||||
/>
|
||||
|
||||
<InputElement
|
||||
v-show="integrationsConfig.goe_ctrl_enabled"
|
||||
:label="$t('integrationsadmin.goecontrollerUpdateInterval')"
|
||||
v-model="integrationsConfig.goe_ctrl_update_interval"
|
||||
type="number"
|
||||
min="3"
|
||||
max="65535"
|
||||
:postfix="$t('mqttadmin.Seconds')"
|
||||
/>
|
||||
</CardElement>
|
||||
<FormFooter @reload="getIntegrationsConfig" />
|
||||
</form>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import BasePage from '@/components/BasePage.vue';
|
||||
import BootstrapAlert from '@/components/BootstrapAlert.vue';
|
||||
import CardElement from '@/components/CardElement.vue';
|
||||
import FormFooter from '@/components/FormFooter.vue';
|
||||
import InputElement from '@/components/InputElement.vue';
|
||||
import { authHeader, handleResponse } from '@/utils/authentication';
|
||||
import { defineComponent } from 'vue';
|
||||
import type { IntegrationsConfig } from '@/types/IntegrationsConfig';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
BasePage,
|
||||
BootstrapAlert,
|
||||
CardElement,
|
||||
FormFooter,
|
||||
InputElement,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataLoading: true,
|
||||
integrationsConfig: {} as IntegrationsConfig,
|
||||
alertMessage: '',
|
||||
alertType: 'info',
|
||||
showAlert: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getIntegrationsConfig();
|
||||
},
|
||||
methods: {
|
||||
getIntegrationsConfig() {
|
||||
this.dataLoading = true;
|
||||
fetch('/api/integrations/config', { headers: authHeader() })
|
||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||
.then((data) => {
|
||||
this.integrationsConfig = data;
|
||||
this.dataLoading = false;
|
||||
});
|
||||
},
|
||||
saveIntegrationsConfig(e: Event) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('data', JSON.stringify(this.integrationsConfig));
|
||||
|
||||
fetch('/api/integrations/config', {
|
||||
method: 'POST',
|
||||
headers: authHeader(),
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||
.then((response) => {
|
||||
this.alertMessage = this.$t('apiresponse.' + response.code, response.param);
|
||||
this.alertType = response.type;
|
||||
this.showAlert = true;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -80,7 +80,7 @@
|
||||
v-model="mqttConfigList.mqtt_publish_interval"
|
||||
type="number"
|
||||
min="5"
|
||||
max="86400"
|
||||
max="65535"
|
||||
:postfix="$t('mqttadmin.Seconds')"
|
||||
/>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user