improved weekly performance report quality based on inesco team meeting feedback on 24.02
This commit is contained in:
parent
3bffe70a75
commit
36848b97c5
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 " : "")}
|
||||
<span style=""display:inline-block;width:10px;height:10px;background:#3498db;border-radius:2px;margin-right:4px""></span>{s.Load}
|
||||
{(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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -184,6 +184,7 @@ public static class WeeklyReportService
|
|||
};
|
||||
|
||||
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();
|
||||
|
|
@ -216,14 +223,57 @@ public static class WeeklyReportService
|
|||
// Behavioral facts as compact lines
|
||||
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 1–2 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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue