improved weekly performance report quality based on inesco team meeting feedback on 24.02

This commit is contained in:
Yinyin Liu 2026-02-24 15:52:28 +01:00
parent 3bffe70a75
commit 36848b97c5
8 changed files with 165 additions and 75 deletions

View File

@ -206,8 +206,8 @@ public static class DiagnosticService
? string.Join(", ", recentErrors)
: "none";
return $@"You are a technician for Innovenergy {productName} battery energy storage systems.
These are lithium-ion BESS units with a BMS, PV inverter, and grid inverter.
return $@"You are a technician for {productName} battery energy storage systems.
These are sodium-ion BESS units with a BMS, PV inverter, and grid inverter.
Error: {errorDescription}
Other recent errors: {recentList}

View File

@ -99,20 +99,20 @@ public static class ReportEmailService
Consumption: "Verbrauch",
GridImport: "Netzbezug",
GridExport: "Netzeinspeisung",
BatteryInOut: "Batterie Ein/Aus",
BatteryInOut: "Batterie Laden / Entladen",
SolarEnergyUsed: "Energie gespart",
StayedAtHome: "Solar + Batterie, nicht vom Netz",
EstMoneySaved: "Geschätzte Ersparnis",
AtRate: "bei 0.27 CHF/kWh",
AtRate: "bei 0.39 CHF/kWh",
SolarCoverage: "Eigenversorgung",
FromSolar: "aus Solar + Batterie",
BatteryEff: "Batterie-Eff.",
OutVsIn: "Aus vs. Ein",
OutVsIn: "Entladung vs. Ladung",
Day: "Tag",
Load: "Last",
GridIn: "Netz Ein",
GridOut: "Netz Aus",
BattInOut: "Batt. Ein/Aus",
BattInOut: "Batt. Laden/Entl.",
Footer: "Erstellt von <strong style=\"color:#666\">Inesco Energy Monitor Platform</strong> · Powered by Mistral AI"
),
"fr" => new EmailStrings(
@ -129,20 +129,20 @@ public static class ReportEmailService
Consumption: "Consommation",
GridImport: "Import réseau",
GridExport: "Export réseau",
BatteryInOut: "Batterie Entrée/Sortie",
BatteryInOut: "Batterie Charge / Décharge",
SolarEnergyUsed: "Énergie économisée",
StayedAtHome: "solaire + batterie, non achetée au réseau",
EstMoneySaved: "Économies estimées",
AtRate: "à 0.27 CHF/kWh",
AtRate: "à 0.39 CHF/kWh",
SolarCoverage: "Autosuffisance",
FromSolar: "du solaire + batterie",
BatteryEff: "Eff. batterie",
OutVsIn: "sortie vs entrée",
OutVsIn: "décharge vs charge",
Day: "Jour",
Load: "Charge",
GridIn: "Réseau Ent.",
GridOut: "Réseau Sor.",
BattInOut: "Batt. Ent./Sor.",
BattInOut: "Batt. Ch./Déch.",
Footer: "Généré par <strong style=\"color:#666\">Inesco Energy Monitor Platform</strong> · Propulsé par Mistral AI"
),
"it" => new EmailStrings(
@ -159,20 +159,20 @@ public static class ReportEmailService
Consumption: "Consumo",
GridImport: "Import dalla rete",
GridExport: "Export nella rete",
BatteryInOut: "Batteria Ent./Usc.",
BatteryInOut: "Batteria Carica / Scarica",
SolarEnergyUsed: "Energia risparmiata",
StayedAtHome: "solare + batteria, non acquistata dalla rete",
EstMoneySaved: "Risparmio stimato",
AtRate: "a 0.27 CHF/kWh",
AtRate: "a 0.39 CHF/kWh",
SolarCoverage: "Autosufficienza",
FromSolar: "da solare + batteria",
BatteryEff: "Eff. batteria",
OutVsIn: "uscita vs entrata",
OutVsIn: "scarica vs carica",
Day: "Giorno",
Load: "Carico",
GridIn: "Rete Ent.",
GridOut: "Rete Usc.",
BattInOut: "Batt. Ent./Usc.",
BattInOut: "Batt. Car./Sc.",
Footer: "Generato da <strong style=\"color:#666\">Inesco Energy Monitor Platform</strong> · Powered by Mistral AI"
),
_ => new EmailStrings(
@ -189,20 +189,20 @@ public static class ReportEmailService
Consumption: "Consumption",
GridImport: "Grid Import",
GridExport: "Grid Export",
BatteryInOut: "Battery In/Out",
BatteryInOut: "Battery Charge / Discharge",
SolarEnergyUsed: "Energy Saved",
StayedAtHome: "solar + battery, not bought from grid",
EstMoneySaved: "Est. Money Saved",
AtRate: "at 0.27 CHF/kWh",
AtRate: "at 0.39 CHF/kWh",
SolarCoverage: "Self-Sufficiency",
FromSolar: "from solar + battery",
BatteryEff: "Battery Eff.",
OutVsIn: "out vs in",
OutVsIn: "discharge vs charge",
Day: "Day",
Load: "Load",
GridIn: "Grid In",
GridOut: "Grid Out",
BattInOut: "Batt In/Out",
BattInOut: "Batt. Ch./Dis.",
Footer: "Generated by <strong style=\"color:#666\">Inesco Energy Monitor Platform</strong> · Powered by Mistral AI"
)
};
@ -230,21 +230,44 @@ public static class ReportEmailService
"</ul>"
: $"<p style=\"margin:0;line-height:1.6\">{FormatInsightLine(r.AiInsight)}</p>";
// Daily rows
// Detect which components are present across all daily data
var showPv = r.DailyData.Any(d => d.PvProduction > 0.1);
var showGrid = r.DailyData.Any(d => d.GridImport > 0.1);
// Daily rows — colorful bar chart (pixel widths, email-safe)
// Scale each day's bars so their combined total always fills maxBarPx (right-edge aligned).
// This replicates the web page's CSS flexbox flex-shrink:1 behaviour.
const int maxBarPx = 400;
var dailyRows = "";
foreach (var d in r.DailyData)
{
var dayName = DateTime.Parse(d.Date).ToString("ddd");
var dayName = DateTime.Parse(d.Date).ToString("ddd dd.MM");
var isCurrentWeek = string.Compare(d.Date, r.PeriodStart, StringComparison.Ordinal) >= 0;
var bgColor = isCurrentWeek ? "#ffffff" : "#f9f9f9";
var opacity = isCurrentWeek ? "1" : "0.55";
var fontWeight = isCurrentWeek ? "bold" : "normal";
var dayTotal = (showPv ? d.PvProduction : 0) + d.LoadConsumption + (showGrid ? d.GridImport : 0);
if (dayTotal < 0.1) dayTotal = 0.1;
var pvPx = showPv ? (int)(d.PvProduction / dayTotal * maxBarPx) : 0;
var ldPx = (int)(d.LoadConsumption / dayTotal * maxBarPx);
var giPx = showGrid ? (int)(d.GridImport / dayTotal * maxBarPx) : 0;
var pvSpan = showPv ? $@"<span style=""display:inline-block;height:14px;background:#f39c12;width:{pvPx}px;border-radius:2px 0 0 2px""></span>" : "";
var gridSpan = showGrid ? $@"<span style=""display:inline-block;height:14px;background:#e74c3c;width:{giPx}px;border-radius:0 2px 2px 0;margin-left:2px""></span>" : "";
var ldRadius = (!showPv ? "border-radius:2px 0 0 2px;" : "") + (!showGrid ? "border-radius:0 2px 2px 0;" : "");
var valueText = (showPv ? $"PV {d.PvProduction:F1} | " : "")
+ $"{s.Load} {d.LoadConsumption:F1}"
+ (showGrid ? $" | {s.GridIn} {d.GridImport:F1}" : "")
+ " kWh";
dailyRows += $@"
<tr style=""background:{bgColor}"">
<td style=""padding:6px 10px;border-bottom:1px solid #eee"">{dayName} {d.Date}</td>
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.PvProduction:F1}</td>
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.LoadConsumption:F1}</td>
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.GridImport:F1}</td>
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.GridExport:F1}</td>
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.BatteryCharged:F1}/{d.BatteryDischarged:F1}</td>
<tr style=""opacity:{opacity};border-bottom:1px solid #f0f0f0"">
<td style=""padding:6px 8px;font-size:12px;font-weight:{fontWeight};white-space:nowrap;width:80px;vertical-align:top;padding-top:10px"">{dayName}</td>
<td style=""padding:4px 8px"">
<div style=""font-size:10px;color:#888;margin-bottom:3px;text-align:right"">{valueText}</div>
<div style=""height:14px;line-height:14px;font-size:0;white-space:nowrap;width:{maxBarPx}px"">{pvSpan}<span style=""display:inline-block;height:14px;background:#3498db;width:{ldPx}px;{ldRadius}margin-left:{(showPv ? 2 : 0)}px""></span>{gridSpan}</div>
</td>
</tr>";
}
@ -351,18 +374,18 @@ public static class ReportEmailService
</td>
</tr>
<!-- Daily Breakdown -->
<!-- Daily Breakdown (bar chart) -->
<tr>
<td style=""padding:0 30px 24px"">
<div style=""font-size:16px;font-weight:bold;margin-bottom:12px;color:#2c3e50"">{s.DailyBreakdown}</div>
<div style=""font-size:16px;font-weight:bold;margin-bottom:8px;color:#2c3e50"">{s.DailyBreakdown}</div>
<table width=""100%"" cellpadding=""0"" cellspacing=""0"" style=""border:1px solid #eee;border-radius:4px;font-size:13px"">
<!-- Legend -->
<tr style=""background:#f8f9fa"">
<th style=""padding:6px 10px;text-align:left"">{s.Day}</th>
<th style=""padding:6px 10px;text-align:right"">PV</th>
<th style=""padding:6px 10px;text-align:right"">{s.Load}</th>
<th style=""padding:6px 10px;text-align:right"">{s.GridIn}</th>
<th style=""padding:6px 10px;text-align:right"">{s.GridOut}</th>
<th style=""padding:6px 10px;text-align:right"">{s.BattInOut}</th>
<td colspan=""2"" style=""padding:8px 10px;font-size:12px"">
{(showPv ? @$"<span style=""display:inline-block;width:10px;height:10px;background:#f39c12;border-radius:2px;margin-right:4px""></span>PV &nbsp;&nbsp;" : "")}
<span style=""display:inline-block;width:10px;height:10px;background:#3498db;border-radius:2px;margin-right:4px""></span>{s.Load} &nbsp;&nbsp;
{(showGrid ? @$"<span style=""display:inline-block;width:10px;height:10px;background:#e74c3c;border-radius:2px;margin-right:4px""></span>{s.GridIn}" : "")}
</td>
</tr>
{dailyRows}
</table>

View File

@ -120,7 +120,7 @@ public static class WeeklyReportService
var behavior = BehaviorAnalyzer.Analyze(currentHourlyData);
// Pre-computed savings — single source of truth for UI and AI
const double ElectricityPriceCHF = 0.27;
const double ElectricityPriceCHF = 0.39;
var totalEnergySaved = Math.Round(currentSummary.TotalConsumption - currentSummary.TotalGridImport, 1);
var totalSavingsCHF = Math.Round(totalEnergySaved * ElectricityPriceCHF, 0);
var avgDailyConsumption = currentWeekDays.Count > 0 ? currentSummary.TotalConsumption / currentWeekDays.Count : 0;
@ -183,7 +183,8 @@ public static class WeeklyReportService
_ => "English"
};
private static string FormatHour(int hour) => $"{hour:D2}:00";
private static string FormatHour(int hour) => $"{hour:D2}:00";
private static string FormatHourSlot(int hour) => $"{hour:D2}:00{hour + 1:D2}:00";
private static async Task<string> GetAiInsightAsync(
List<DailyEnergyData> currentWeek,
@ -203,7 +204,13 @@ public static class WeeklyReportService
return "AI insight unavailable (API key not configured).";
}
const double ElectricityPriceCHF = 0.27;
const double ElectricityPriceCHF = 0.39;
// Detect which components are present
var hasPv = currentWeek.Sum(d => d.PvProduction) > 0.5;
var hasBattery = currentWeek.Sum(d => d.BatteryCharged) > 0.5
|| currentWeek.Sum(d => d.BatteryDischarged) > 0.5;
var hasGrid = currentWeek.Sum(d => d.GridImport) > 0.5;
var bestDay = currentWeek.OrderByDescending(d => d.PvProduction).First();
var worstDay = currentWeek.OrderBy(d => d.PvProduction).First();
@ -214,16 +221,59 @@ public static class WeeklyReportService
var topBattDayName = DateTime.Parse(topBattDay.Date).ToString("dddd");
// Behavioral facts as compact lines
var peakSolarWindow = FormatHour(behavior.PeakSolarHour) + "" + FormatHour(behavior.PeakSolarEndHour);
var peakSolarWindow = FormatHour(behavior.PeakSolarHour) + "" + FormatHour(behavior.PeakSolarEndHour);
var avoidableSavingsCHF = Math.Round(behavior.AvoidableGridKwh * ElectricityPriceCHF, 0);
var battDepleteLine = behavior.AvgBatteryDepletedHour >= 0
? $"Battery typically depletes below 20% around {FormatHour(behavior.AvgBatteryDepletedHour)}."
: "Battery SoC data not available.";
var battDepleteLine = hasBattery
? (behavior.AvgBatteryDepletedHour >= 0
? $"Battery typically depletes below 20% during {FormatHourSlot(behavior.AvgBatteryDepletedHour)}."
: "Battery stayed above 20% SoC every night this week.")
: "";
var weekdayWeekendLine = behavior.WeekendAvgDailyLoad > 0
? $"Weekday avg load: {behavior.WeekdayAvgDailyLoad} kWh/day. Weekend avg: {behavior.WeekendAvgDailyLoad} kWh/day."
: $"Weekday avg load: {behavior.WeekdayAvgDailyLoad} kWh/day.";
// Build conditional fact lines
var pvDailyFact = hasPv
? $"- PV: total {current.TotalPvProduction:F1} kWh this week. Best day: {bestDayName} ({bestDay.PvProduction:F1} kWh), worst: {worstDayName} ({worstDay.PvProduction:F1} kWh). Solar covered {selfSufficiency}% of consumption."
: "";
var battDailyFact = hasBattery
? $"- Battery: {current.TotalBatteryCharged:F1} kWh charged, {current.TotalBatteryDischarged:F1} kWh discharged. Most active day: {topBattDayName} ({topBattDay.BatteryCharged:F1} kWh charged)."
: "";
var gridDailyFact = hasGrid
? $"- Grid import: {current.TotalGridImport:F1} kWh total this week."
: "";
var pvBehaviorLines = hasPv ? $@"
- Solar active window: {peakSolarWindow}; peak hour: {FormatHourSlot(behavior.PeakSolarHour)}, avg {behavior.AvgPeakSolarKwh} kWh during that hour
- Grid imported while solar was active: {behavior.AvoidableGridKwh} kWh = {avoidableSavingsCHF} CHF that could have been avoided" : "";
var gridBehaviorLine = hasGrid
? $"- Highest grid-import hour: {FormatHourSlot(behavior.HighestGridImportHour)}, avg {behavior.AvgGridImportAtPeakHour} kWh during that hour"
: "";
var battBehaviorLine = !string.IsNullOrEmpty(battDepleteLine) ? $"- {battDepleteLine}" : "";
// Build conditional instructions
var instruction1 = $"1. Energy savings: Write 12 sentences. Say that this week, thanks to SodistoreHome, the customer avoided buying {totalEnergySaved} kWh from the grid, saving {totalSavingsCHF} CHF (at {ElectricityPriceCHF} CHF/kWh). Use these exact numbers — do not recalculate or change them.";
var instruction2 = hasPv
? $"2. Solar performance: Comment on the best and worst solar day this week and the likely weather reason."
: hasGrid
? $"2. Grid usage: Comment on the {current.TotalGridImport:F1} kWh drawn from the grid this week and what time of day drives it most ({FormatHourSlot(behavior.HighestGridImportHour)})."
: "2. Consumption pattern: Comment on the weekday vs weekend load pattern.";
var instruction3 = hasBattery
? $"3. Battery performance: Use the daily facts. Keep it simple for a homeowner."
: "3. Consumption pattern: Comment on the peak load time and weekday vs weekend usage.";
var instruction4 = hasPv
? $"4. Smart action for next week: Write exactly 2 sentences. Sentence 1: point out the timing mismatch using exact numbers — peak household load is during {FormatHourSlot(behavior.PeakLoadHour)} ({behavior.AvgPeakLoadKwh} kWh) but solar peaks during {FormatHourSlot(behavior.PeakSolarHour)} ({behavior.AvgPeakSolarKwh} kWh), with solar active from {peakSolarWindow}. Sentence 2: suggest shifting energy-intensive appliances (such as washing machine, dishwasher, heat pump, or EV charger if applicable) to run during the solar window {peakSolarWindow} — do not assume which specific device the customer has."
: hasGrid
? $"4. Smart action for next week: Write exactly 2 sentences. Sentence 1: state that the peak grid-import hour is {FormatHourSlot(behavior.HighestGridImportHour)} ({behavior.AvgGridImportAtPeakHour} kWh avg). Sentence 2: suggest one action to reduce grid use during that hour — shifting energy-intensive appliances (washing machine, dishwasher, heat pump, EV charger) away from that time."
: "4. Smart action for next week: Give one practical tip to reduce energy consumption based on the peak load time and weekday/weekend pattern.";
var prompt = $@"You are an energy advisor for a SodistoreHome installation: ""{installationName}"".
Write 4 bullet points (each on its own line starting with ""- ""). No bold markers, no asterisks, no markdown plain text only.
@ -232,26 +282,27 @@ IMPORTANT FORMAT RULE: Each bullet MUST start with a short title followed by a c
CRITICAL: All numbers below are pre-calculated. Use these values as-is do not recalculate, round differently, or change any number.
SYSTEM COMPONENTS: PV={hasPv}, Battery={hasBattery}, Grid={hasGrid}
DAILY FACTS:
- Total energy saved: {totalEnergySaved} kWh (solar + battery), saving {totalSavingsCHF} CHF at {ElectricityPriceCHF} CHF/kWh. Self-sufficient {selfSufficiency}% of the time.
- Best solar day: {bestDayName} with {bestDay.PvProduction:F1} kWh. Worst: {worstDayName} with {worstDay.PvProduction:F1} kWh.
- Battery: {current.TotalBatteryCharged:F1} kWh charged, {current.TotalBatteryDischarged:F1} kWh discharged. Most active day: {topBattDayName} ({topBattDay.BatteryCharged:F1} kWh charged).
- Total consumption: {current.TotalConsumption:F1} kWh this week. Self-sufficiency: {selfSufficiency}%.
{pvDailyFact}
{battDailyFact}
{gridDailyFact}
BEHAVIORAL PATTERN (from hourly data this week):
- Peak household load: {FormatHour(behavior.PeakLoadHour)} avg {behavior.AvgPeakLoadKwh} kWh/hr
- Peak solar window: {peakSolarWindow}, avg {behavior.AvgPeakSolarKwh} kWh/hr
- Grid imported while solar was active this week: {behavior.AvoidableGridKwh} kWh total = {avoidableSavingsCHF} CHF that could have been avoided
- Highest single grid-import hour: {FormatHour(behavior.HighestGridImportHour)}, avg {behavior.AvgGridImportAtPeakHour} kWh/hr
- {weekdayWeekendLine}
- {battDepleteLine}
- Peak household load: {FormatHourSlot(behavior.PeakLoadHour)}, avg {behavior.AvgPeakLoadKwh} kWh during that hour
- {weekdayWeekendLine}{pvBehaviorLines}
{gridBehaviorLine}
{battBehaviorLine}
INSTRUCTIONS:
1. Energy savings: Use the daily facts. State {totalEnergySaved} kWh and {totalSavingsCHF} CHF. Use these exact numbers do not recalculate or substitute any of them.
2. Best vs worst solar day: Use the daily facts. Mention likely weather reason.
3. Battery performance: Use the daily facts. Keep it simple for a homeowner.
4. Smart action for next week: Write exactly 2 sentences. Sentence 1: state the pattern using these exact numbers peak load at {FormatHour(behavior.PeakLoadHour)} ({behavior.AvgPeakLoadKwh} kWh/hr) vs solar peak at {peakSolarWindow} ({behavior.AvgPeakSolarKwh} kWh/hr), and that {behavior.AvoidableGridKwh} kWh ({avoidableSavingsCHF} CHF) was drawn from the grid while solar was active. Sentence 2: give ONE concrete action (what appliance to shift, to which hours) and state it would recover the {avoidableSavingsCHF} CHF. Use all these exact numbers do not substitute or omit any.
{instruction1}
{instruction2}
{instruction3}
{instruction4}
Rules: Write for a homeowner, not an engineer. Do NOT use asterisks or any formatting marks.
Rules: Write for a homeowner, not an engineer. Do NOT use asterisks or any formatting marks. Only describe components that exist (PV={hasPv}, Battery={hasBattery}, Grid={hasGrid}). Do NOT add any closing remark, summary sentence, or motivational phrase after the 4 bullet points (e.g. no 'Das ist ein guter Fortschritt', 'Keep it up', 'Good progress', etc.). Write exactly 4 bullet points nothing before, nothing after.
IMPORTANT: Write your entire response in {LanguageName(language)}.";
try

View File

@ -342,10 +342,10 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
<FormattedMessage id="avgDailyConsumption" defaultMessage="Avg Daily Consumption" />
</td>
<td style={{ textAlign: 'right', color: '#888', fontSize: '13px' }}>
{(cur.totalConsumption / currentWeekDayCount).toFixed(1)} kWh/day
{(cur.totalConsumption / currentWeekDayCount).toFixed(1)} kWh
</td>
{prev && <td style={{ textAlign: 'right', color: '#bbb', fontSize: '13px' }}>
{(prev.totalConsumption / previousWeekDayCount).toFixed(1)} kWh/day
{(prev.totalConsumption / previousWeekDayCount).toFixed(1)} kWh
</td>}
{prev && <td />}
</tr>

View File

@ -102,12 +102,12 @@
"solarStayedHome": "Solar + Batterie, nicht vom Netz",
"daysOfYourUsage": "Tage Ihres Verbrauchs",
"estMoneySaved": "Geschätzte Ersparnisse",
"atCHFRate": "bei 0,27 CHF/kWh Ø",
"atCHFRate": "bei 0,39 CHF/kWh Ø",
"solarCoverage": "Eigenversorgung",
"fromSolarSub": "aus Solar + Batterie",
"avgDailyConsumption": "Ø Tagesverbrauch",
"batteryEfficiency": "Batterieeffizienz",
"batteryEffSub": "Energie aus vs. Energie ein",
"batteryEffSub": "Entladung vs. Ladung",
"weeklySummary": "Wöchentliche Zusammenfassung",
"metric": "Kennzahl",
"thisWeek": "Diese Woche",
@ -116,7 +116,7 @@
"consumption": "Verbrauch",
"gridImport": "Netzbezug",
"gridExport": "Netzeinspeisung",
"batteryInOut": "Batterie Ein / Aus",
"batteryInOut": "Batterie Laden / Entladen",
"dailyBreakdown": "Tägliche Aufschlüsselung",
"prevWeek": "(Vorwoche)",
"sendReport": "Bericht senden",
@ -373,5 +373,10 @@
"alarm_AFCIFault": "Lichtbogenfehler",
"alarm_GFCIHigh": "Erhöhter Fehlerstrom",
"alarm_PVVoltageHigh": "PV-Spannung zu hoch",
"alarm_OffGridBusVoltageTooLow": "Off-Grid-Busspannung zu niedrig"
}
"alarm_OffGridBusVoltageTooLow": "Off-Grid-Busspannung zu niedrig",
"Information": "Informationen",
"allInstallations": "Alle Installationen",
"group": "Gruppe",
"groups": "Gruppen",
"requiredOrderNumber": "Pflichtbestellnummer"
}

View File

@ -84,12 +84,12 @@
"solarStayedHome": "solar + battery, not bought from grid",
"daysOfYourUsage": "days of your usage",
"estMoneySaved": "Est. Money Saved",
"atCHFRate": "at 0.27 CHF/kWh avg.",
"atCHFRate": "at 0.39 CHF/kWh avg.",
"solarCoverage": "Self-Sufficiency",
"fromSolarSub": "from solar + battery",
"avgDailyConsumption": "Avg Daily Consumption",
"batteryEfficiency": "Battery Efficiency",
"batteryEffSub": "energy out vs energy in",
"batteryEffSub": "discharge vs charge",
"weeklySummary": "Weekly Summary",
"metric": "Metric",
"thisWeek": "This Week",
@ -98,7 +98,7 @@
"consumption": "Consumption",
"gridImport": "Grid Import",
"gridExport": "Grid Export",
"batteryInOut": "Battery In / Out",
"batteryInOut": "Battery Charge / Discharge",
"dailyBreakdown": "Daily Breakdown",
"prevWeek": "(prev week)",
"sendReport": "Send Report",

View File

@ -96,12 +96,12 @@
"solarStayedHome": "solaire + batterie, non achetée au réseau",
"daysOfYourUsage": "jours de votre consommation",
"estMoneySaved": "Économies estimées",
"atCHFRate": "à 0,27 CHF/kWh moy.",
"atCHFRate": "à 0,39 CHF/kWh moy.",
"solarCoverage": "Autosuffisance",
"fromSolarSub": "du solaire + batterie",
"avgDailyConsumption": "Conso. quotidienne moy.",
"batteryEfficiency": "Efficacité de la batterie",
"batteryEffSub": "énergie sortante vs énergie entrante",
"batteryEffSub": "décharge vs charge",
"weeklySummary": "Résumé hebdomadaire",
"metric": "Métrique",
"thisWeek": "Cette semaine",
@ -110,7 +110,7 @@
"consumption": "Consommation",
"gridImport": "Importation réseau",
"gridExport": "Exportation réseau",
"batteryInOut": "Batterie Entrée / Sortie",
"batteryInOut": "Batterie Charge / Décharge",
"dailyBreakdown": "Répartition quotidienne",
"prevWeek": "(semaine précédente)",
"sendReport": "Envoyer le rapport",
@ -367,5 +367,16 @@
"alarm_AFCIFault": "Défaillance AFCI",
"alarm_GFCIHigh": "Courant de défaut élevé",
"alarm_PVVoltageHigh": "Tension PV élevée",
"alarm_OffGridBusVoltageTooLow": "Tension du bus hors réseau trop faible"
}
"alarm_OffGridBusVoltageTooLow": "Tension du bus hors réseau trop faible",
"Information": "Informations",
"allInstallations": "Toutes les installations",
"group": "Groupe",
"groups": "Groupes",
"requiredOrderNumber": "Numéro de commande requis",
"addNewChild": "Ajouter un sous-élément",
"addNewDialogButton": "Ajouter un bouton de dialogue",
"groupTabs": "Groupes",
"groupTree": "Arborescence de groupes",
"installationTabs": "Installations",
"navigationTabs": "Navigation"
}

View File

@ -107,12 +107,12 @@
"solarStayedHome": "solare + batteria, non acquistata dalla rete",
"daysOfYourUsage": "giorni del tuo consumo",
"estMoneySaved": "Risparmio stimato",
"atCHFRate": "a 0,27 CHF/kWh media",
"atCHFRate": "a 0,39 CHF/kWh media",
"solarCoverage": "Autosufficienza",
"fromSolarSub": "da solare + batteria",
"avgDailyConsumption": "Consumo medio giornaliero",
"batteryEfficiency": "Efficienza della batteria",
"batteryEffSub": "energia in uscita vs energia in entrata",
"batteryEffSub": "scarica vs carica",
"weeklySummary": "Riepilogo settimanale",
"metric": "Metrica",
"thisWeek": "Questa settimana",
@ -121,7 +121,7 @@
"consumption": "Consumo",
"gridImport": "Importazione rete",
"gridExport": "Esportazione rete",
"batteryInOut": "Batteria Entrata / Uscita",
"batteryInOut": "Batteria Carica / Scarica",
"dailyBreakdown": "Ripartizione giornaliera",
"prevWeek": "(settimana precedente)",
"sendReport": "Invia rapporto",