diff --git a/include/Configuration.h b/include/Configuration.h index 39c46c39..9b464545 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -106,6 +106,8 @@ struct CONFIG_T { char PowerLimiter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1]; char PowerLimiter_MqttTopicPowerMeter3[MQTT_MAX_TOPIC_STRLEN + 1]; bool PowerLimiter_IsInverterBehindPowerMeter; + uint8_t PowerLimiter_InverterId; + uint8_t PowerLimiter_InverterChannelId; uint32_t PowerLimiter_LowerPowerLimit; uint32_t PowerLimiter_UpperPowerLimit; uint32_t PowerLimiter_BatterySocStartThreshold; diff --git a/include/defaults.h b/include/defaults.h index 2784a8d9..14c6d545 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -96,6 +96,8 @@ #define POWERLIMITER_SOLAR_PASSTROUGH_ENABLED true #define POWERLIMITER_INTERVAL 10 #define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true +#define POWERLIMITER_INVERTER_ID 0 +#define POWERLIMITER_INVERTER_CHANNEL_ID 0 #define POWERLIMITER_LOWER_POWER_LIMIT 10 #define POWERLIMITER_UPPER_POWER_LIMIT 800 #define POWERLIMITER_BATTERY_SOC_START_THRESHOLD 80 diff --git a/src/Configuration.cpp b/src/Configuration.cpp index f61723e9..a1d978a4 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -123,6 +123,8 @@ bool ConfigurationClass::write() powerlimiter["mqtt_topic_powermeter_2"] = config.PowerLimiter_MqttTopicPowerMeter2; powerlimiter["mqtt_topic_powermeter_3"] = config.PowerLimiter_MqttTopicPowerMeter3; powerlimiter["is_inverter_behind_powermeter"] = config.PowerLimiter_IsInverterBehindPowerMeter; + powerlimiter["inverter_id"] = config.PowerLimiter_InverterId; + powerlimiter["inverter_channel_id"] = config.PowerLimiter_InverterChannelId; powerlimiter["lower_power_limit"] = config.PowerLimiter_LowerPowerLimit; powerlimiter["upper_power_limit"] = config.PowerLimiter_UpperPowerLimit; powerlimiter["battery_soc_start_threshold"] = config.PowerLimiter_BatterySocStartThreshold; @@ -284,6 +286,8 @@ bool ConfigurationClass::read() strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, powerlimiter["mqtt_topic_powermeter_2"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter2)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, powerlimiter["mqtt_topic_powermeter_3"] | "", sizeof(config.PowerLimiter_MqttTopicPowerMeter3)); config.PowerLimiter_IsInverterBehindPowerMeter = powerlimiter["is_inverter_behind_powermeter"] | POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER; + config.PowerLimiter_InverterId = powerlimiter["inverter_id"] | POWERLIMITER_INVERTER_ID; + config.PowerLimiter_InverterChannelId = powerlimiter["inverter_channel_id"] | POWERLIMITER_INVERTER_CHANNEL_ID; config.PowerLimiter_LowerPowerLimit = powerlimiter["lower_power_limit"] | POWERLIMITER_LOWER_POWER_LIMIT; config.PowerLimiter_UpperPowerLimit = powerlimiter["upper_power_limit"] | POWERLIMITER_UPPER_POWER_LIMIT; config.PowerLimiter_BatterySocStartThreshold = powerlimiter["battery_soc_start_threshold"] | POWERLIMITER_BATTERY_SOC_START_THRESHOLD; diff --git a/src/PowerLimiter.cpp b/src/PowerLimiter.cpp index 826b070b..bbc3532c 100644 --- a/src/PowerLimiter.cpp +++ b/src/PowerLimiter.cpp @@ -78,13 +78,13 @@ void PowerLimiterClass::loop() _lastLoop = millis(); - std::shared_ptr inverter = Hoymiles.getInverterByPos(1); // TODO(helgeerbe) make Inverter selectable + std::shared_ptr inverter = Hoymiles.getInverterByPos(config.PowerLimiter_InverterId); if (inverter == nullptr || !inverter->isReachable()) { return; } - float dcVoltage = inverter->Statistics()->getChannelFieldValue(TYPE_DC, CH0, FLD_UDC); // TODO(helgeerbe) make channel selectable + float dcVoltage = inverter->Statistics()->getChannelFieldValue(TYPE_DC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_UDC); if ((millis() - inverter->Statistics()->getLastUpdate()) > 10000) { return; diff --git a/src/WebApi_powerlimiter.cpp b/src/WebApi_powerlimiter.cpp index 6a463c22..09f3b227 100644 --- a/src/WebApi_powerlimiter.cpp +++ b/src/WebApi_powerlimiter.cpp @@ -40,6 +40,8 @@ void WebApiPowerLimiterClass::onStatus(AsyncWebServerRequest* request) root[F("mqtt_topic_powermeter_2")] = config.PowerLimiter_MqttTopicPowerMeter2; root[F("mqtt_topic_powermeter_3")] = config.PowerLimiter_MqttTopicPowerMeter3; root[F("is_inverter_behind_powermeter")] = config.PowerLimiter_IsInverterBehindPowerMeter; + root[F("inverter_id")] = config.PowerLimiter_InverterId; + root[F("inverter_channel_id")] = config.PowerLimiter_InverterChannelId; root[F("lower_power_limit")] = config.PowerLimiter_LowerPowerLimit; root[F("upper_power_limit")] = config.PowerLimiter_UpperPowerLimit; root[F("battery_soc_start_threshold")] = config.PowerLimiter_BatterySocStartThreshold; @@ -97,7 +99,10 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request) return; } - if (!(root.containsKey("enabled") && root.containsKey("lower_power_limit"))) { + if (!(root.containsKey("enabled") + && root.containsKey("lower_power_limit") + && root.containsKey("inverter_id") + && root.containsKey("inverter_channel_id"))) { retMsg[F("message")] = F("Values are missing!"); response->setLength(); request->send(response); @@ -111,6 +116,8 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request) strlcpy(config.PowerLimiter_MqttTopicPowerMeter2, root[F("mqtt_topic_powermeter_2")].as().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter2)); strlcpy(config.PowerLimiter_MqttTopicPowerMeter3, root[F("mqtt_topic_powermeter_3")].as().c_str(), sizeof(config.PowerLimiter_MqttTopicPowerMeter3)); config.PowerLimiter_IsInverterBehindPowerMeter = root[F("is_inverter_behind_powermeter")].as(); + config.PowerLimiter_InverterId = root[F("inverter_id")].as(); + config.PowerLimiter_InverterChannelId = root[F("inverter_channel_id")].as(); config.PowerLimiter_LowerPowerLimit = root[F("lower_power_limit")].as(); config.PowerLimiter_UpperPowerLimit = root[F("upper_power_limit")].as(); config.PowerLimiter_BatterySocStartThreshold = root[F("battery_soc_start_threshold")].as(); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 7851b2f8..3ec4f19f 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -443,6 +443,12 @@ "UpdatesOnly": "Nur Änderungen senden:", "Save": "@:dtuadmin.Save" }, + "powerlimiteradmin": { + "InverterId": "Wechselrichter ID", + "InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.", + "InverterChannelId": "Kanal ID", + "InverterChannelIdHint": "Wähle den Kanal an dem die Batterie hängt." + }, "batteryadmin": { "BatterySettings": "Batterie Einstellungen", "BatteryConfiguration": "Batterie Konfiguration", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index e1b06eb7..695eeb2c 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -450,6 +450,10 @@ "Enable": "Enable", "EnableSolarPasstrough": "Enable Solar Passtrough", "SolarpasstroughInfo": "When the sun is shining, this setting enables the sychronization of the inverter limit with the current solar power of the Victron MPPT charger. This optimizes battery degradation and loses.", + "InverterId": "Inverter ID", + "InverterIdHint": "Select proper inverter ID where battery is connected to.", + "InverterChannelId": "Channel ID", + "InverterChannelIdHint": "Select proper channel where battery is connected to.", "LowerPowerLimit": "Lower power limit / continuous feed", "UpperPowerLimit": "Upper power limit", "PowerMeters": "Power meters - MQTT", diff --git a/webapp/src/types/PowerLimiterConfig.ts b/webapp/src/types/PowerLimiterConfig.ts index f199a540..7b4e6281 100644 --- a/webapp/src/types/PowerLimiterConfig.ts +++ b/webapp/src/types/PowerLimiterConfig.ts @@ -5,6 +5,8 @@ export interface PowerLimiterConfig { mqtt_topic_powermeter_2: string; mqtt_topic_powermeter_3: string; is_inverter_behind_powermeter: boolean; + inverterId: number; + inverterChannelId: number; lower_power_limit: number; upper_power_limit: number; battery_soc_start_threshold: number; diff --git a/webapp/src/views/PowerLimiterAdminView.vue b/webapp/src/views/PowerLimiterAdminView.vue index b749b2aa..58c760cc 100644 --- a/webapp/src/views/PowerLimiterAdminView.vue +++ b/webapp/src/views/PowerLimiterAdminView.vue @@ -5,172 +5,182 @@
-
-
{{ $t('powerlimiteradmin.General') }}
-
- -
- -
-
- -
-
-
- -
- -
-
- -
-
-
- - - -
- -
-
- - W -
-
-
- -
- -
-
- - W -
-
-
-
-
- -
-
{{ $t('powerlimiteradmin.PowerMeters') }}
-
-
- -
-
- -
-
-
+ + -
- -
-
- -
-
-
+ -
- -
-
- -
-
-
+ -
- -
-
- -
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ + W
-
-
-
{{ $t('powerlimiteradmin.Battery') }}
-
- -
- -
-
- - % -
+
+ +
+
+ + W
- -
- -
-
- - % -
-
-
- - - -
- -
-
- - V -
-
-
- -
- -
-
- - V -
-
-
- -
- -
-
- - V -
-
-
- -
-
+ + + +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+
+ + +
+ +
+
+ + % +
+
+
+ +
+ +
+
+ + % +
+
+
+ + + +
+ +
+
+ + V +
+
+
+ +
+ +
+
+ + V +
+
+
+ +
+ +
+
+ + V +
+
+
+ + +
@@ -182,17 +192,42 @@ import { defineComponent } from 'vue'; import BasePage from '@/components/BasePage.vue'; import BootstrapAlert from "@/components/BootstrapAlert.vue"; import { handleResponse, authHeader } from '@/utils/authentication'; +import CardElement from '@/components/CardElement.vue'; +import InputElement from '@/components/InputElement.vue'; +import { BIconInfoCircle } from 'bootstrap-icons-vue'; import type { PowerLimiterConfig } from "@/types/PowerLimiterConfig"; export default defineComponent({ components: { BasePage, BootstrapAlert, + CardElement, + InputElement, + BIconInfoCircle, }, data() { return { dataLoading: true, powerLimiterConfigList: {} as PowerLimiterConfig, + inverterList: [ + { key: 0, value: "ID 00" }, + { key: 1, value: "ID 01" }, + { key: 2, value: "ID 02" }, + { key: 3, value: "ID 03" }, + { key: 4, value: "ID 04" }, + { key: 5, value: "ID 05" }, + { key: 6, value: "ID 06" }, + { key: 7, value: "ID 07" }, + { key: 8, value: "ID 08" }, + { key: 9, value: "ID 09" }, + { key: 10, value: "ID 10" }, + ], + inverterChannelList: [ + { key: 0, value: "CH 0" }, + { key: 1, value: "CH 1" }, + { key: 2, value: "CH 2" }, + { key: 3, value: "CH 3" }, + ], alertMessage: "", alertType: "info", showAlert: false, diff --git a/webapp_dist/index.html.gz b/webapp_dist/index.html.gz index 0830730b..f7547917 100644 Binary files a/webapp_dist/index.html.gz and b/webapp_dist/index.html.gz differ diff --git a/webapp_dist/js/app.js.gz b/webapp_dist/js/app.js.gz index f8ee050f..2133bc21 100644 Binary files a/webapp_dist/js/app.js.gz and b/webapp_dist/js/app.js.gz differ diff --git a/webapp_dist/zones.json.gz b/webapp_dist/zones.json.gz index f1ea50bf..45374b96 100644 Binary files a/webapp_dist/zones.json.gz and b/webapp_dist/zones.json.gz differ