Merge branch 'sinexcel_multiinveters_configurtaion' into main
Introduce per-cluster Configuration page (V2) for installations 790, 839
(Growatt + Sinexcel pilot). All other installations continue using the
original SodistoreHomeConfiguration unchanged via an installation-id gate.
V2 highlights:
- Per-inverter / per-cluster Battery Limits (foldable accordions)
- Default current = slotCount * 95A from preset
- Dynamic Pricing block under LoadPriority (Off / Spot Price / TOU)
- Wire format: Devices.InverterN.Clusters.ClusterN.{BatteryCount, MaxCharging/DischargingCurrent}, PvCount
Backend Configuration DTO keeps legacy flat fields for V1 backward compat;
audit log + UDP send both use JsonIgnoreCondition.WhenWritingNull.
Pilot validation on installation 790 + 839 before V2 becomes the default.
This commit is contained in:
commit
b9745a1712
|
|
@ -1900,14 +1900,21 @@ public class Controller : ControllerBase
|
||||||
{
|
{
|
||||||
var session = Db.GetSession(authToken);
|
var session = Db.GetSession(authToken);
|
||||||
|
|
||||||
string configString = product switch
|
// Dynamic Pricing in Spot Price mode: forward the provider chosen on the Information tab
|
||||||
|
// so the device knows which operator's API to query for spot prices.
|
||||||
|
if (config.DynamicPricingMode == "SpotPrice")
|
||||||
{
|
{
|
||||||
0 => config.GetConfigurationSalimax(), // Salimax
|
var installation = Db.GetInstallationById(installationId);
|
||||||
3 => config.GetConfigurationSodistoreMax(), // SodiStoreMax
|
config.NetworkProvider = installation?.NetworkProvider;
|
||||||
2 => config.GetConfigurationSodistoreHome(), // SodiStoreHome
|
}
|
||||||
4 => config.GetConfigurationSodistoreGrid(), // SodistoreGrid
|
|
||||||
_ => config.GetConfigurationString() // fallback
|
// Serialize what was actually sent — drops null/unset fields so the audit
|
||||||
};
|
// entry is product-shaped automatically (no per-product formatter to maintain).
|
||||||
|
var configString = System.Text.Json.JsonSerializer.Serialize(config, new System.Text.Json.JsonSerializerOptions
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
WriteIndented = false,
|
||||||
|
});
|
||||||
|
|
||||||
Console.WriteLine("CONFIG IS " + configString);
|
Console.WriteLine("CONFIG IS " + configString);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,56 +9,55 @@ public class Configuration
|
||||||
public CalibrationChargeType? CalibrationDischargeState { get; set; }
|
public CalibrationChargeType? CalibrationDischargeState { get; set; }
|
||||||
public DateTime? CalibrationDischargeDate { get; set; }
|
public DateTime? CalibrationDischargeDate { get; set; }
|
||||||
|
|
||||||
|
// V1 (legacy) flat fields — still used by the original SodistoreHomeConfiguration page
|
||||||
|
// for installations not opted in to V2. WhenWritingNull keeps them out of V2 payloads.
|
||||||
public double? MaximumDischargingCurrent { get; set; }
|
public double? MaximumDischargingCurrent { get; set; }
|
||||||
public double? MaximumChargingCurrent { get; set; }
|
public double? MaximumChargingCurrent { get; set; }
|
||||||
public double? OperatingPriority { get; set; }
|
public int? InverterNumber { get; set; }
|
||||||
public double? BatteriesCount { get; set; }
|
public double? BatteriesCount { get; set; }
|
||||||
|
public List<int>? BatteriesCountPerInverter { get; set; }
|
||||||
public double? ClusterNumber { get; set; }
|
public double? ClusterNumber { get; set; }
|
||||||
public double? PvNumber { get; set; }
|
public double? PvNumber { get; set; }
|
||||||
|
// V2 — per-inverter Clusters + PvCount, keyed by "Inverter1".."InverterN".
|
||||||
|
// Wire format mirrors the on-disk shape — device merges these into its existing Devices.InverterN entries.
|
||||||
|
// Per-cluster MaxChargingCurrent / MaxDischargingCurrent live inside Devices[InverterN].Clusters[ClusterN].
|
||||||
|
public Dictionary<string, DeviceConfigPartial>? Devices { get; set; }
|
||||||
|
public double? OperatingPriority { get; set; }
|
||||||
public bool ControlPermission { get; set; }
|
public bool ControlPermission { get; set; }
|
||||||
public double? TimeChargeandDischargePower { get; set; }
|
public double? TimeChargeandDischargePower { get; set; }
|
||||||
public DateTime? StartTimeChargeandDischargeDayandTime { get; set; }
|
public DateTime? StartTimeChargeandDischargeDayandTime { get; set; }
|
||||||
public DateTime? StopTimeChargeandDischargeDayandTime { get; set; }
|
public DateTime? StopTimeChargeandDischargeDayandTime { get; set; }
|
||||||
|
|
||||||
public String GetConfigurationString()
|
// Sinexcel Dynamic Pricing (under GridPriority) — strings for demo; engine will parse later.
|
||||||
{
|
public string? DynamicPricingMode { get; set; }
|
||||||
return $"MinimumSoC: {MinimumSoC}, GridSetPoint: {GridSetPoint}, CalibrationChargeState: {CalibrationChargeState}, CalibrationChargeDate: {CalibrationChargeDate}, " +
|
public string? NetworkProvider { get; set; }
|
||||||
$"CalibrationDischargeState: {CalibrationDischargeState}, CalibrationDischargeDate: {CalibrationDischargeDate}, " +
|
public string? CurrentPrice { get; set; }
|
||||||
$"MaximumDischargingCurrent: {MaximumDischargingCurrent}, MaximumChargingCurrent: {MaximumChargingCurrent}, OperatingPriority: {OperatingPriority}, " +
|
public string? PriceToSell { get; set; }
|
||||||
$"BatteriesCount: {BatteriesCount}, ClusterNumber: {ClusterNumber}, PvNumber: {PvNumber}, ControlPermission:{ControlPermission}, "+
|
public string? PriceToBuy { get; set; }
|
||||||
$"SinexcelTimeChargeandDischargePower: {TimeChargeandDischargePower}, SinexcelStartTimeChargeandDischargeDayandTime: {StartTimeChargeandDischargeDayandTime}, SinexcelStopTimeChargeandDischargeDayandTime: {StopTimeChargeandDischargeDayandTime}";
|
// TOU windows stored as "HH:mm" strings
|
||||||
|
public string? TimeToSellFrom { get; set; }
|
||||||
|
public string? TimeToSellTo { get; set; }
|
||||||
|
public string? TimeToBuyFrom { get; set; }
|
||||||
|
public string? TimeToBuyTo { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetConfigurationSalimax()
|
|
||||||
{
|
|
||||||
return
|
|
||||||
$"MinimumSoC: {MinimumSoC}, GridSetPoint: {GridSetPoint}, CalibrationChargeState: {CalibrationChargeState}, CalibrationChargeDate: {CalibrationChargeDate}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetConfigurationSodistoreMax()
|
|
||||||
{
|
|
||||||
return
|
|
||||||
$"MinimumSoC: {MinimumSoC}, GridSetPoint: {GridSetPoint}, CalibrationChargeState: {CalibrationChargeState}, CalibrationChargeDate: {CalibrationChargeDate}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetConfigurationSodistoreHome()
|
|
||||||
{
|
|
||||||
return $"MinimumSoC: {MinimumSoC}, MaximumDischargingCurrent: {MaximumDischargingCurrent}, MaximumChargingCurrent: {MaximumChargingCurrent}, OperatingPriority: {OperatingPriority}, " +
|
|
||||||
$"BatteriesCount: {BatteriesCount}, ClusterNumber: {ClusterNumber}, PvNumber: {PvNumber}, ControlPermission:{ControlPermission}, "+
|
|
||||||
$"SinexcelTimeChargeandDischargePower: {TimeChargeandDischargePower}, SinexcelStartTimeChargeandDischargeDayandTime: {StartTimeChargeandDischargeDayandTime}, SinexcelStopTimeChargeandDischargeDayandTime: {StopTimeChargeandDischargeDayandTime}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: SodistoreGrid — update configuration fields when defined
|
|
||||||
public string GetConfigurationSodistoreGrid()
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CalibrationChargeType
|
public enum CalibrationChargeType
|
||||||
{
|
{
|
||||||
RepetitivelyEvery,
|
RepetitivelyEvery,
|
||||||
AdditionallyOnce,
|
AdditionallyOnce,
|
||||||
ChargePermanently
|
ChargePermanently
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DeviceConfigPartial
|
||||||
|
{
|
||||||
|
public Dictionary<string, ClusterConfig>? Clusters { get; set; }
|
||||||
|
public int? PvCount { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClusterConfig
|
||||||
|
{
|
||||||
|
public int BatteryCount { get; set; }
|
||||||
|
public double MaxChargingCurrent { get; set; }
|
||||||
|
public double MaxDischargingCurrent { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -448,12 +448,16 @@ public static class ExoCmd
|
||||||
for (int j = 0; j < maxRetransmissions; j++)
|
for (int j = 0; j < maxRetransmissions; j++)
|
||||||
{
|
{
|
||||||
//string message = "This is a message from RabbitMQ server, you can subscribe to the RabbitMQ queue";
|
//string message = "This is a message from RabbitMQ server, you can subscribe to the RabbitMQ queue";
|
||||||
byte[] data = Encoding.UTF8.GetBytes(JsonSerializer.Serialize<Configuration>(config));
|
// Drop null fields so the device only sees what's actually set for this product.
|
||||||
|
var jsonOptions = new System.Text.Json.JsonSerializerOptions
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
var payload = JsonSerializer.Serialize<Configuration>(config, jsonOptions);
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(payload);
|
||||||
udpClient.Send(data, data.Length, installation.VpnIp, port);
|
udpClient.Send(data, data.Length, installation.VpnIp, port);
|
||||||
|
|
||||||
Console.WriteLine(config.GetConfigurationString());
|
Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}: {payload}");
|
||||||
|
|
||||||
Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}: {config}");
|
|
||||||
//Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}"+" GridSetPoint is "+config.GridSetPoint +" and MinimumSoC is "+config.MinimumSoC);
|
//Console.WriteLine($"Sent UDP message to {installation.VpnIp}:{port}"+" GridSetPoint is "+config.GridSetPoint +" and MinimumSoC is "+config.MinimumSoC);
|
||||||
|
|
||||||
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(installation.VpnIp), port);
|
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(installation.VpnIp), port);
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,16 @@ public class Configuration
|
||||||
public Single TimeChargeandDischargePower { get; set; }
|
public Single TimeChargeandDischargePower { get; set; }
|
||||||
public Boolean ControlPermission { get; set; }
|
public Boolean ControlPermission { get; set; }
|
||||||
|
|
||||||
|
// Dynamic Pricing (under GridPriority) — strings for demo; engine parses when needed.
|
||||||
|
public String? DynamicPricingMode { get; set; }
|
||||||
|
public String? NetworkProvider { get; set; }
|
||||||
|
public String? CurrentPrice { get; set; }
|
||||||
|
public String? PriceToSell { get; set; }
|
||||||
|
public String? PriceToBuy { get; set; }
|
||||||
|
public String? TimeToSellFrom { get; set; }
|
||||||
|
public String? TimeToSellTo { get; set; }
|
||||||
|
public String? TimeToBuyFrom { get; set; }
|
||||||
|
public String? TimeToBuyTo { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -639,6 +639,15 @@ internal static class Program
|
||||||
status.Config.PvNumber = config.PvNumber;
|
status.Config.PvNumber = config.PvNumber;
|
||||||
status.Config.ControlPermission = config.ControlPermission;
|
status.Config.ControlPermission = config.ControlPermission;
|
||||||
|
|
||||||
|
status.Config.DynamicPricingMode = config.DynamicPricingMode;
|
||||||
|
status.Config.NetworkProvider = config.NetworkProvider;
|
||||||
|
status.Config.CurrentPrice = config.CurrentPrice;
|
||||||
|
status.Config.PriceToSell = config.PriceToSell;
|
||||||
|
status.Config.PriceToBuy = config.PriceToBuy;
|
||||||
|
status.Config.TimeToSellFrom = config.TimeToSellFrom;
|
||||||
|
status.Config.TimeToSellTo = config.TimeToSellTo;
|
||||||
|
status.Config.TimeToBuyFrom = config.TimeToBuyFrom;
|
||||||
|
status.Config.TimeToBuyTo = config.TimeToBuyTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Boolean> SaveModbusTcpFile(StatusRecord status)
|
private static async Task<Boolean> SaveModbusTcpFile(StatusRecord status)
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,17 @@ public class Config
|
||||||
public required Single TimeChargeandDischargePower { get; set; }
|
public required Single TimeChargeandDischargePower { get; set; }
|
||||||
public required Boolean ControlPermission { get; set; }
|
public required Boolean ControlPermission { get; set; }
|
||||||
|
|
||||||
|
// Dynamic Pricing (under GridPriority) — strings for demo; engine parses when needed.
|
||||||
|
public String? DynamicPricingMode { get; set; }
|
||||||
|
public String? NetworkProvider { get; set; }
|
||||||
|
public String? CurrentPrice { get; set; }
|
||||||
|
public String? PriceToSell { get; set; }
|
||||||
|
public String? PriceToBuy { get; set; }
|
||||||
|
public String? TimeToSellFrom { get; set; }
|
||||||
|
public String? TimeToSellTo { get; set; }
|
||||||
|
public String? TimeToBuyFrom { get; set; }
|
||||||
|
public String? TimeToBuyTo { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public required S3Config? S3 { get; set; }
|
public required S3Config? S3 { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,8 @@ export interface JSONRecordData {
|
||||||
MaximumDischargingCurrent: number;
|
MaximumDischargingCurrent: number;
|
||||||
OperatingPriority: string;
|
OperatingPriority: string;
|
||||||
BatteriesCount: number;
|
BatteriesCount: number;
|
||||||
|
InverterNumber?: number;
|
||||||
|
BatteriesCountPerInverter?: number[];
|
||||||
ClusterNumber: number;
|
ClusterNumber: number;
|
||||||
PvNumber: number;
|
PvNumber: number;
|
||||||
ControlPermission:boolean;
|
ControlPermission:boolean;
|
||||||
|
|
@ -683,6 +685,17 @@ export interface I_BoxDataValue {
|
||||||
value: string | number;
|
value: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ClusterConfig = {
|
||||||
|
BatteryCount: number;
|
||||||
|
MaxChargingCurrent: number;
|
||||||
|
MaxDischargingCurrent: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InverterConfig = {
|
||||||
|
Clusters: { [clusterKey: string]: ClusterConfig };
|
||||||
|
PvCount: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type ConfigurationValues = {
|
export type ConfigurationValues = {
|
||||||
minimumSoC: string | number;
|
minimumSoC: string | number;
|
||||||
gridSetPoint: number;
|
gridSetPoint: number;
|
||||||
|
|
@ -694,16 +707,33 @@ export type ConfigurationValues = {
|
||||||
//For sodistoreHome
|
//For sodistoreHome
|
||||||
maximumDischargingCurrent: number;
|
maximumDischargingCurrent: number;
|
||||||
maximumChargingCurrent: number;
|
maximumChargingCurrent: number;
|
||||||
|
// Per-inverter Clusters + PvCount, keyed by "Inverter1".."InverterN".
|
||||||
|
// Wire format mirrors the on-disk Devices.InverterN shape — device merges by key.
|
||||||
|
devices?: { [inverterKey: string]: InverterConfig };
|
||||||
operatingPriority: number;
|
operatingPriority: number;
|
||||||
batteriesCount: number;
|
batteriesCount: number;
|
||||||
|
inverterNumber: number;
|
||||||
|
batteriesCountPerInverter: number[];
|
||||||
clusterNumber: number;
|
clusterNumber: number;
|
||||||
PvNumber: number;
|
PvNumber: number;
|
||||||
|
pvCountPerInverter: number[];
|
||||||
controlPermission:boolean;
|
controlPermission:boolean;
|
||||||
|
|
||||||
// For sodistoreHome-Sinexcel: TimeChargeDischarge mode
|
// For sodistoreHome-Sinexcel: TimeChargeDischarge mode
|
||||||
timeChargeandDischargePower?: number;
|
timeChargeandDischargePower?: number;
|
||||||
startTimeChargeandDischargeDayandTime?: Date | null;
|
startTimeChargeandDischargeDayandTime?: Date | null;
|
||||||
stopTimeChargeandDischargeDayandTime?: Date | null;
|
stopTimeChargeandDischargeDayandTime?: Date | null;
|
||||||
|
|
||||||
|
// For sodistoreHome-Sinexcel: Dynamic Pricing (under GridPriority)
|
||||||
|
dynamicPricingMode?: string;
|
||||||
|
currentPrice?: string;
|
||||||
|
priceToSell?: string;
|
||||||
|
priceToBuy?: string;
|
||||||
|
// TOU time windows stored as "HH:mm" strings
|
||||||
|
timeToSellFrom?: string;
|
||||||
|
timeToSellTo?: string;
|
||||||
|
timeToBuyFrom?: string;
|
||||||
|
timeToBuyTo?: string;
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
// export interface Pv {
|
// export interface Pv {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,11 @@ import { fetchDataJson } from '../Installations/fetchData';
|
||||||
import { FetchResult } from '../../../dataCache/dataCache';
|
import { FetchResult } from '../../../dataCache/dataCache';
|
||||||
import BatteryViewSodioHome from '../BatteryView/BatteryViewSodioHome';
|
import BatteryViewSodioHome from '../BatteryView/BatteryViewSodioHome';
|
||||||
import SodistoreHomeConfiguration from './SodistoreHomeConfiguration';
|
import SodistoreHomeConfiguration from './SodistoreHomeConfiguration';
|
||||||
|
import SodistoreHomeConfigurationV2 from './SodistoreHomeConfigurationV2';
|
||||||
|
|
||||||
|
// Pilot installations using the new per-cluster Configuration page (V2).
|
||||||
|
// All other installations keep using the original SodistoreHomeConfiguration (V1).
|
||||||
|
const CONFIG_V2_INSTALLATION_IDS = new Set<number>([790, 839]);
|
||||||
import TopologySodistoreHome from '../Topology/TopologySodistoreHome';
|
import TopologySodistoreHome from '../Topology/TopologySodistoreHome';
|
||||||
import Overview from '../Overview/overview';
|
import Overview from '../Overview/overview';
|
||||||
import WeeklyReport from './WeeklyReport';
|
import WeeklyReport from './WeeklyReport';
|
||||||
|
|
@ -599,11 +604,19 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
<Route
|
<Route
|
||||||
path={routes.configuration}
|
path={routes.configuration}
|
||||||
element={
|
element={
|
||||||
|
CONFIG_V2_INSTALLATION_IDS.has(props.current_installation.id) ? (
|
||||||
|
<SodistoreHomeConfigurationV2
|
||||||
|
values={values}
|
||||||
|
id={props.current_installation.id}
|
||||||
|
installation={props.current_installation}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<SodistoreHomeConfiguration
|
<SodistoreHomeConfiguration
|
||||||
values={values}
|
values={values}
|
||||||
id={props.current_installation.id}
|
id={props.current_installation.id}
|
||||||
installation={props.current_installation}
|
installation={props.current_installation}
|
||||||
></SodistoreHomeConfiguration>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -521,8 +521,36 @@
|
||||||
"minimumSocPercent": "Minimaler Ladezustand (%)",
|
"minimumSocPercent": "Minimaler Ladezustand (%)",
|
||||||
"powerW": "Leistung (W)",
|
"powerW": "Leistung (W)",
|
||||||
"enterPowerValue": "Positiven oder negativen Leistungswert eingeben",
|
"enterPowerValue": "Positiven oder negativen Leistungswert eingeben",
|
||||||
|
"inverterNumber": "Anzahl Wechselrichter",
|
||||||
|
"batteriesCountInInverter": "Batterieanzahl in Wechselrichter {number}",
|
||||||
|
"batteryNumberInClusterN": "Batterieanzahl in Cluster {n}",
|
||||||
|
"pvStringsNumberInInverterN": "Anzahl PV-Strings in Wechselrichter {n}",
|
||||||
|
"batteries": "Batterien",
|
||||||
|
"maximumChargingCurrentPerBattery": "Maximaler Ladestrom pro Batterie (A)",
|
||||||
|
"maximumChargingCurrentPerClusterLabel": "Maximaler Ladestrom pro Cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerClusterLabel": "Maximaler Entladestrom pro Cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerBattery": "Maximaler Entladestrom pro Batterie (A)",
|
||||||
|
"powerPerInverterKW": "Leistung pro Wechselrichter (kW)",
|
||||||
"startDateTime": "Startdatum und -zeit (Startzeit < Stoppzeit)",
|
"startDateTime": "Startdatum und -zeit (Startzeit < Stoppzeit)",
|
||||||
"stopDateTime": "Stoppdatum und -zeit (Startzeit < Stoppzeit)",
|
"stopDateTime": "Stoppdatum und -zeit (Startzeit < Stoppzeit)",
|
||||||
|
"installationSetup": "Installationseinrichtung",
|
||||||
|
"batteryLimits": "Batteriegrenzwerte",
|
||||||
|
"systemSettings": "Systemeinstellungen",
|
||||||
|
"pvPerInverter": "PV pro Wechselrichter",
|
||||||
|
"pvInInverter": "PV in Wechselrichter {number}",
|
||||||
|
"dynamicPricing": "Dynamische Preisgestaltung",
|
||||||
|
"dynamicPricingMode": "Modus der dynamischen Preisgestaltung",
|
||||||
|
"dynamicPricingOff": "Aus",
|
||||||
|
"dynamicPricingSpotPrice": "Spot-Preis",
|
||||||
|
"dynamicPricingTou": "TOU",
|
||||||
|
"currentPrice": "Aktueller Preis",
|
||||||
|
"priceToSell": "Verkaufspreis",
|
||||||
|
"priceToBuy": "Kaufpreis",
|
||||||
|
"timeToSell": "Verkaufszeit",
|
||||||
|
"timeToBuy": "Kaufzeit",
|
||||||
|
"timeFrom": "Von",
|
||||||
|
"timeTo": "Bis",
|
||||||
|
"networkProviderSetOnInformationTab": "Im Informations-Tab festlegen",
|
||||||
"tourLanguageTitle": "Sprache",
|
"tourLanguageTitle": "Sprache",
|
||||||
"tourLanguageContent": "Wählen Sie Ihre bevorzugte Sprache. Die Oberfläche unterstützt Englisch, Deutsch, Französisch und Italienisch.",
|
"tourLanguageContent": "Wählen Sie Ihre bevorzugte Sprache. Die Oberfläche unterstützt Englisch, Deutsch, Französisch und Italienisch.",
|
||||||
"tourExploreTitle": "Installation erkunden",
|
"tourExploreTitle": "Installation erkunden",
|
||||||
|
|
|
||||||
|
|
@ -269,8 +269,36 @@
|
||||||
"minimumSocPercent": "Minimum SoC (%)",
|
"minimumSocPercent": "Minimum SoC (%)",
|
||||||
"powerW": "Power (W)",
|
"powerW": "Power (W)",
|
||||||
"enterPowerValue": "Enter a positive or negative power value",
|
"enterPowerValue": "Enter a positive or negative power value",
|
||||||
|
"inverterNumber": "Inverter Number",
|
||||||
|
"batteriesCountInInverter": "Batteries Count in Inverter {number}",
|
||||||
|
"batteryNumberInClusterN": "Battery Number in Cluster {n}",
|
||||||
|
"pvStringsNumberInInverterN": "PV Strings Number in Inverter {n}",
|
||||||
|
"batteries": "batteries",
|
||||||
|
"maximumChargingCurrentPerBattery": "Maximum Charging Current per Battery (A)",
|
||||||
|
"maximumDischargingCurrentPerBattery": "Maximum Discharging Current per Battery (A)",
|
||||||
|
"maximumChargingCurrentPerClusterLabel": "Maximum Charging Current per Cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerClusterLabel": "Maximum Discharging Current per Cluster (A)",
|
||||||
|
"powerPerInverterKW": "Power per Inverter (kW)",
|
||||||
"startDateTime": "Start Date and Time (Start Time < Stop Time)",
|
"startDateTime": "Start Date and Time (Start Time < Stop Time)",
|
||||||
"stopDateTime": "Stop Date and Time (Start Time < Stop Time)",
|
"stopDateTime": "Stop Date and Time (Start Time < Stop Time)",
|
||||||
|
"installationSetup": "Installation Setup",
|
||||||
|
"batteryLimits": "Battery Limits",
|
||||||
|
"systemSettings": "System Settings",
|
||||||
|
"pvPerInverter": "PV per Inverter",
|
||||||
|
"pvInInverter": "PV in Inverter {number}",
|
||||||
|
"dynamicPricing": "Dynamic Pricing",
|
||||||
|
"dynamicPricingMode": "Dynamic Pricing Mode",
|
||||||
|
"dynamicPricingOff": "Off",
|
||||||
|
"dynamicPricingSpotPrice": "Spot Price",
|
||||||
|
"dynamicPricingTou": "TOU",
|
||||||
|
"currentPrice": "Current Price",
|
||||||
|
"priceToSell": "Price to Sell",
|
||||||
|
"priceToBuy": "Price to Buy",
|
||||||
|
"timeToSell": "Time to Sell",
|
||||||
|
"timeToBuy": "Time to Buy",
|
||||||
|
"timeFrom": "From",
|
||||||
|
"timeTo": "To",
|
||||||
|
"networkProviderSetOnInformationTab": "Set on Information tab",
|
||||||
"tourLanguageTitle": "Language",
|
"tourLanguageTitle": "Language",
|
||||||
"tourLanguageContent": "Choose your preferred language. The interface supports English, German, French, and Italian.",
|
"tourLanguageContent": "Choose your preferred language. The interface supports English, German, French, and Italian.",
|
||||||
"tourExploreTitle": "Explore an Installation",
|
"tourExploreTitle": "Explore an Installation",
|
||||||
|
|
|
||||||
|
|
@ -521,8 +521,36 @@
|
||||||
"minimumSocPercent": "SoC minimum (%)",
|
"minimumSocPercent": "SoC minimum (%)",
|
||||||
"powerW": "Puissance (W)",
|
"powerW": "Puissance (W)",
|
||||||
"enterPowerValue": "Entrez une valeur de puissance positive ou négative",
|
"enterPowerValue": "Entrez une valeur de puissance positive ou négative",
|
||||||
|
"inverterNumber": "Nombre d'onduleurs",
|
||||||
|
"batteriesCountInInverter": "Nombre de batteries dans l'onduleur {number}",
|
||||||
|
"batteryNumberInClusterN": "Nombre de batteries dans le cluster {n}",
|
||||||
|
"pvStringsNumberInInverterN": "Nombre de chaînes PV dans l'onduleur {n}",
|
||||||
|
"batteries": "batteries",
|
||||||
|
"maximumChargingCurrentPerBattery": "Courant de charge maximum par batterie (A)",
|
||||||
|
"maximumChargingCurrentPerClusterLabel": "Courant de charge maximum par cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerClusterLabel": "Courant de décharge maximum par cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerBattery": "Courant de décharge maximum par batterie (A)",
|
||||||
|
"powerPerInverterKW": "Puissance par onduleur (kW)",
|
||||||
"startDateTime": "Date et heure de début (Début < Fin)",
|
"startDateTime": "Date et heure de début (Début < Fin)",
|
||||||
"stopDateTime": "Date et heure de fin (Début < Fin)",
|
"stopDateTime": "Date et heure de fin (Début < Fin)",
|
||||||
|
"installationSetup": "Configuration de l'installation",
|
||||||
|
"batteryLimits": "Limites de la batterie",
|
||||||
|
"systemSettings": "Paramètres système",
|
||||||
|
"pvPerInverter": "PV par onduleur",
|
||||||
|
"pvInInverter": "PV dans l'onduleur {number}",
|
||||||
|
"dynamicPricing": "Tarification dynamique",
|
||||||
|
"dynamicPricingMode": "Mode de tarification dynamique",
|
||||||
|
"dynamicPricingOff": "Désactivé",
|
||||||
|
"dynamicPricingSpotPrice": "Prix spot",
|
||||||
|
"dynamicPricingTou": "TOU",
|
||||||
|
"currentPrice": "Prix actuel",
|
||||||
|
"priceToSell": "Prix de vente",
|
||||||
|
"priceToBuy": "Prix d'achat",
|
||||||
|
"timeToSell": "Heure de vente",
|
||||||
|
"timeToBuy": "Heure d'achat",
|
||||||
|
"timeFrom": "De",
|
||||||
|
"timeTo": "À",
|
||||||
|
"networkProviderSetOnInformationTab": "À définir dans l'onglet Informations",
|
||||||
"tourLanguageTitle": "Langue",
|
"tourLanguageTitle": "Langue",
|
||||||
"tourLanguageContent": "Choisissez votre langue préférée. L'interface est disponible en anglais, allemand, français et italien.",
|
"tourLanguageContent": "Choisissez votre langue préférée. L'interface est disponible en anglais, allemand, français et italien.",
|
||||||
"tourExploreTitle": "Explorer une installation",
|
"tourExploreTitle": "Explorer une installation",
|
||||||
|
|
|
||||||
|
|
@ -521,8 +521,36 @@
|
||||||
"minimumSocPercent": "SoC minimo (%)",
|
"minimumSocPercent": "SoC minimo (%)",
|
||||||
"powerW": "Potenza (W)",
|
"powerW": "Potenza (W)",
|
||||||
"enterPowerValue": "Inserire un valore di potenza positivo o negativo",
|
"enterPowerValue": "Inserire un valore di potenza positivo o negativo",
|
||||||
|
"inverterNumber": "Numero di inverter",
|
||||||
|
"batteriesCountInInverter": "Numero di batterie nell'inverter {number}",
|
||||||
|
"batteryNumberInClusterN": "Numero di batterie nel cluster {n}",
|
||||||
|
"pvStringsNumberInInverterN": "Numero di stringhe PV nell'inverter {n}",
|
||||||
|
"batteries": "batterie",
|
||||||
|
"maximumChargingCurrentPerBattery": "Corrente massima di carica per batteria (A)",
|
||||||
|
"maximumChargingCurrentPerClusterLabel": "Corrente massima di carica per cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerClusterLabel": "Corrente massima di scarica per cluster (A)",
|
||||||
|
"maximumDischargingCurrentPerBattery": "Corrente massima di scarica per batteria (A)",
|
||||||
|
"powerPerInverterKW": "Potenza per inverter (kW)",
|
||||||
"startDateTime": "Data e ora di inizio (Inizio < Fine)",
|
"startDateTime": "Data e ora di inizio (Inizio < Fine)",
|
||||||
"stopDateTime": "Data e ora di fine (Inizio < Fine)",
|
"stopDateTime": "Data e ora di fine (Inizio < Fine)",
|
||||||
|
"installationSetup": "Configurazione dell'installazione",
|
||||||
|
"batteryLimits": "Limiti della batteria",
|
||||||
|
"systemSettings": "Impostazioni di sistema",
|
||||||
|
"pvPerInverter": "PV per inverter",
|
||||||
|
"pvInInverter": "PV nell'inverter {number}",
|
||||||
|
"dynamicPricing": "Prezzi dinamici",
|
||||||
|
"dynamicPricingMode": "Modalità prezzi dinamici",
|
||||||
|
"dynamicPricingOff": "Off",
|
||||||
|
"dynamicPricingSpotPrice": "Prezzo spot",
|
||||||
|
"dynamicPricingTou": "TOU",
|
||||||
|
"currentPrice": "Prezzo attuale",
|
||||||
|
"priceToSell": "Prezzo di vendita",
|
||||||
|
"priceToBuy": "Prezzo di acquisto",
|
||||||
|
"timeToSell": "Orario di vendita",
|
||||||
|
"timeToBuy": "Orario di acquisto",
|
||||||
|
"timeFrom": "Da",
|
||||||
|
"timeTo": "A",
|
||||||
|
"networkProviderSetOnInformationTab": "Imposta nella scheda Informazioni",
|
||||||
"tourLanguageTitle": "Lingua",
|
"tourLanguageTitle": "Lingua",
|
||||||
"tourLanguageContent": "Scegli la tua lingua preferita. L'interfaccia supporta inglese, tedesco, francese e italiano.",
|
"tourLanguageContent": "Scegli la tua lingua preferita. L'interfaccia supporta inglese, tedesco, francese e italiano.",
|
||||||
"tourExploreTitle": "Esplora un'installazione",
|
"tourExploreTitle": "Esplora un'installazione",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue