Compare commits
8 Commits
4d0d446686
...
062fd5141f
| Author | SHA1 | Date |
|---|---|---|
|
|
062fd5141f | |
|
|
e72f16f26b | |
|
|
8de43276a0 | |
|
|
2f8eda5e7e | |
|
|
50c45399bd | |
|
|
36848b97c5 | |
|
|
3bffe70a75 | |
|
|
25280afb8f |
|
|
@ -44,6 +44,12 @@
|
||||||
<None Update="Resources/s3cmd.py">
|
<None Update="Resources/s3cmd.py">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Resources/AlarmTranslations.*.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Resources/AlarmNames.de.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update=".env">
|
<None Update=".env">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|
|
||||||
|
|
@ -827,28 +827,28 @@ public class Controller : ControllerBase
|
||||||
/// Usage: GET /api/TestDiagnoseError?errorDescription=SomeAlarm
|
/// Usage: GET /api/TestDiagnoseError?errorDescription=SomeAlarm
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet(nameof(TestDiagnoseError))]
|
[HttpGet(nameof(TestDiagnoseError))]
|
||||||
public async Task<ActionResult> TestDiagnoseError(string errorDescription = "AbnormalGridVoltage")
|
public async Task<ActionResult> TestDiagnoseError(string errorDescription = "AbnormalGridVoltage", string language = "en")
|
||||||
{
|
{
|
||||||
// 1. Try knowledge base first
|
// 1. Try static lookup (KB for English, pre-generated translations for others)
|
||||||
var kbResult = AlarmKnowledgeBase.TryGetDiagnosis(errorDescription);
|
var staticResult = DiagnosticService.TryGetTranslation(errorDescription, language);
|
||||||
if (kbResult is not null)
|
if (staticResult is not null)
|
||||||
{
|
{
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
Source = "KnowledgeBase",
|
Source = "KnowledgeBase",
|
||||||
Alarm = errorDescription,
|
Alarm = errorDescription,
|
||||||
MistralEnabled = DiagnosticService.IsEnabled,
|
MistralEnabled = DiagnosticService.IsEnabled,
|
||||||
kbResult.Explanation,
|
staticResult.Explanation,
|
||||||
kbResult.Causes,
|
staticResult.Causes,
|
||||||
kbResult.NextSteps
|
staticResult.NextSteps
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. If not in KB, try Mistral directly with a test prompt
|
// 2. If not found, try Mistral with the correct language
|
||||||
if (!DiagnosticService.IsEnabled)
|
if (!DiagnosticService.IsEnabled)
|
||||||
return Ok(new { Source = "None", Alarm = errorDescription, Message = "Not in knowledge base and Mistral API key not configured." });
|
return Ok(new { Source = "None", Alarm = errorDescription, Message = "Not in knowledge base and Mistral API key not configured." });
|
||||||
|
|
||||||
var aiResult = await DiagnosticService.TestCallMistralAsync(errorDescription);
|
var aiResult = await DiagnosticService.TestCallMistralAsync(errorDescription, language);
|
||||||
if (aiResult is null)
|
if (aiResult is null)
|
||||||
return Ok(new { Source = "MistralFailed", Alarm = errorDescription, Message = "Mistral API call failed or returned empty." });
|
return Ok(new { Source = "MistralFailed", Alarm = errorDescription, Message = "Mistral API call failed or returned empty." });
|
||||||
|
|
||||||
|
|
@ -1255,6 +1255,104 @@ public class Controller : ControllerBase
|
||||||
return Redirect($"https://monitor.inesco.energy/?username={user.Email}&reset=true"); // TODO: move to settings file
|
return Redirect($"https://monitor.inesco.energy/?username={user.Email}&reset=true"); // TODO: move to settings file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Alarm Review Campaign ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
[HttpPost(nameof(SendTestAlarmReview))]
|
||||||
|
public async Task<ActionResult> SendTestAlarmReview()
|
||||||
|
{
|
||||||
|
await AlarmReviewService.SendTestBatchAsync();
|
||||||
|
return Ok(new { message = "Test review email sent to liu@inesco.energy. Check your inbox." });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(StartAlarmReviewCampaign))]
|
||||||
|
public ActionResult StartAlarmReviewCampaign()
|
||||||
|
{
|
||||||
|
AlarmReviewService.StartCampaign();
|
||||||
|
return Ok(new { message = "Alarm review campaign started." });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(StopAlarmReviewCampaign))]
|
||||||
|
public ActionResult StopAlarmReviewCampaign()
|
||||||
|
{
|
||||||
|
AlarmReviewService.StopCampaign();
|
||||||
|
return Ok(new { message = "Campaign paused — progress preserved. Use ResumeAlarmReviewCampaign to restart timers." });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(ResumeAlarmReviewCampaign))]
|
||||||
|
public ActionResult ResumeAlarmReviewCampaign()
|
||||||
|
{
|
||||||
|
AlarmReviewService.ResumeCampaign();
|
||||||
|
return Ok(new { message = "Campaign resumed — timers restarted from existing progress." });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(ResetAlarmReviewCampaign))]
|
||||||
|
public ActionResult ResetAlarmReviewCampaign()
|
||||||
|
{
|
||||||
|
AlarmReviewService.ResetCampaign();
|
||||||
|
return Ok(new { message = "Campaign fully reset — all progress deleted. Use StartAlarmReviewCampaign to begin again." });
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(CorrectAlarm))]
|
||||||
|
public ActionResult CorrectAlarm(int batch, string key)
|
||||||
|
{
|
||||||
|
var html = AlarmReviewService.GetCorrectionPage(batch, key);
|
||||||
|
return Content(html, "text/html");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(ApplyAlarmCorrection))]
|
||||||
|
public ActionResult ApplyAlarmCorrection([FromBody] AlarmCorrectionRequest req)
|
||||||
|
{
|
||||||
|
if (req == null) return BadRequest();
|
||||||
|
var correction = new DiagnosticResponse
|
||||||
|
{
|
||||||
|
Explanation = req.Explanation ?? "",
|
||||||
|
Causes = req.Causes ?? new List<string>(),
|
||||||
|
NextSteps = req.NextSteps ?? new List<string>(),
|
||||||
|
};
|
||||||
|
var ok = AlarmReviewService.ApplyCorrection(req.BatchNumber, req.AlarmKey ?? "", correction);
|
||||||
|
return ok ? Ok(new { message = "Korrektur gespeichert." }) : BadRequest("Batch or alarm not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(ReviewAlarms))]
|
||||||
|
public ActionResult ReviewAlarms(int batch, string reviewer)
|
||||||
|
{
|
||||||
|
var html = AlarmReviewService.GetReviewPage(batch, reviewer);
|
||||||
|
if (html is null) return NotFound("Batch not found or reviewer not recognised.");
|
||||||
|
return Content(html, "text/html");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(SubmitAlarmReview))]
|
||||||
|
public async Task<ActionResult> SubmitAlarmReview(int batch, string? reviewer, [FromBody] List<ReviewFeedback>? feedbacks)
|
||||||
|
{
|
||||||
|
// Batch 0 = test mode — run dry-run synthesis and return preview HTML (nothing is saved)
|
||||||
|
if (batch == 0)
|
||||||
|
{
|
||||||
|
var previewHtml = await AlarmReviewService.PreviewSynthesisAsync(feedbacks);
|
||||||
|
return Ok(new { preview = previewHtml });
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok = AlarmReviewService.SubmitFeedback(batch, reviewer, feedbacks);
|
||||||
|
return ok ? Ok(new { message = "Feedback saved. Thank you!" })
|
||||||
|
: BadRequest("Batch not found, reviewer not recognised, or already submitted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(GetAlarmReviewStatus))]
|
||||||
|
public ActionResult GetAlarmReviewStatus()
|
||||||
|
{
|
||||||
|
return Ok(AlarmReviewService.GetStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(DownloadCheckedKnowledgeBase))]
|
||||||
|
public ActionResult DownloadCheckedKnowledgeBase()
|
||||||
|
{
|
||||||
|
var content = AlarmReviewService.GetCheckedFileContent();
|
||||||
|
if (content is null) return NotFound("AlarmKnowledgeBaseChecked.cs has not been generated yet.");
|
||||||
|
|
||||||
|
return File(System.Text.Encoding.UTF8.GetBytes(content),
|
||||||
|
"text/plain",
|
||||||
|
"AlarmKnowledgeBaseChecked.cs");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pre-computed behavioral facts derived from hourly data.
|
||||||
|
/// All heavy analysis is done in C# — the AI only gets these clean conclusions.
|
||||||
|
/// </summary>
|
||||||
|
public class BehavioralPattern
|
||||||
|
{
|
||||||
|
// Peak hours
|
||||||
|
public int PeakLoadHour { get; set; } // 0-23, hour of day with highest avg load
|
||||||
|
public int PeakSolarHour { get; set; } // 0-23, hour with highest avg PV output
|
||||||
|
public int PeakSolarEndHour { get; set; } // last hour of meaningful solar window
|
||||||
|
public int HighestGridImportHour { get; set; } // 0-23, hour with most avg grid import
|
||||||
|
|
||||||
|
// kWh figures
|
||||||
|
public double AvgPeakLoadKwh { get; set; } // avg load at peak hour (per day)
|
||||||
|
public double AvgPeakSolarKwh { get; set; } // avg PV at peak solar hour (per day)
|
||||||
|
public double AvoidableGridKwh { get; set; } // grid import during hours solar was active
|
||||||
|
public double AvgGridImportAtPeakHour { get; set; } // avg grid import at worst hour
|
||||||
|
|
||||||
|
// Weekday vs weekend
|
||||||
|
public double WeekdayAvgDailyLoad { get; set; } // avg kWh/day Mon-Fri
|
||||||
|
public double WeekendAvgDailyLoad { get; set; } // avg kWh/day Sat-Sun
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
public int AvgBatteryDepletedHour { get; set; } // avg hour when SoC first drops below 20%
|
||||||
|
public bool BatteryDepletesOvernight { get; set; } // true if battery regularly hits low SoC at night
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
|
public class HourlyEnergyData
|
||||||
|
{
|
||||||
|
public DateTime DateTime { get; set; } // e.g. 2026-02-14 08:00:00
|
||||||
|
public int Hour { get; set; } // 0-23
|
||||||
|
public string DayOfWeek { get; set; } = ""; // "Monday" etc.
|
||||||
|
public bool IsWeekend { get; set; }
|
||||||
|
|
||||||
|
// Energy for this hour (kWh) — derived from diff of consecutive "Today" cumulative snapshots
|
||||||
|
public double PvKwh { get; set; }
|
||||||
|
public double LoadKwh { get; set; }
|
||||||
|
public double GridImportKwh { get; set; }
|
||||||
|
public double BatteryChargedKwh { get; set; }
|
||||||
|
public double BatteryDischargedKwh { get; set; }
|
||||||
|
|
||||||
|
// Instantaneous state at snapshot time
|
||||||
|
public double BattSoC { get; set; } // % (0-100)
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,11 @@ public class WeeklyReportResponse
|
||||||
public WeeklySummary CurrentWeek { get; set; } = new();
|
public WeeklySummary CurrentWeek { get; set; } = new();
|
||||||
public WeeklySummary? PreviousWeek { get; set; }
|
public WeeklySummary? PreviousWeek { get; set; }
|
||||||
|
|
||||||
|
// Pre-computed savings — single source of truth for UI and AI
|
||||||
|
public double TotalEnergySaved { get; set; } // kWh = Consumption - GridImport
|
||||||
|
public double TotalSavingsCHF { get; set; } // CHF = TotalEnergySaved * 0.27
|
||||||
|
public double DaysEquivalent { get; set; } // TotalEnergySaved / avg daily consumption
|
||||||
|
|
||||||
// Key ratios (current week)
|
// Key ratios (current week)
|
||||||
public double SelfSufficiencyPercent { get; set; }
|
public double SelfSufficiencyPercent { get; set; }
|
||||||
public double SelfConsumptionPercent { get; set; }
|
public double SelfConsumptionPercent { get; set; }
|
||||||
|
|
@ -21,6 +26,7 @@ public class WeeklyReportResponse
|
||||||
public double GridImportChangePercent { get; set; }
|
public double GridImportChangePercent { get; set; }
|
||||||
|
|
||||||
public List<DailyEnergyData> DailyData { get; set; } = new();
|
public List<DailyEnergyData> DailyData { get; set; } = new();
|
||||||
|
public BehavioralPattern? Behavior { get; set; }
|
||||||
public string AiInsight { get; set; } = "";
|
public string AiInsight { get; set; } = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public static class Program
|
||||||
Db.Init();
|
Db.Init();
|
||||||
LoadEnvFile();
|
LoadEnvFile();
|
||||||
DiagnosticService.Initialize();
|
DiagnosticService.Initialize();
|
||||||
|
AlarmReviewService.StartDailyScheduler();
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
RabbitMqManager.InitializeEnvironment();
|
RabbitMqManager.InitializeEnvironment();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
{
|
||||||
|
"AbnormalGridVoltage": "Unnormale Netzspannung",
|
||||||
|
"AbnormalGridFrequency": "Unnormale Netzfrequenz",
|
||||||
|
"InvertedSequenceOfGridVoltage": "Falsche Phasenreihenfolge",
|
||||||
|
"GridVoltagePhaseLoss": "Phasenausfall im Netz",
|
||||||
|
"AbnormalGridCurrent": "Unnormaler Netzstrom",
|
||||||
|
"AbnormalOutputVoltage": "Ungewöhnliche Ausgangsspannung",
|
||||||
|
"AbnormalOutputFrequency": "Ungewöhnliche Ausgangsfrequenz",
|
||||||
|
"AbnormalNullLine": "Fehlerhafter Nullleiter",
|
||||||
|
"AbnormalOffGridOutputVoltage": "Ungewöhnliche Backup-Spannung",
|
||||||
|
"ExcessivelyHighAmbientTemperature": "Zu hohe Umgebungstemperatur",
|
||||||
|
"ExcessiveRadiatorTemperature": "Überhitzter Kühlkörper",
|
||||||
|
"PcbOvertemperature": "Überhitzte Leiterplatte",
|
||||||
|
"DcConverterOvertemperature": "Überhitzter DC-Wandler",
|
||||||
|
"InverterOvertemperatureAlarm": "Warnung: Überhitzung",
|
||||||
|
"InverterOvertemperature": "Wechselrichter überhitzt",
|
||||||
|
"DcConverterOvertemperatureAlarm": "Übertemperaturalarm DC-Wandler",
|
||||||
|
"InsulationFault": "Isolationsfehler",
|
||||||
|
"LeakageProtectionFault": "Leckschutzfehler",
|
||||||
|
"AbnormalLeakageSelfCheck": "Anomaler Leckstrom-Selbsttest",
|
||||||
|
"PoorGrounding": "Schlechte Erdung",
|
||||||
|
"FanFault": "Lüfterfehler",
|
||||||
|
"AuxiliaryPowerFault": "Hilfsstromversorgung Fehler",
|
||||||
|
"ModelCapacityFault": "Modellkapazitätsfehler",
|
||||||
|
"AbnormalLightningArrester": "Überspannungsschutz Fehler",
|
||||||
|
"IslandProtection": "Inselbetrieb Schutz",
|
||||||
|
"Battery1NotConnected": "Batterie 1 nicht verbunden",
|
||||||
|
"Battery1Overvoltage": "Batterie 1 Überspannung",
|
||||||
|
"Battery1Undervoltage": "Batterie 1 Unterspannung",
|
||||||
|
"Battery1DischargeEnd": "Batterie 1 Entladung beendet",
|
||||||
|
"Battery1Inverted": "Batterie 1 Polarität vertauscht",
|
||||||
|
"Battery1OverloadTimeout": "Batterie 1 Überlastung",
|
||||||
|
"Battery1SoftStartFailure": "Batterie 1 Startfehler",
|
||||||
|
"Battery1PowerTubeFault": "Batterie 1 Leistungsteil defekt",
|
||||||
|
"Battery1InsufficientPower": "Batterie 1 Leistung unzureichend",
|
||||||
|
"Battery1BackupProhibited": "Batterie 1 Backup gesperrt",
|
||||||
|
"Battery2NotConnected": "Batterie 2 nicht verbunden",
|
||||||
|
"Battery2Overvoltage": "Batterie 2 Überspannung",
|
||||||
|
"Battery2Undervoltage": "Batterie 2 Unterspannung",
|
||||||
|
"Battery2DischargeEnd": "Batterie 2 Entladung beendet",
|
||||||
|
"Battery2Inverted": "Batterie 2 falsch angeschlossen",
|
||||||
|
"Battery2OverloadTimeout": "Batterie 2 Überlastung",
|
||||||
|
"Battery2SoftStartFailure": "Batterie 2 Startfehler",
|
||||||
|
"Battery2PowerTubeFault": "Batterie 2 Leistungsteil defekt",
|
||||||
|
"Battery2InsufficientPower": "Batterie 2 Leistung unzureichend",
|
||||||
|
"Battery2BackupProhibited": "Batterie 2 Backup gesperrt",
|
||||||
|
"LithiumBattery1ChargeForbidden": "Lithium-Batterie 1 Ladeverbot",
|
||||||
|
"LithiumBattery1DischargeForbidden": "Lithium-Batterie 1 Entladeverbot",
|
||||||
|
"LithiumBattery2ChargeForbidden": "Lithium-Batterie 2 Ladeverbot",
|
||||||
|
"LithiumBattery2DischargeForbidden": "Lithium-Batterie 2 Entladeverbot",
|
||||||
|
"LithiumBattery1Full": "Lithium-Batterie 1 voll",
|
||||||
|
"LithiumBattery1DischargeEnd": "Lithium-Batterie 1 entladen",
|
||||||
|
"LithiumBattery2Full": "Lithium-Batterie 2 voll",
|
||||||
|
"LithiumBattery2DischargeEnd": "Lithium-Batterie 2 entladen",
|
||||||
|
"LeadBatteryTemperatureAbnormality": "Batterietemperatur abnormal",
|
||||||
|
"BatteryAccessMethodError": "Batteriezugriffsfehler",
|
||||||
|
"Pv1NotAccessed": "PV1 nicht erreichbar",
|
||||||
|
"Pv1Overvoltage": "PV1 Überspannung",
|
||||||
|
"AbnormalPv1CurrentSharing": "Ungleichmäßiger PV1-Strom",
|
||||||
|
"Pv1PowerTubeFault": "PV1 Leistungstubus defekt",
|
||||||
|
"Pv1SoftStartFailure": "PV1 Soft-Start fehlgeschlagen",
|
||||||
|
"Pv1OverloadTimeout": "PV1-Überlastung",
|
||||||
|
"Pv1InsufficientPower": "PV1-Schwacher Strom",
|
||||||
|
"Photovoltaic1Overcurrent": "PV1-Überstrom",
|
||||||
|
"Pv2NotAccessed": "PV2-Nicht erkannt",
|
||||||
|
"Pv2Overvoltage": "PV2-Überspannung",
|
||||||
|
"AbnormalPv2CurrentSharing": "Ungewöhnliche Stromverteilung PV2",
|
||||||
|
"Pv2PowerTubeFault": "PV2-Leistungsrohrfehler",
|
||||||
|
"Pv2SoftStartFailure": "PV2-Softstart fehlgeschlagen",
|
||||||
|
"Pv2OverloadTimeout": "PV2-Überlastung Timeout",
|
||||||
|
"Pv2InsufficientPower": "Unzureichende Leistung PV2",
|
||||||
|
"Pv3NotConnected": "PV3 nicht verbunden",
|
||||||
|
"Pv3Overvoltage": "PV3 Überspannung",
|
||||||
|
"Pv3AverageCurrentAnomaly": "PV3 Stromanomalie",
|
||||||
|
"Pv3PowerTubeFailure": "PV3 Leistungselektronik defekt",
|
||||||
|
"Pv3SoftStartFailure": "PV3 Startfehler",
|
||||||
|
"Pv3OverloadTimeout": "PV3-Überlastung",
|
||||||
|
"Pv3ReverseConnection": "PV3-Falschpolung",
|
||||||
|
"Pv4NotConnected": "PV4 Nicht Verbunden",
|
||||||
|
"Pv4Overvoltage": "PV4 Überspannung",
|
||||||
|
"Pv4AverageCurrentAnomaly": "PV4 Stromanomalie",
|
||||||
|
"Pv4PowerTubeFailure": "PV4-Leistungsrohr defekt",
|
||||||
|
"Pv4SoftStartFailure": "PV4-Softstart fehlgeschlagen",
|
||||||
|
"Pv4OverloadTimeout": "PV4-Überlastung",
|
||||||
|
"Pv4ReverseConnection": "PV4 falsch angeschlossen",
|
||||||
|
"InsufficientPhotovoltaicPower": "Zu wenig Solarstrom",
|
||||||
|
"DcBusOvervoltage": "DC-Bus Überspannung",
|
||||||
|
"DcBusUndervoltage": "DC-Bus Unterspannung",
|
||||||
|
"DcBusVoltageUnbalance": "DC-Bus Spannungsungleichgewicht",
|
||||||
|
"BusSlowOvervoltage": "Langsame DC-Bus Überspannung",
|
||||||
|
"HardwareBusOvervoltage": "Hardware DC-Bus Überspannung",
|
||||||
|
"BusSoftStartFailure": "Fehler beim sanften Start",
|
||||||
|
"InverterPowerTubeFault": "Wechselrichter-Leistungshalbleiter defekt",
|
||||||
|
"HardwareOvercurrent": "Hardware-Überstrom",
|
||||||
|
"DcConverterOvervoltage": "DC-Wandler Überspannung",
|
||||||
|
"DcConverterHardwareOvervoltage": "DC-Wandler Hardware-Überspannung",
|
||||||
|
"DcConverterOvercurrent": "DC-Wandler Überstrom",
|
||||||
|
"DcConverterHardwareOvercurrent": "DC-Wandler Hardware-Überstrom",
|
||||||
|
"DcConverterResonatorOvercurrent": "DC-Wandler Resonanz-Überstrom",
|
||||||
|
"SystemOutputOverload": "Systemausgang überlastet",
|
||||||
|
"InverterOverload": "Wechselrichter überlastet",
|
||||||
|
"InverterOverloadTimeout": "Wechselrichter-Überlastung",
|
||||||
|
"LoadPowerOverload": "Überlastung der Lastleistung",
|
||||||
|
"BalancedCircuitOverloadTimeout": "Phasenausgleich-Überlastung",
|
||||||
|
"InverterSoftStartFailure": "Wechselrichter-Softstart-Fehler",
|
||||||
|
"Dsp1ParameterSettingFault": "DSP-Parameter-Fehler",
|
||||||
|
"Dsp2ParameterSettingFault": "DSP2 Parameterfehler",
|
||||||
|
"DspVersionCompatibilityFault": "DSP-Versionen nicht kompatibel",
|
||||||
|
"CpldVersionCompatibilityFault": "CPLD-Version nicht kompatibel",
|
||||||
|
"CpldCommunicationFault": "CPLD-Kommunikationsfehler",
|
||||||
|
"DspCommunicationFault": "DSP-Kommunikationsfehler",
|
||||||
|
"OutputVoltageDcOverlimit": "DC-Spannung zu hoch",
|
||||||
|
"OutputCurrentDcOverlimit": "DC-Strom zu hoch",
|
||||||
|
"RelaySelfCheckFails": "Relais-Selbsttest fehlgeschlagen",
|
||||||
|
"InverterRelayOpen": "Wechselrichter-Relais offen",
|
||||||
|
"InverterRelayShortCircuit": "Wechselrichter-Relais Kurzschluss",
|
||||||
|
"OpenCircuitOfPowerGridRelay": "Netzrelais offen",
|
||||||
|
"ShortCircuitOfPowerGridRelay": "Netzrelais kurzgeschlossen",
|
||||||
|
"GeneratorRelayOpenCircuit": "Generatorrelais offen",
|
||||||
|
"GeneratorRelayShortCircuit": "Generatorrelais kurzgeschlossen",
|
||||||
|
"AbnormalInverter": "Wechselrichter abnormal",
|
||||||
|
"ParallelCommunicationAlarm": "Parallelkommunikationsalarm",
|
||||||
|
"ParallelModuleMissing": "Parallelmodul fehlt",
|
||||||
|
"DuplicateMachineNumbersForParallelModules": "Doppelte Gerätenummern",
|
||||||
|
"ParameterConflictInParallelModule": "Parameterkonflikt im Parallelmodul",
|
||||||
|
"SystemDerating": "Systemleistung reduziert",
|
||||||
|
"PvAccessMethodErrorAlarm": "PV-Zugriffsfehler",
|
||||||
|
"ReservedAlarms4": "Reservierter Alarm 4",
|
||||||
|
"ReservedAlarms5": "Reservierter Alarm 5",
|
||||||
|
"ReverseMeterConnection": "Zähler falsch angeschlossen",
|
||||||
|
"InverterSealPulse": "Wechselrichter-Leistungsbegrenzung",
|
||||||
|
"AbnormalDieselGeneratorVoltage": "Ungewöhnliche Dieselgenerator-Spannung",
|
||||||
|
"AbnormalDieselGeneratorFrequency": "Ungewöhnliche Dieselgenerator-Frequenz",
|
||||||
|
"DieselGeneratorVoltageReverseSequence": "Falsche Phasenfolge des Generators",
|
||||||
|
"DieselGeneratorVoltageOutOfPhase": "Generator nicht synchronisiert",
|
||||||
|
"GeneratorOverload": "Generator überlastet",
|
||||||
|
"StringFault": "PV-String-Fehler",
|
||||||
|
"PvStringPidQuickConnectAbnormal": "PV-String-Anschluss defekt",
|
||||||
|
"DcSpdFunctionAbnormal": "DC-Überspannungsschutz defekt",
|
||||||
|
"PvShortCircuited": "PV-String kurzgeschlossen",
|
||||||
|
"PvBoostDriverAbnormal": "PV-Boost-Treiber defekt",
|
||||||
|
"AcSpdFunctionAbnormal": "AC-Überspannungsschutz defekt",
|
||||||
|
"DcFuseBlown": "DC-Sicherung durchgebrannt",
|
||||||
|
"DcInputVoltageTooHigh": "DC-Eingangsspannung zu hoch",
|
||||||
|
"PvReversed": "PV-Polarität vertauscht",
|
||||||
|
"PidFunctionAbnormal": "PID-Schutzfunktion gestört",
|
||||||
|
"PvStringDisconnected": "PV-String getrennt",
|
||||||
|
"PvStringCurrentUnbalanced": "PV-String Strom unausgeglichen",
|
||||||
|
"NoUtilityGrid": "Kein Stromnetz",
|
||||||
|
"GridVoltageOutOfRange": "Netzspannung außerhalb des Bereichs",
|
||||||
|
"GridFrequencyOutOfRange": "Netzfrequenz außerhalb des Bereichs",
|
||||||
|
"Overload": "Überlastung",
|
||||||
|
"MeterDisconnected": "Stromzähler getrennt",
|
||||||
|
"MeterReverselyConnected": "Zähler falsch angeschlossen",
|
||||||
|
"LinePeVoltageAbnormal": "Abnormale PE-Spannung",
|
||||||
|
"PhaseSequenceError": "Phasenfolgefehler",
|
||||||
|
"FanFailure": "Lüfterausfall",
|
||||||
|
"MeterAbnormal": "Störungsanzeige Zähler",
|
||||||
|
"OptimizerCommunicationAbnormal": "Kommunikationsstörung Optimierer",
|
||||||
|
"OverTemperature": "Überhitzung",
|
||||||
|
"OverTemperatureAlarm": "Überhitzungswarnung",
|
||||||
|
"NtcTemperatureSensorBroken": "Temperatursensor defekt",
|
||||||
|
"SyncSignalAbnormal": "Synchronisationsfehler",
|
||||||
|
"GridStartupConditionsNotMet": "Netzstartbedingungen nicht erfüllt",
|
||||||
|
"BatteryCommunicationFailure": "Batteriekommunikation fehlgeschlagen",
|
||||||
|
"BatteryDisconnected": "Batterie getrennt",
|
||||||
|
"BatteryVoltageTooHigh": "Batteriespannung zu hoch",
|
||||||
|
"BatteryVoltageTooLow": "Batteriespannung zu niedrig",
|
||||||
|
"BatteryReverseConnected": "Batterie falsch angeschlossen",
|
||||||
|
"LeadAcidTempSensorDisconnected": "Temperatursensor nicht angeschlossen",
|
||||||
|
"BatteryTemperatureOutOfRange": "Batterietemperatur außerhalb des Bereichs",
|
||||||
|
"BmsFault": "BMS-Fehler",
|
||||||
|
"LithiumBatteryOverload": "Batterie-Überlastung",
|
||||||
|
"BmsCommunicationAbnormal": "BMS-Kommunikationsfehler",
|
||||||
|
"BatterySpdAbnormal": "Batterie-Überspannungsschutz",
|
||||||
|
"OutputDcComponentBiasAbnormal": "DC-Versatz im Ausgang",
|
||||||
|
"DcComponentOverHighOutputVoltage": "DC-Komponente zu hohe Ausgangsspannung",
|
||||||
|
"OffGridOutputVoltageTooLow": "Netzunabhängige Ausgangsspannung zu niedrig",
|
||||||
|
"OffGridOutputVoltageTooHigh": "Netzunabhängige Ausgangsspannung zu hoch",
|
||||||
|
"OffGridOutputOverCurrent": "Netzunabhängiger Ausgangsüberstrom",
|
||||||
|
"OffGridOutputOverload": "Netzunabhängiger Ausgang überlastet",
|
||||||
|
"BalancedCircuitAbnormal": "Phasenausgleich gestört",
|
||||||
|
"ExportLimitationFailSafe": "Exportbegrenzung Notaus",
|
||||||
|
"DcBiasAbnormal": "DC-Vorspannung abnormal",
|
||||||
|
"HighDcComponentOutputCurrent": "Hohe DC-Komponente im Ausgangsstrom",
|
||||||
|
"BusVoltageSamplingAbnormal": "Spannungsmessung defekt",
|
||||||
|
"RelayFault": "Relaisfehler",
|
||||||
|
"BusVoltageAbnormal": "Gleichspannung abnormal",
|
||||||
|
"InternalCommunicationFailure": "Interne Kommunikation ausgefallen",
|
||||||
|
"TemperatureSensorDisconnected": "Temperatursensor getrennt",
|
||||||
|
"IgbtDriveFault": "IGBT-Ansteuerungsfehler",
|
||||||
|
"EepromError": "EEPROM-Fehler",
|
||||||
|
"AuxiliaryPowerAbnormal": "Hilfsstromversorgung abnormal",
|
||||||
|
"DcAcOvercurrentProtection": "Überstromschutz aktiviert",
|
||||||
|
"CommunicationProtocolMismatch": "Kommunikationsprotokoll-Fehler",
|
||||||
|
"DspComFirmwareMismatch": "Firmware-Inkompatibilität DSP/COM",
|
||||||
|
"DspSoftwareHardwareMismatch": "DSP-Software-Hardware-Inkompatibilität",
|
||||||
|
"CpldAbnormal": "CPLD-Fehler",
|
||||||
|
"RedundancySamplingInconsistent": "Inkonsistente redundante Messungen",
|
||||||
|
"PwmPassThroughSignalFailure": "PWM-Signalweg ausgefallen",
|
||||||
|
"AfciSelfTestFailure": "AFCI-Selbsttest fehlgeschlagen",
|
||||||
|
"PvCurrentSamplingAbnormal": "PV-Strommessung abnormal",
|
||||||
|
"AcCurrentSamplingAbnormal": "AC-Strommessung abnormal",
|
||||||
|
"BusSoftbootFailure": "DC-Bus-Vorstart fehlgeschlagen",
|
||||||
|
"EpoFault": "EPO-Fehler (Notaus)",
|
||||||
|
"MonitoringChipBootVerificationFailed": "Überwachungs-Chip Startfehler",
|
||||||
|
"BmsCommunicationFailure": "BMS-Kommunikationsfehler",
|
||||||
|
"BmsChargeDischargeFailure": "BMS-Lade-/Entladefehler",
|
||||||
|
"BatteryVoltageLow": "Batteriespannung zu niedrig",
|
||||||
|
"BatteryVoltageHigh": "Batteriespannung zu hoch",
|
||||||
|
"BatteryTemperatureAbnormal": "Batterietemperatur ungewöhnlich",
|
||||||
|
"BatteryReversed": "Batterie verkehrt herum",
|
||||||
|
"BatteryOpenCircuit": "Batteriekreis offen",
|
||||||
|
"BatteryOverloadProtection": "Batterieüberlastungsschutz",
|
||||||
|
"Bus2VoltageAbnormal": "Bus2-Spannung ungewöhnlich",
|
||||||
|
"BatteryChargeOcp": "Batterieladung Überstrom",
|
||||||
|
"BatteryDischargeOcp": "Batterieentladung Überstrom",
|
||||||
|
"BatterySoftStartFailed": "Batterie-Softstart fehlgeschlagen",
|
||||||
|
"EpsOutputShortCircuited": "EPS-Ausgang kurzgeschlossen",
|
||||||
|
"OffGridBusVoltageLow": "Netzunabhängige Busspannung zu niedrig",
|
||||||
|
"OffGridTerminalVoltageAbnormal": "Abnormale Spannung am Netzausgang",
|
||||||
|
"SoftStartFailed": "Sanfter Start fehlgeschlagen",
|
||||||
|
"OffGridOutputVoltageAbnormal": "Abnormale Ausgangsspannung im Netzmodus",
|
||||||
|
"BalancedCircuitSelfTestFailed": "Ausgleichsschaltungstest fehlgeschlagen",
|
||||||
|
"HighDcComponentOutputVoltage": "Hohe Gleichspannungskomponente im Ausgang",
|
||||||
|
"OffGridParallelSignalAbnormal": "Parallelsignalstörung",
|
||||||
|
"AFCIFault": "Lichtbogenfehler",
|
||||||
|
"GFCIHigh": "Erhöhter Fehlerstrom",
|
||||||
|
"PVVoltageHigh": "PV-Spannung zu hoch",
|
||||||
|
"OffGridBusVoltageTooLow": "Off-Grid-Busspannung zu niedrig"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
{
|
||||||
|
"alarm_AbnormalGridVoltage": "Tension réseau anormale",
|
||||||
|
"alarm_AbnormalGridFrequency": "Fréquence réseau anormale",
|
||||||
|
"alarm_InvertedSequenceOfGridVoltage": "Séquence de tension inversée",
|
||||||
|
"alarm_GridVoltagePhaseLoss": "Perte de phase réseau",
|
||||||
|
"alarm_AbnormalGridCurrent": "Courant réseau anormal",
|
||||||
|
"alarm_AbnormalOutputVoltage": "Tension de sortie anormale",
|
||||||
|
"alarm_AbnormalOutputFrequency": "Fréquence de sortie anormale",
|
||||||
|
"alarm_AbnormalNullLine": "Ligne neutre anormale",
|
||||||
|
"alarm_AbnormalOffGridOutputVoltage": "Tension de sortie hors réseau anormale",
|
||||||
|
"alarm_ExcessivelyHighAmbientTemperature": "Température ambiante trop élevée",
|
||||||
|
"alarm_ExcessiveRadiatorTemperature": "Température excessive du radiateur",
|
||||||
|
"alarm_PcbOvertemperature": "Température excessive PCB",
|
||||||
|
"alarm_DcConverterOvertemperature": "Température excessive convertisseur DC",
|
||||||
|
"alarm_InverterOvertemperatureAlarm": "Alarme température onduleur",
|
||||||
|
"alarm_InverterOvertemperature": "Température onduleur excessive",
|
||||||
|
"alarm_DcConverterOvertemperatureAlarm": "Alarme surchauffe convertisseur DC",
|
||||||
|
"alarm_InsulationFault": "Défaut d'isolation",
|
||||||
|
"alarm_LeakageProtectionFault": "Défaut protection fuite",
|
||||||
|
"alarm_AbnormalLeakageSelfCheck": "Auto-test fuite anormale",
|
||||||
|
"alarm_PoorGrounding": "Mise à la terre insuffisante",
|
||||||
|
"alarm_FanFault": "Défaut du ventilateur",
|
||||||
|
"alarm_AuxiliaryPowerFault": "Défaut d'alimentation auxiliaire",
|
||||||
|
"alarm_ModelCapacityFault": "Défaut de configuration",
|
||||||
|
"alarm_AbnormalLightningArrester": "Paratonnerre défectueux",
|
||||||
|
"alarm_IslandProtection": "Protection d'îlotage",
|
||||||
|
"alarm_Battery1NotConnected": "Batterie 1 non connectée",
|
||||||
|
"alarm_Battery1Overvoltage": "Tension batterie 1 trop élevée",
|
||||||
|
"alarm_Battery1Undervoltage": "Tension batterie 1 trop basse",
|
||||||
|
"alarm_Battery1DischargeEnd": "Fin de décharge batterie 1",
|
||||||
|
"alarm_Battery1Inverted": "Polarité batterie 1 inversée",
|
||||||
|
"alarm_Battery1OverloadTimeout": "Dépassement de charge Batterie 1",
|
||||||
|
"alarm_Battery1SoftStartFailure": "Échec démarrage Batterie 1",
|
||||||
|
"alarm_Battery1PowerTubeFault": "Défaut électronique Batterie 1",
|
||||||
|
"alarm_Battery1InsufficientPower": "Puissance insuffisante Batterie 1",
|
||||||
|
"alarm_Battery1BackupProhibited": "Sauvegarde interdite Batterie 1",
|
||||||
|
"alarm_Battery2NotConnected": "Batterie 2 non connectée",
|
||||||
|
"alarm_Battery2Overvoltage": "Tension batterie 2 élevée",
|
||||||
|
"alarm_Battery2Undervoltage": "Tension batterie 2 basse",
|
||||||
|
"alarm_Battery2DischargeEnd": "Fin décharge batterie 2",
|
||||||
|
"alarm_Battery2Inverted": "Polarité batterie 2 inversée",
|
||||||
|
"alarm_Battery2OverloadTimeout": "Dépassement de charge Batterie 2",
|
||||||
|
"alarm_Battery2SoftStartFailure": "Échec démarrage Batterie 2",
|
||||||
|
"alarm_Battery2PowerTubeFault": "Défaut électronique Batterie 2",
|
||||||
|
"alarm_Battery2InsufficientPower": "Puissance insuffisante Batterie 2",
|
||||||
|
"alarm_Battery2BackupProhibited": "Sauvegarde interdite Batterie 2",
|
||||||
|
"alarm_LithiumBattery1ChargeForbidden": "Charge batterie lithium 1 interdite",
|
||||||
|
"alarm_LithiumBattery1DischargeForbidden": "Décharge batterie lithium 1 interdite",
|
||||||
|
"alarm_LithiumBattery2ChargeForbidden": "Charge batterie lithium 2 interdite",
|
||||||
|
"alarm_LithiumBattery2DischargeForbidden": "Décharge batterie lithium 2 interdite",
|
||||||
|
"alarm_LithiumBattery1Full": "Batterie lithium 1 pleine",
|
||||||
|
"alarm_LithiumBattery1DischargeEnd": "Fin de décharge batterie lithium 1",
|
||||||
|
"alarm_LithiumBattery2Full": "Batterie lithium 2 pleine",
|
||||||
|
"alarm_LithiumBattery2DischargeEnd": "Fin de décharge batterie lithium 2",
|
||||||
|
"alarm_LeadBatteryTemperatureAbnormality": "Température anormale batterie plomb",
|
||||||
|
"alarm_BatteryAccessMethodError": "Erreur de méthode d'accès batterie",
|
||||||
|
"alarm_Pv1NotAccessed": "Chaîne PV1 non accessible",
|
||||||
|
"alarm_Pv1Overvoltage": "Survoltage PV1",
|
||||||
|
"alarm_AbnormalPv1CurrentSharing": "Partage de courant PV1 anormal",
|
||||||
|
"alarm_Pv1PowerTubeFault": "Défaut du tube de puissance PV1",
|
||||||
|
"alarm_Pv1SoftStartFailure": "Échec de démarrage doux PV1",
|
||||||
|
"alarm_Pv1OverloadTimeout": "Dépassement de charge PV1",
|
||||||
|
"alarm_Pv1InsufficientPower": "Puissance PV1 insuffisante",
|
||||||
|
"alarm_Photovoltaic1Overcurrent": "Surintensité PV1",
|
||||||
|
"alarm_Pv2NotAccessed": "Chaîne PV2 inaccessible",
|
||||||
|
"alarm_Pv2Overvoltage": "Survoltage PV2",
|
||||||
|
"alarm_AbnormalPv2CurrentSharing": "Partage de courant anormal PV2",
|
||||||
|
"alarm_Pv2PowerTubeFault": "Défaillance du tube de puissance PV2",
|
||||||
|
"alarm_Pv2SoftStartFailure": "Échec de démarrage progressif PV2",
|
||||||
|
"alarm_Pv2OverloadTimeout": "Dépassement de charge PV2",
|
||||||
|
"alarm_Pv2InsufficientPower": "Puissance insuffisante PV2",
|
||||||
|
"alarm_Pv3NotConnected": "PV3 non connecté",
|
||||||
|
"alarm_Pv3Overvoltage": "Survoltage PV3",
|
||||||
|
"alarm_Pv3AverageCurrentAnomaly": "Anomalie courant PV3",
|
||||||
|
"alarm_Pv3PowerTubeFailure": "Défaillance tube PV3",
|
||||||
|
"alarm_Pv3SoftStartFailure": "Échec démarrage PV3",
|
||||||
|
"alarm_Pv3OverloadTimeout": "Dépassement de charge PV3",
|
||||||
|
"alarm_Pv3ReverseConnection": "Connexion inversée PV3",
|
||||||
|
"alarm_Pv4NotConnected": "Chaîne PV4 non connectée",
|
||||||
|
"alarm_Pv4Overvoltage": "Survoltage PV4",
|
||||||
|
"alarm_Pv4AverageCurrentAnomaly": "Anomalie de courant PV4",
|
||||||
|
"alarm_Pv4PowerTubeFailure": "Défaillance du tube de puissance PV4",
|
||||||
|
"alarm_Pv4SoftStartFailure": "Échec du démarrage progressif PV4",
|
||||||
|
"alarm_Pv4OverloadTimeout": "Dépassement de charge PV4",
|
||||||
|
"alarm_Pv4ReverseConnection": "Connexion inversée PV4",
|
||||||
|
"alarm_InsufficientPhotovoltaicPower": "Puissance photovoltaïque insuffisante",
|
||||||
|
"alarm_DcBusOvervoltage": "Tension DC trop élevée",
|
||||||
|
"alarm_DcBusUndervoltage": "Tension DC trop basse",
|
||||||
|
"alarm_DcBusVoltageUnbalance": "Déséquilibre tension DC",
|
||||||
|
"alarm_BusSlowOvervoltage": "Tension DC lente excessive",
|
||||||
|
"alarm_HardwareBusOvervoltage": "Tension DC critique",
|
||||||
|
"alarm_BusSoftStartFailure": "Échec démarrage progressif",
|
||||||
|
"alarm_InverterPowerTubeFault": "Défaut tube de puissance",
|
||||||
|
"alarm_HardwareOvercurrent": "Surintensité matérielle",
|
||||||
|
"alarm_DcConverterOvervoltage": "Survoltage convertisseur DC",
|
||||||
|
"alarm_DcConverterHardwareOvervoltage": "Survoltage matériel convertisseur DC",
|
||||||
|
"alarm_DcConverterOvercurrent": "Surintensité convertisseur CC",
|
||||||
|
"alarm_DcConverterHardwareOvercurrent": "Surintensité matérielle convertisseur CC",
|
||||||
|
"alarm_DcConverterResonatorOvercurrent": "Surintensité résonateur convertisseur CC",
|
||||||
|
"alarm_SystemOutputOverload": "Surcharge de sortie système",
|
||||||
|
"alarm_InverterOverload": "Surcharge onduleur",
|
||||||
|
"alarm_InverterOverloadTimeout": "Dépassement de charge de l'onduleur",
|
||||||
|
"alarm_LoadPowerOverload": "Surcharge de puissance de charge",
|
||||||
|
"alarm_BalancedCircuitOverloadTimeout": "Dépassement de charge du circuit équilibré",
|
||||||
|
"alarm_InverterSoftStartFailure": "Échec de démarrage progressif de l'onduleur",
|
||||||
|
"alarm_Dsp1ParameterSettingFault": "Défaillance de paramétrage DSP 1",
|
||||||
|
"alarm_Dsp2ParameterSettingFault": "Paramètre DSP2 incorrect",
|
||||||
|
"alarm_DspVersionCompatibilityFault": "Incompatibilité version DSP",
|
||||||
|
"alarm_CpldVersionCompatibilityFault": "Incompatibilité version CPLD",
|
||||||
|
"alarm_CpldCommunicationFault": "Échec communication CPLD",
|
||||||
|
"alarm_DspCommunicationFault": "Échec communication DSP",
|
||||||
|
"alarm_OutputVoltageDcOverlimit": "Tension de sortie DC excessive",
|
||||||
|
"alarm_OutputCurrentDcOverlimit": "Courant de sortie DC excessif",
|
||||||
|
"alarm_RelaySelfCheckFails": "Auto-test relais échoué",
|
||||||
|
"alarm_InverterRelayOpen": "Relais de l'onduleur ouvert",
|
||||||
|
"alarm_InverterRelayShortCircuit": "Relais de l'onduleur en court-circuit",
|
||||||
|
"alarm_OpenCircuitOfPowerGridRelay": "Relais du réseau ouvert",
|
||||||
|
"alarm_ShortCircuitOfPowerGridRelay": "Court-circuit du relais réseau",
|
||||||
|
"alarm_GeneratorRelayOpenCircuit": "Relais du générateur ouvert",
|
||||||
|
"alarm_GeneratorRelayShortCircuit": "Court-circuit du relais générateur",
|
||||||
|
"alarm_AbnormalInverter": "Onduleur anormal",
|
||||||
|
"alarm_ParallelCommunicationAlarm": "Alarme de communication parallèle",
|
||||||
|
"alarm_ParallelModuleMissing": "Module parallèle manquant",
|
||||||
|
"alarm_DuplicateMachineNumbersForParallelModules": "Numéros de machine en double",
|
||||||
|
"alarm_ParameterConflictInParallelModule": "Conflit de paramètres parallèle",
|
||||||
|
"alarm_SystemDerating": "Réduction de puissance du système",
|
||||||
|
"alarm_PvAccessMethodErrorAlarm": "Erreur méthode d'accès PV",
|
||||||
|
"alarm_ReservedAlarms4": "Alarme réservée 4",
|
||||||
|
"alarm_ReservedAlarms5": "Alarme réservée 5",
|
||||||
|
"alarm_ReverseMeterConnection": "Connexion du compteur inversée",
|
||||||
|
"alarm_InverterSealPulse": "Impulsion de scellement de l'onduleur",
|
||||||
|
"alarm_AbnormalDieselGeneratorVoltage": "Tension anormale du générateur diesel",
|
||||||
|
"alarm_AbnormalDieselGeneratorFrequency": "Fréquence anormale du générateur diesel",
|
||||||
|
"alarm_DieselGeneratorVoltageReverseSequence": "Séquence de phase inversée du générateur",
|
||||||
|
"alarm_DieselGeneratorVoltageOutOfPhase": "Déphasage du générateur",
|
||||||
|
"alarm_GeneratorOverload": "Surcharge du générateur",
|
||||||
|
"alarm_StringFault": "Défaut de chaîne",
|
||||||
|
"alarm_PvStringPidQuickConnectAbnormal": "Connexion rapide anormale",
|
||||||
|
"alarm_DcSpdFunctionAbnormal": "Problème de protection DC",
|
||||||
|
"alarm_PvShortCircuited": "Court-circuit PV",
|
||||||
|
"alarm_PvBoostDriverAbnormal": "Problème de convertisseur",
|
||||||
|
"alarm_AcSpdFunctionAbnormal": "Problème de protection contre les surtensions AC",
|
||||||
|
"alarm_DcFuseBlown": "Fusible DC grillé",
|
||||||
|
"alarm_DcInputVoltageTooHigh": "Tension DC d'entrée trop élevée",
|
||||||
|
"alarm_PvReversed": "Polarité PV inversée",
|
||||||
|
"alarm_PidFunctionAbnormal": "Problème de fonction PID",
|
||||||
|
"alarm_PvStringDisconnected": "Chaîne PV déconnectée",
|
||||||
|
"alarm_PvStringCurrentUnbalanced": "Déséquilibre de courant PV",
|
||||||
|
"alarm_NoUtilityGrid": "Réseau électrique absent",
|
||||||
|
"alarm_GridVoltageOutOfRange": "Tension réseau hors plage",
|
||||||
|
"alarm_GridFrequencyOutOfRange": "Fréquence réseau hors plage",
|
||||||
|
"alarm_Overload": "Surcharge",
|
||||||
|
"alarm_MeterDisconnected": "Compteur déconnecté",
|
||||||
|
"alarm_MeterReverselyConnected": "Compteur inversé",
|
||||||
|
"alarm_LinePeVoltageAbnormal": "Tension anormale",
|
||||||
|
"alarm_PhaseSequenceError": "Séquence de phase erronée",
|
||||||
|
"alarm_FanFailure": "Défaillance du ventilateur",
|
||||||
|
"alarm_MeterAbnormal": "Compteur anormal",
|
||||||
|
"alarm_OptimizerCommunicationAbnormal": "Communication optimiseur anormale",
|
||||||
|
"alarm_OverTemperature": "Température excessive",
|
||||||
|
"alarm_OverTemperatureAlarm": "Alarme température élevée",
|
||||||
|
"alarm_NtcTemperatureSensorBroken": "Capteur de température défectueux",
|
||||||
|
"alarm_SyncSignalAbnormal": "Signal de synchronisation anormal",
|
||||||
|
"alarm_GridStartupConditionsNotMet": "Conditions de démarrage réseau non remplies",
|
||||||
|
"alarm_BatteryCommunicationFailure": "Échec de communication batterie",
|
||||||
|
"alarm_BatteryDisconnected": "Batterie déconnectée",
|
||||||
|
"alarm_BatteryVoltageTooHigh": "Tension batterie trop élevée",
|
||||||
|
"alarm_BatteryVoltageTooLow": "Tension batterie trop basse",
|
||||||
|
"alarm_BatteryReverseConnected": "Batterie branchée à l'envers",
|
||||||
|
"alarm_LeadAcidTempSensorDisconnected": "Capteur température batterie plomb désactivé",
|
||||||
|
"alarm_BatteryTemperatureOutOfRange": "Température batterie hors plage",
|
||||||
|
"alarm_BmsFault": "Défaillance BMS",
|
||||||
|
"alarm_LithiumBatteryOverload": "Surcharge batterie lithium",
|
||||||
|
"alarm_BmsCommunicationAbnormal": "Communication BMS anormale",
|
||||||
|
"alarm_BatterySpdAbnormal": "Défaillance SPD batterie",
|
||||||
|
"alarm_OutputDcComponentBiasAbnormal": "Biais DC de sortie anormal",
|
||||||
|
"alarm_DcComponentOverHighOutputVoltage": "Tension de sortie trop élevée",
|
||||||
|
"alarm_OffGridOutputVoltageTooLow": "Tension de sortie hors réseau trop basse",
|
||||||
|
"alarm_OffGridOutputVoltageTooHigh": "Tension de sortie hors réseau trop élevée",
|
||||||
|
"alarm_OffGridOutputOverCurrent": "Courant de sortie hors réseau trop élevé",
|
||||||
|
"alarm_OffGridOutputOverload": "Surcharge sortie hors réseau",
|
||||||
|
"alarm_BalancedCircuitAbnormal": "Circuit équilibré anormal",
|
||||||
|
"alarm_ExportLimitationFailSafe": "Sécurité limite d'exportation",
|
||||||
|
"alarm_DcBiasAbnormal": "Biais DC anormal",
|
||||||
|
"alarm_HighDcComponentOutputCurrent": "Composante DC élevée courant de sortie",
|
||||||
|
"alarm_BusVoltageSamplingAbnormal": "Tension d'alimentation anormale",
|
||||||
|
"alarm_RelayFault": "Défaillance du relais",
|
||||||
|
"alarm_BusVoltageAbnormal": "Tension d'alimentation anormale",
|
||||||
|
"alarm_InternalCommunicationFailure": "Échec de communication interne",
|
||||||
|
"alarm_TemperatureSensorDisconnected": "Capteur de température déconnecté",
|
||||||
|
"alarm_IgbtDriveFault": "Défaillance de l'IGBT",
|
||||||
|
"alarm_EepromError": "Erreur EEPROM",
|
||||||
|
"alarm_AuxiliaryPowerAbnormal": "Alimentation auxiliaire anormale",
|
||||||
|
"alarm_DcAcOvercurrentProtection": "Protection contre les surintensités",
|
||||||
|
"alarm_CommunicationProtocolMismatch": "Incompatibilité de protocole",
|
||||||
|
"alarm_DspComFirmwareMismatch": "Incompatibilité firmware DSP/COM",
|
||||||
|
"alarm_DspSoftwareHardwareMismatch": "Incompatibilité logiciel DSP/matériel",
|
||||||
|
"alarm_CpldAbnormal": "CPLD anormal",
|
||||||
|
"alarm_RedundancySamplingInconsistent": "Échantillonnage redondant incohérent",
|
||||||
|
"alarm_PwmPassThroughSignalFailure": "Échec signal PWM",
|
||||||
|
"alarm_AfciSelfTestFailure": "Échec auto-test AFCI",
|
||||||
|
"alarm_PvCurrentSamplingAbnormal": "Mesure PV anormale",
|
||||||
|
"alarm_AcCurrentSamplingAbnormal": "Mesure AC anormale",
|
||||||
|
"alarm_BusSoftbootFailure": "Échec démarrage DC",
|
||||||
|
"alarm_EpoFault": "Défaillance EPO",
|
||||||
|
"alarm_MonitoringChipBootVerificationFailed": "Échec vérification démarrage",
|
||||||
|
"alarm_BmsCommunicationFailure": "Échec communication BMS",
|
||||||
|
"alarm_BmsChargeDischargeFailure": "Échec charge/décharge BMS",
|
||||||
|
"alarm_BatteryVoltageLow": "Tension batterie faible",
|
||||||
|
"alarm_BatteryVoltageHigh": "Tension batterie élevée",
|
||||||
|
"alarm_BatteryTemperatureAbnormal": "Température anormale de la batterie",
|
||||||
|
"alarm_BatteryReversed": "Batterie inversée",
|
||||||
|
"alarm_BatteryOpenCircuit": "Circuit batterie ouvert",
|
||||||
|
"alarm_BatteryOverloadProtection": "Protection contre la surcharge",
|
||||||
|
"alarm_Bus2VoltageAbnormal": "Tension anormale Bus2",
|
||||||
|
"alarm_BatteryChargeOcp": "Surintensité charge batterie",
|
||||||
|
"alarm_BatteryDischargeOcp": "Surintensité décharge batterie",
|
||||||
|
"alarm_BatterySoftStartFailed": "Démarrage en douceur échoué",
|
||||||
|
"alarm_EpsOutputShortCircuited": "Circuit de secours en court-circuit",
|
||||||
|
"alarm_OffGridBusVoltageLow": "Tension bus hors réseau basse",
|
||||||
|
"alarm_OffGridTerminalVoltageAbnormal": "Tension anormale terminal hors réseau",
|
||||||
|
"alarm_SoftStartFailed": "Démarrage progressif échoué",
|
||||||
|
"alarm_OffGridOutputVoltageAbnormal": "Tension de sortie hors réseau anormale",
|
||||||
|
"alarm_BalancedCircuitSelfTestFailed": "Autotest circuit équilibré échoué",
|
||||||
|
"alarm_HighDcComponentOutputVoltage": "Tension de sortie à composante CC élevée",
|
||||||
|
"alarm_OffGridParallelSignalAbnormal": "Signal parallèle hors réseau anormal",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
{
|
||||||
|
"alarm_AbnormalGridVoltage": "Tensione di rete anomala",
|
||||||
|
"alarm_AbnormalGridFrequency": "Frequenza di rete anomala",
|
||||||
|
"alarm_InvertedSequenceOfGridVoltage": "Sequenza di fase invertita",
|
||||||
|
"alarm_GridVoltagePhaseLoss": "Mancanza di fase rete",
|
||||||
|
"alarm_AbnormalGridCurrent": "Corrente di rete anomala",
|
||||||
|
"alarm_AbnormalOutputVoltage": "Tensione di uscita anomala",
|
||||||
|
"alarm_AbnormalOutputFrequency": "Frequenza di uscita anomala",
|
||||||
|
"alarm_AbnormalNullLine": "Linea neutra anomala",
|
||||||
|
"alarm_AbnormalOffGridOutputVoltage": "Tensione di uscita in standby anomala",
|
||||||
|
"alarm_ExcessivelyHighAmbientTemperature": "Temperatura ambientale troppo alta",
|
||||||
|
"alarm_ExcessiveRadiatorTemperature": "Temperatura radiatore troppo alta",
|
||||||
|
"alarm_PcbOvertemperature": "Scheda elettronica troppo calda",
|
||||||
|
"alarm_DcConverterOvertemperature": "Sovratemperatura convertitore DC",
|
||||||
|
"alarm_InverterOvertemperatureAlarm": "Allarme surriscaldamento inverter",
|
||||||
|
"alarm_InverterOvertemperature": "Surriscaldamento inverter",
|
||||||
|
"alarm_DcConverterOvertemperatureAlarm": "Allarme sovratemperatura convertitore DC",
|
||||||
|
"alarm_InsulationFault": "Guasto isolamento",
|
||||||
|
"alarm_LeakageProtectionFault": "Guasto protezione dispersione",
|
||||||
|
"alarm_AbnormalLeakageSelfCheck": "Autocontrollo perdite anomalo",
|
||||||
|
"alarm_PoorGrounding": "Messa a terra insufficiente",
|
||||||
|
"alarm_FanFault": "Guasto ventilatore",
|
||||||
|
"alarm_AuxiliaryPowerFault": "Guasto Alimentazione Ausiliaria",
|
||||||
|
"alarm_ModelCapacityFault": "Guasto Configurazione Modello",
|
||||||
|
"alarm_AbnormalLightningArrester": "Parasurtense Anomalo",
|
||||||
|
"alarm_IslandProtection": "Protezione Isola",
|
||||||
|
"alarm_Battery1NotConnected": "Batteria 1 Non Connessa",
|
||||||
|
"alarm_Battery1Overvoltage": "Batteria 1 Sovratensione",
|
||||||
|
"alarm_Battery1Undervoltage": "Batteria 1 sottotensione",
|
||||||
|
"alarm_Battery1DischargeEnd": "Fine scarica batteria 1",
|
||||||
|
"alarm_Battery1Inverted": "Batteria 1 invertita",
|
||||||
|
"alarm_Battery1OverloadTimeout": "Tempo di sovraccarico batteria 1",
|
||||||
|
"alarm_Battery1SoftStartFailure": "Avvio morbido batteria 1 fallito",
|
||||||
|
"alarm_Battery1PowerTubeFault": "Guasto modulo di potenza batteria 1",
|
||||||
|
"alarm_Battery1InsufficientPower": "Batteria 1 Potenza Insufficiente",
|
||||||
|
"alarm_Battery1BackupProhibited": "Backup Batteria 1 Bloccato",
|
||||||
|
"alarm_Battery2NotConnected": "Batteria 2 Non Connessa",
|
||||||
|
"alarm_Battery2Overvoltage": "Sovratensione Batteria 2",
|
||||||
|
"alarm_Battery2Undervoltage": "Sottotensione Batteria 2",
|
||||||
|
"alarm_Battery2DischargeEnd": "Fine Scarica Batteria 2",
|
||||||
|
"alarm_Battery2Inverted": "Polarità batteria 2 invertita",
|
||||||
|
"alarm_Battery2OverloadTimeout": "Sovraccarico batteria 2",
|
||||||
|
"alarm_Battery2SoftStartFailure": "Avvio batteria 2 fallito",
|
||||||
|
"alarm_Battery2PowerTubeFault": "Guasto modulo potenza batteria 2",
|
||||||
|
"alarm_Battery2InsufficientPower": "Potenza insufficiente batteria 2",
|
||||||
|
"alarm_Battery2BackupProhibited": "Backup vietato batteria 2",
|
||||||
|
"alarm_LithiumBattery1ChargeForbidden": "Carica Batteria Litio 1 Bloccata",
|
||||||
|
"alarm_LithiumBattery1DischargeForbidden": "Scarica Batteria Litio 1 Bloccata",
|
||||||
|
"alarm_LithiumBattery2ChargeForbidden": "Carica Batteria Litio 2 Bloccata",
|
||||||
|
"alarm_LithiumBattery2DischargeForbidden": "Scarica Batteria Litio 2 Bloccata",
|
||||||
|
"alarm_LithiumBattery1Full": "Batteria Litio 1 Piena",
|
||||||
|
"alarm_LithiumBattery1DischargeEnd": "Fine Scarica Batteria Litio 1",
|
||||||
|
"alarm_LithiumBattery2Full": "Batteria Litio 2 Piena",
|
||||||
|
"alarm_LithiumBattery2DischargeEnd": "Fine Scarica Batteria 2",
|
||||||
|
"alarm_LeadBatteryTemperatureAbnormality": "Temperatura Batteria Anomala",
|
||||||
|
"alarm_BatteryAccessMethodError": "Errore Metodo Accesso Batteria",
|
||||||
|
"alarm_Pv1NotAccessed": "PV1 Non Rilevato",
|
||||||
|
"alarm_Pv1Overvoltage": "Sovratensione PV1",
|
||||||
|
"alarm_AbnormalPv1CurrentSharing": "Corrente PV1 anomala",
|
||||||
|
"alarm_Pv1PowerTubeFault": "Guasto tubo di potenza PV1",
|
||||||
|
"alarm_Pv1SoftStartFailure": "Avvio morbido PV1 fallito",
|
||||||
|
"alarm_Pv1OverloadTimeout": "Sovraccarico PV1",
|
||||||
|
"alarm_Pv1InsufficientPower": "Bassa potenza PV1",
|
||||||
|
"alarm_Photovoltaic1Overcurrent": "Sovracorrente PV1",
|
||||||
|
"alarm_Pv2NotAccessed": "PV2 non accessibile",
|
||||||
|
"alarm_Pv2Overvoltage": "Sovratensione PV2",
|
||||||
|
"alarm_AbnormalPv2CurrentSharing": "Condivisione corrente PV2 anomala",
|
||||||
|
"alarm_Pv2PowerTubeFault": "Guasto Tubo di Potenza PV2",
|
||||||
|
"alarm_Pv2SoftStartFailure": "Avvio Morbido PV2 Fallito",
|
||||||
|
"alarm_Pv2OverloadTimeout": "Sovraccarico PV2 Scaduto",
|
||||||
|
"alarm_Pv2InsufficientPower": "Potenza PV2 insufficiente",
|
||||||
|
"alarm_Pv3NotConnected": "PV3 non connesso",
|
||||||
|
"alarm_Pv3Overvoltage": "Sovratensione PV3",
|
||||||
|
"alarm_Pv3AverageCurrentAnomaly": "Anomalia Corrente Media PV3",
|
||||||
|
"alarm_Pv3PowerTubeFailure": "Guasto Tubo di Potenza PV3",
|
||||||
|
"alarm_Pv3SoftStartFailure": "Guasto Avvio Morbido PV3",
|
||||||
|
"alarm_Pv3OverloadTimeout": "Sovraccarico Pv3",
|
||||||
|
"alarm_Pv3ReverseConnection": "Collegamento Inverso Pv3",
|
||||||
|
"alarm_Pv4NotConnected": "Pv4 Non Collegato",
|
||||||
|
"alarm_Pv4Overvoltage": "Sovratensione PV4",
|
||||||
|
"alarm_Pv4AverageCurrentAnomaly": "Anomalia Corrente Media PV4",
|
||||||
|
"alarm_Pv4PowerTubeFailure": "Guasto Modulo di Potenza PV4",
|
||||||
|
"alarm_Pv4SoftStartFailure": "Avvio morbido fallito PV4",
|
||||||
|
"alarm_Pv4OverloadTimeout": "Sovraccarico prolungato PV4",
|
||||||
|
"alarm_Pv4ReverseConnection": "Connessione invertita PV4",
|
||||||
|
"alarm_InsufficientPhotovoltaicPower": "Potenza fotovoltaica insufficiente",
|
||||||
|
"alarm_DcBusOvervoltage": "Sovratensione bus DC",
|
||||||
|
"alarm_DcBusUndervoltage": "Sottotensione bus DC",
|
||||||
|
"alarm_DcBusVoltageUnbalance": "Squilibrio tensione DC",
|
||||||
|
"alarm_BusSlowOvervoltage": "Sovratensione lenta del bus",
|
||||||
|
"alarm_HardwareBusOvervoltage": "Sovratensione hardware del bus",
|
||||||
|
"alarm_BusSoftStartFailure": "Avvio morbido fallito",
|
||||||
|
"alarm_InverterPowerTubeFault": "Guasto modulo inverter",
|
||||||
|
"alarm_HardwareOvercurrent": "Sovracorrente hardware",
|
||||||
|
"alarm_DcConverterOvervoltage": "Sovratensione convertitore DC",
|
||||||
|
"alarm_DcConverterHardwareOvervoltage": "Protezione sovratensione hardware",
|
||||||
|
"alarm_DcConverterOvercurrent": "Sovracorrente convertitore DC",
|
||||||
|
"alarm_DcConverterHardwareOvercurrent": "Sovracorrente hardware convertitore DC",
|
||||||
|
"alarm_DcConverterResonatorOvercurrent": "Sovracorrente risonatore convertitore DC",
|
||||||
|
"alarm_SystemOutputOverload": "Sovraccarico uscita sistema",
|
||||||
|
"alarm_InverterOverload": "Sovraccarico Inverter",
|
||||||
|
"alarm_InverterOverloadTimeout": "Sovraccarico Inverter Prolungato",
|
||||||
|
"alarm_LoadPowerOverload": "Carico Elettrico Eccessivo",
|
||||||
|
"alarm_BalancedCircuitOverloadTimeout": "Sovraccarico circuito bilanciato",
|
||||||
|
"alarm_InverterSoftStartFailure": "Avvio inverter fallito",
|
||||||
|
"alarm_Dsp1ParameterSettingFault": "Parametri DSP1 errati",
|
||||||
|
"alarm_Dsp2ParameterSettingFault": "Errore configurazione parametri DSP 2",
|
||||||
|
"alarm_DspVersionCompatibilityFault": "Errore compatibilità versione DSP",
|
||||||
|
"alarm_CpldVersionCompatibilityFault": "Errore compatibilità versione CPLD",
|
||||||
|
"alarm_CpldCommunicationFault": "Guasto comunicazione CPLD",
|
||||||
|
"alarm_DspCommunicationFault": "Guasto comunicazione DSP",
|
||||||
|
"alarm_OutputVoltageDcOverlimit": "Tensione DC in uscita eccessiva",
|
||||||
|
"alarm_OutputCurrentDcOverlimit": "Corrente DC in uscita superata",
|
||||||
|
"alarm_RelaySelfCheckFails": "Autotest relè fallito",
|
||||||
|
"alarm_InverterRelayOpen": "Relè inverter aperto",
|
||||||
|
"alarm_InverterRelayShortCircuit": "Cortocircuito del relè dell'inverter",
|
||||||
|
"alarm_OpenCircuitOfPowerGridRelay": "Relè di rete aperto",
|
||||||
|
"alarm_ShortCircuitOfPowerGridRelay": "Cortocircuito del relè di rete",
|
||||||
|
"alarm_GeneratorRelayOpenCircuit": "Relè generatore aperto",
|
||||||
|
"alarm_GeneratorRelayShortCircuit": "Relè generatore corto circuito",
|
||||||
|
"alarm_AbnormalInverter": "Inverter anomalo",
|
||||||
|
"alarm_ParallelCommunicationAlarm": "Allarme Comunicazione Parallela",
|
||||||
|
"alarm_ParallelModuleMissing": "Modulo Parallelo Mancante",
|
||||||
|
"alarm_DuplicateMachineNumbersForParallelModules": "Numeri Duplicati Moduli Paralleli",
|
||||||
|
"alarm_ParameterConflictInParallelModule": "Conflitto parametri modulo parallelo",
|
||||||
|
"alarm_SystemDerating": "Riduzione prestazioni sistema",
|
||||||
|
"alarm_PvAccessMethodErrorAlarm": "Errore metodo accesso PV",
|
||||||
|
"alarm_ReservedAlarms4": "Allarme Riservato 4",
|
||||||
|
"alarm_ReservedAlarms5": "Allarme Riservato 5",
|
||||||
|
"alarm_ReverseMeterConnection": "Contatore Inverso",
|
||||||
|
"alarm_InverterSealPulse": "Impulso Sigillo Inverter",
|
||||||
|
"alarm_AbnormalDieselGeneratorVoltage": "Tensione Generatore Diesel Anomala",
|
||||||
|
"alarm_AbnormalDieselGeneratorFrequency": "Frequenza Generatore Diesel Anomala",
|
||||||
|
"alarm_DieselGeneratorVoltageReverseSequence": "Sequenza di fase invertita",
|
||||||
|
"alarm_DieselGeneratorVoltageOutOfPhase": "Fase del generatore errata",
|
||||||
|
"alarm_GeneratorOverload": "Sovraccarico del generatore",
|
||||||
|
"alarm_StringFault": "Guasto alla stringa",
|
||||||
|
"alarm_PvStringPidQuickConnectAbnormal": "Connessione rapida anomala",
|
||||||
|
"alarm_DcSpdFunctionAbnormal": "Protezione sovratensione DC anomala",
|
||||||
|
"alarm_PvShortCircuited": "Cortocircuito PV",
|
||||||
|
"alarm_PvBoostDriverAbnormal": "Anomalia driver di boost PV",
|
||||||
|
"alarm_AcSpdFunctionAbnormal": "Anomalia protezione da sovratensioni AC",
|
||||||
|
"alarm_DcFuseBlown": "Fusibile DC saltato",
|
||||||
|
"alarm_DcInputVoltageTooHigh": "Tensione DC troppo alta",
|
||||||
|
"alarm_PvReversed": "Polarità PV invertita",
|
||||||
|
"alarm_PidFunctionAbnormal": "Funzione PID Anomala",
|
||||||
|
"alarm_PvStringDisconnected": "Stringa PV Disconnessa",
|
||||||
|
"alarm_PvStringCurrentUnbalanced": "Corrente Stringa PV Squilibrata",
|
||||||
|
"alarm_NoUtilityGrid": "Nessuna rete elettrica",
|
||||||
|
"alarm_GridVoltageOutOfRange": "Tensione di rete fuori limite",
|
||||||
|
"alarm_GridFrequencyOutOfRange": "Frequenza di rete fuori limite",
|
||||||
|
"alarm_Overload": "Sovraccarico",
|
||||||
|
"alarm_MeterDisconnected": "Contatore scollegato",
|
||||||
|
"alarm_MeterReverselyConnected": "Contatore collegato inversamente",
|
||||||
|
"alarm_LinePeVoltageAbnormal": "Tensione PE anomala",
|
||||||
|
"alarm_PhaseSequenceError": "Errore sequenza fase",
|
||||||
|
"alarm_FanFailure": "Guasto ventola",
|
||||||
|
"alarm_MeterAbnormal": "Contatore Anomalo",
|
||||||
|
"alarm_OptimizerCommunicationAbnormal": "Comunicazione Ottimizzatore Anomala",
|
||||||
|
"alarm_OverTemperature": "Temperatura Eccessiva",
|
||||||
|
"alarm_OverTemperatureAlarm": "Allarme Temperatura Elevata",
|
||||||
|
"alarm_NtcTemperatureSensorBroken": "Sensore Temperatura NTC Guasto",
|
||||||
|
"alarm_SyncSignalAbnormal": "Segnale di Sincronizzazione Anomalo",
|
||||||
|
"alarm_GridStartupConditionsNotMet": "Condizioni di avvio rete non soddisfatte",
|
||||||
|
"alarm_BatteryCommunicationFailure": "Comunicazione batteria fallita",
|
||||||
|
"alarm_BatteryDisconnected": "Batteria scollegata",
|
||||||
|
"alarm_BatteryVoltageTooHigh": "Tensione batteria troppo alta",
|
||||||
|
"alarm_BatteryVoltageTooLow": "Tensione batteria troppo bassa",
|
||||||
|
"alarm_BatteryReverseConnected": "Batteria collegata al contrario",
|
||||||
|
"alarm_LeadAcidTempSensorDisconnected": "Sensore temperatura disconnesso",
|
||||||
|
"alarm_BatteryTemperatureOutOfRange": "Temperatura batteria anomala",
|
||||||
|
"alarm_BmsFault": "Guasto BMS",
|
||||||
|
"alarm_LithiumBatteryOverload": "Sovraccarico batteria litio",
|
||||||
|
"alarm_BmsCommunicationAbnormal": "Comunicazione BMS anomala",
|
||||||
|
"alarm_BatterySpdAbnormal": "SPD batteria anomalo",
|
||||||
|
"alarm_OutputDcComponentBiasAbnormal": "Bias DC anomalo in uscita",
|
||||||
|
"alarm_DcComponentOverHighOutputVoltage": "Tensione di uscita troppo alta",
|
||||||
|
"alarm_OffGridOutputVoltageTooLow": "Tensione di uscita troppo bassa",
|
||||||
|
"alarm_OffGridOutputVoltageTooHigh": "Tensione in uscita troppo alta",
|
||||||
|
"alarm_OffGridOutputOverCurrent": "Corrente in uscita eccessiva",
|
||||||
|
"alarm_OffGridOutputOverload": "Sovraccarico uscita off-grid",
|
||||||
|
"alarm_BalancedCircuitAbnormal": "Circuiti squilibrati anomali",
|
||||||
|
"alarm_ExportLimitationFailSafe": "Limite esportazione sicurezza",
|
||||||
|
"alarm_DcBiasAbnormal": "Bias DC anomalo",
|
||||||
|
"alarm_HighDcComponentOutputCurrent": "Corrente di uscita DC elevata",
|
||||||
|
"alarm_BusVoltageSamplingAbnormal": "Campionamento tensione bus anomalo",
|
||||||
|
"alarm_RelayFault": "Guasto Relè",
|
||||||
|
"alarm_BusVoltageAbnormal": "Tensione Bus Anomala",
|
||||||
|
"alarm_InternalCommunicationFailure": "Comunicazione Interna Interrotta",
|
||||||
|
"alarm_TemperatureSensorDisconnected": "Sensore temperatura scollegato",
|
||||||
|
"alarm_IgbtDriveFault": "Guasto al driver IGBT",
|
||||||
|
"alarm_EepromError": "Errore EEPROM",
|
||||||
|
"alarm_AuxiliaryPowerAbnormal": "Alimentazione ausiliaria anomala",
|
||||||
|
"alarm_DcAcOvercurrentProtection": "Protezione sovracorrente DC/AC",
|
||||||
|
"alarm_CommunicationProtocolMismatch": "Incompatibilità protocollo comunicazione",
|
||||||
|
"alarm_DspComFirmwareMismatch": "Incompatibilità firmware DSP/COM",
|
||||||
|
"alarm_DspSoftwareHardwareMismatch": "Incompatibilità software/hardware DSP",
|
||||||
|
"alarm_CpldAbnormal": "Anomalia CPLD",
|
||||||
|
"alarm_RedundancySamplingInconsistent": "Campioni ridondanti incoerenti",
|
||||||
|
"alarm_PwmPassThroughSignalFailure": "Segnale PWM guasto",
|
||||||
|
"alarm_AfciSelfTestFailure": "Autotest AFCI fallito",
|
||||||
|
"alarm_PvCurrentSamplingAbnormal": "Corrente PV Anomala",
|
||||||
|
"alarm_AcCurrentSamplingAbnormal": "Corrente AC Anomala",
|
||||||
|
"alarm_BusSoftbootFailure": "Avvio Bus DC Fallito",
|
||||||
|
"alarm_EpoFault": "Guasto EPO",
|
||||||
|
"alarm_MonitoringChipBootVerificationFailed": "Verifica avvio chip monitoraggio fallita",
|
||||||
|
"alarm_BmsCommunicationFailure": "Comunicazione BMS fallita",
|
||||||
|
"alarm_BmsChargeDischargeFailure": "Guasto Carica/Scarica BMS",
|
||||||
|
"alarm_BatteryVoltageLow": "Tensione Batteria Bassa",
|
||||||
|
"alarm_BatteryVoltageHigh": "Tensione Batteria Alta",
|
||||||
|
"alarm_BatteryTemperatureAbnormal": "Temperatura batteria anomala",
|
||||||
|
"alarm_BatteryReversed": "Batteria invertita",
|
||||||
|
"alarm_BatteryOpenCircuit": "Circuiti aperti batteria",
|
||||||
|
"alarm_BatteryOverloadProtection": "Protezione sovraccarico batteria",
|
||||||
|
"alarm_Bus2VoltageAbnormal": "Tensione bus2 anomala",
|
||||||
|
"alarm_BatteryChargeOcp": "Protezione sovraccarico carica",
|
||||||
|
"alarm_BatteryDischargeOcp": "Protezione sovraccarico scarica",
|
||||||
|
"alarm_BatterySoftStartFailed": "Avvio batteria fallito",
|
||||||
|
"alarm_EpsOutputShortCircuited": "Cortocircuito uscita EPS",
|
||||||
|
"alarm_OffGridBusVoltageLow": "Tensione Bus Fuori Rete Bassa",
|
||||||
|
"alarm_OffGridTerminalVoltageAbnormal": "Tensione Terminale Fuori Rete Anomala",
|
||||||
|
"alarm_SoftStartFailed": "Avvio Morbido Fallito",
|
||||||
|
"alarm_OffGridOutputVoltageAbnormal": "Tensione uscita off-grid anomala",
|
||||||
|
"alarm_BalancedCircuitSelfTestFailed": "Autotest circuito bilanciato fallito",
|
||||||
|
"alarm_HighDcComponentOutputVoltage": "Tensione uscita con componente DC elevato",
|
||||||
|
"alarm_OffGridParallelSignalAbnormal": "Segnale parallelo anomalo",
|
||||||
|
"alarm_AFCIFault": "Guasto AFCI",
|
||||||
|
"alarm_GFCIHigh": "Corrente di guasto elevata",
|
||||||
|
"alarm_PVVoltageHigh": "Tensione PV Elevata",
|
||||||
|
"alarm_OffGridBusVoltageTooLow": "Tensione bus off-grid troppo bassa"
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -26,7 +26,7 @@ public static class AlarmKnowledgeBase
|
||||||
if (GrowattAlarms.TryGetValue(normalized, out var growattDiag))
|
if (GrowattAlarms.TryGetValue(normalized, out var growattDiag))
|
||||||
return growattDiag;
|
return growattDiag;
|
||||||
|
|
||||||
// Try case-insensitive match for Sinexcel (alarm names may vary in casing)
|
// Try case-insensitive match for both Sinexcel and Growatt
|
||||||
var lowerDesc = normalized.ToLowerInvariant();
|
var lowerDesc = normalized.ToLowerInvariant();
|
||||||
foreach (var kvp in SinexcelAlarms)
|
foreach (var kvp in SinexcelAlarms)
|
||||||
{
|
{
|
||||||
|
|
@ -34,6 +34,12 @@ public static class AlarmKnowledgeBase
|
||||||
return kvp.Value;
|
return kvp.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var kvp in GrowattAlarms)
|
||||||
|
{
|
||||||
|
if (kvp.Key.ToLowerInvariant() == lowerDesc)
|
||||||
|
return kvp.Value;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,101 @@
|
||||||
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.Backend.Services;
|
||||||
|
|
||||||
|
public static class BehaviorAnalyzer
|
||||||
|
{
|
||||||
|
private const double SolarActiveThresholdKwh = 0.1; // min PV kWh in an hour to count as "solar active"
|
||||||
|
private const double LowSoCThreshold = 20.0; // % below which battery is considered depleted
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Derives behavioral facts from hourly data for the current week only.
|
||||||
|
/// All computation is pure C# — no AI involved.
|
||||||
|
/// </summary>
|
||||||
|
public static BehavioralPattern Analyze(List<HourlyEnergyData> hourlyData)
|
||||||
|
{
|
||||||
|
if (hourlyData.Count == 0)
|
||||||
|
return new BehavioralPattern();
|
||||||
|
|
||||||
|
// ── Per-hour averages across the week ──────────────────────────────
|
||||||
|
// Group by hour-of-day (0-23), average each metric across all days
|
||||||
|
var byHour = Enumerable.Range(0, 24).Select(h =>
|
||||||
|
{
|
||||||
|
var rows = hourlyData.Where(r => r.Hour == h).ToList();
|
||||||
|
if (rows.Count == 0)
|
||||||
|
return (Hour: h, AvgPv: 0.0, AvgLoad: 0.0, AvgGridImport: 0.0);
|
||||||
|
return (
|
||||||
|
Hour: h,
|
||||||
|
AvgPv: rows.Average(r => r.PvKwh),
|
||||||
|
AvgLoad: rows.Average(r => r.LoadKwh),
|
||||||
|
AvgGridImport: rows.Average(r => r.GridImportKwh)
|
||||||
|
);
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// ── Peak load hour ─────────────────────────────────────────────────
|
||||||
|
var peakLoadEntry = byHour.OrderByDescending(h => h.AvgLoad).First();
|
||||||
|
|
||||||
|
// ── Peak solar hour and end of solar window ────────────────────────
|
||||||
|
var peakSolarEntry = byHour.OrderByDescending(h => h.AvgPv).First();
|
||||||
|
|
||||||
|
// Solar window: last hour in the day where avg PV > threshold
|
||||||
|
var solarActiveHours = byHour.Where(h => h.AvgPv >= SolarActiveThresholdKwh).ToList();
|
||||||
|
var peakSolarEndHour = solarActiveHours.Count > 0
|
||||||
|
? solarActiveHours.Max(h => h.Hour)
|
||||||
|
: peakSolarEntry.Hour;
|
||||||
|
|
||||||
|
// ── Highest grid-import hour ────────────────────────────────────────
|
||||||
|
var worstGridEntry = byHour.OrderByDescending(h => h.AvgGridImport).First();
|
||||||
|
|
||||||
|
// ── Avoidable grid imports: grid drawn during hours when solar was active ──
|
||||||
|
// For each actual hourly record: if solar > threshold AND grid import > 0 → avoidable
|
||||||
|
var avoidableGridKwh = Math.Round(
|
||||||
|
hourlyData
|
||||||
|
.Where(r => r.PvKwh >= SolarActiveThresholdKwh && r.GridImportKwh > 0)
|
||||||
|
.Sum(r => r.GridImportKwh),
|
||||||
|
1);
|
||||||
|
|
||||||
|
// ── Weekday vs weekend average daily load ──────────────────────────
|
||||||
|
var weekdayDays = hourlyData
|
||||||
|
.Where(r => !r.IsWeekend)
|
||||||
|
.GroupBy(r => r.DateTime.Date)
|
||||||
|
.Select(g => g.Sum(r => r.LoadKwh))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var weekendDays = hourlyData
|
||||||
|
.Where(r => r.IsWeekend)
|
||||||
|
.GroupBy(r => r.DateTime.Date)
|
||||||
|
.Select(g => g.Sum(r => r.LoadKwh))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var weekdayAvg = weekdayDays.Count > 0 ? Math.Round(weekdayDays.Average(), 1) : 0;
|
||||||
|
var weekendAvg = weekendDays.Count > 0 ? Math.Round(weekendDays.Average(), 1) : 0;
|
||||||
|
|
||||||
|
// ── Battery depletion hour ─────────────────────────────────────────
|
||||||
|
// For each day, find the first evening hour (after 18:00) where SoC < threshold
|
||||||
|
// Average that hour across days where it occurs
|
||||||
|
var depletionHours = hourlyData
|
||||||
|
.Where(r => r.Hour >= 18 && r.BattSoC > 0 && r.BattSoC < LowSoCThreshold)
|
||||||
|
.GroupBy(r => r.DateTime.Date)
|
||||||
|
.Select(g => g.OrderBy(r => r.Hour).First().Hour)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var avgDepletedHour = depletionHours.Count > 0 ? (int)Math.Round(depletionHours.Average()) : -1;
|
||||||
|
var batteryDepletsNight = depletionHours.Count >= 3; // happens on 3+ nights = consistent pattern
|
||||||
|
|
||||||
|
return new BehavioralPattern
|
||||||
|
{
|
||||||
|
PeakLoadHour = peakLoadEntry.Hour,
|
||||||
|
AvgPeakLoadKwh = Math.Round(peakLoadEntry.AvgLoad, 2),
|
||||||
|
PeakSolarHour = peakSolarEntry.Hour,
|
||||||
|
PeakSolarEndHour = peakSolarEndHour,
|
||||||
|
AvgPeakSolarKwh = Math.Round(peakSolarEntry.AvgPv, 2),
|
||||||
|
HighestGridImportHour = worstGridEntry.Hour,
|
||||||
|
AvgGridImportAtPeakHour = Math.Round(worstGridEntry.AvgGridImport, 2),
|
||||||
|
AvoidableGridKwh = avoidableGridKwh,
|
||||||
|
WeekdayAvgDailyLoad = weekdayAvg,
|
||||||
|
WeekendAvgDailyLoad = weekendAvg,
|
||||||
|
AvgBatteryDepletedHour = avgDepletedHour,
|
||||||
|
BatteryDepletesOvernight = batteryDepletsNight,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ using Flurl.Http;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
using InnovEnergy.App.Backend.DataTypes;
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Services;
|
namespace InnovEnergy.App.Backend.Services;
|
||||||
|
|
||||||
|
|
@ -18,6 +19,9 @@ public static class DiagnosticService
|
||||||
/// <summary>In-memory cache: errorDescription → parsed response.</summary>
|
/// <summary>In-memory cache: errorDescription → parsed response.</summary>
|
||||||
private static readonly ConcurrentDictionary<string, DiagnosticResponse> Cache = new();
|
private static readonly ConcurrentDictionary<string, DiagnosticResponse> Cache = new();
|
||||||
|
|
||||||
|
/// <summary>Pre-generated translations keyed by language code → alarm key → response.</summary>
|
||||||
|
private static readonly Dictionary<string, IReadOnlyDictionary<string, DiagnosticResponse>> Translations = new();
|
||||||
|
|
||||||
// ── initialisation ──────────────────────────────────────────────
|
// ── initialisation ──────────────────────────────────────────────
|
||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
|
|
@ -25,12 +29,34 @@ public static class DiagnosticService
|
||||||
var apiKey = Environment.GetEnvironmentVariable("MISTRAL_API_KEY");
|
var apiKey = Environment.GetEnvironmentVariable("MISTRAL_API_KEY");
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(apiKey))
|
if (string.IsNullOrWhiteSpace(apiKey))
|
||||||
{
|
|
||||||
Console.Error.WriteLine("[DiagnosticService] MISTRAL_API_KEY not set – AI diagnostics disabled.");
|
Console.Error.WriteLine("[DiagnosticService] MISTRAL_API_KEY not set – AI diagnostics disabled.");
|
||||||
return;
|
else
|
||||||
|
_apiKey = apiKey;
|
||||||
|
|
||||||
|
// Load pre-generated translation files (en, de, fr, it) if available
|
||||||
|
// en.json is generated by generate_alarm_translations.py after the review campaign
|
||||||
|
var resourcesDir = Path.Combine(AppContext.BaseDirectory, "Resources");
|
||||||
|
foreach (var lang in new[] { "en", "de", "fr", "it" })
|
||||||
|
{
|
||||||
|
var file = Path.Combine(resourcesDir, $"AlarmTranslations.{lang}.json");
|
||||||
|
if (!File.Exists(file)) continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(file);
|
||||||
|
var raw = JsonConvert.DeserializeObject<Dictionary<string, DiagnosticResponse>>(json);
|
||||||
|
if (raw is not null)
|
||||||
|
{
|
||||||
|
Translations[lang] = raw;
|
||||||
|
Console.WriteLine($"[DiagnosticService] Loaded {raw.Count} {lang} translations.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[DiagnosticService] Failed to load AlarmTranslations.{lang}.json: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_apiKey = apiKey;
|
|
||||||
Console.WriteLine("[DiagnosticService] initialised.");
|
Console.WriteLine("[DiagnosticService] initialised.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,6 +72,10 @@ public static class DiagnosticService
|
||||||
_ => "English"
|
_ => "English"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>Converts "AbnormalGridVoltage" → "Abnormal Grid Voltage".</summary>
|
||||||
|
private static string SplitCamelCase(string name) =>
|
||||||
|
Regex.Replace(name, @"(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])", " ").Trim();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a diagnosis for <paramref name="errorDescription"/> in the given language.
|
/// Returns a diagnosis for <paramref name="errorDescription"/> in the given language.
|
||||||
/// For English: checks the static AlarmKnowledgeBase first, then in-memory cache, then Mistral AI.
|
/// For English: checks the static AlarmKnowledgeBase first, then in-memory cache, then Mistral AI.
|
||||||
|
|
@ -56,21 +86,38 @@ public static class DiagnosticService
|
||||||
{
|
{
|
||||||
var cacheKey = $"{errorDescription}|{language}";
|
var cacheKey = $"{errorDescription}|{language}";
|
||||||
|
|
||||||
// 1. For English only: check the static knowledge base first (no API call needed)
|
// 1. For English: check the static knowledge base first (no API call needed)
|
||||||
if (language == "en")
|
if (language == "en")
|
||||||
{
|
{
|
||||||
var knownDiagnosis = AlarmKnowledgeBase.TryGetDiagnosis(errorDescription);
|
var knownDiagnosis = AlarmKnowledgeBase.TryGetDiagnosis(errorDescription);
|
||||||
if (knownDiagnosis is not null)
|
if (knownDiagnosis is not null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[DiagnosticService] Found diagnosis in knowledge base for: {errorDescription}");
|
Console.WriteLine($"[DiagnosticService] Knowledge base hit (en): {errorDescription}");
|
||||||
return knownDiagnosis;
|
// Return a new instance with Name set — avoids mutating the shared static dictionary
|
||||||
|
return new DiagnosticResponse
|
||||||
|
{
|
||||||
|
Name = SplitCamelCase(errorDescription),
|
||||||
|
Explanation = knownDiagnosis.Explanation,
|
||||||
|
Causes = knownDiagnosis.Causes,
|
||||||
|
NextSteps = knownDiagnosis.NextSteps,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. If AI is not enabled, we can't proceed further
|
// 2. For non-English: check pre-generated translation files (no API call needed)
|
||||||
|
if (language != "en" && Translations.TryGetValue(language, out var langDict))
|
||||||
|
{
|
||||||
|
if (langDict.TryGetValue(errorDescription, out var translatedDiagnosis))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[DiagnosticService] Pre-generated translation hit ({language}): {errorDescription}");
|
||||||
|
return translatedDiagnosis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. If AI is not enabled, we can't proceed further
|
||||||
if (!IsEnabled) return null;
|
if (!IsEnabled) return null;
|
||||||
|
|
||||||
// 3. Check in-memory cache for previously fetched AI diagnoses
|
// 4. Check in-memory cache for previously fetched AI diagnoses
|
||||||
if (Cache.TryGetValue(cacheKey, out var cached))
|
if (Cache.TryGetValue(cacheKey, out var cached))
|
||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
|
|
@ -104,22 +151,52 @@ public static class DiagnosticService
|
||||||
|
|
||||||
// ── test helper (no DB dependency) ─────────────────────────────
|
// ── test helper (no DB dependency) ─────────────────────────────
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a diagnosis from the static knowledge base (English) or pre-generated
|
||||||
|
/// translations (other languages). Returns null if not found in either.
|
||||||
|
/// </summary>
|
||||||
|
public static DiagnosticResponse? TryGetTranslation(string errorDescription, string language)
|
||||||
|
{
|
||||||
|
// Check JSON translations first (en.json exists after review campaign)
|
||||||
|
if (Translations.TryGetValue(language, out var langDict) &&
|
||||||
|
langDict.TryGetValue(errorDescription, out var translated))
|
||||||
|
return translated;
|
||||||
|
|
||||||
|
// Fallback: English from compiled AlarmKnowledgeBase.cs (until en.json is deployed)
|
||||||
|
if (language == "en")
|
||||||
|
{
|
||||||
|
var kb = AlarmKnowledgeBase.TryGetDiagnosis(errorDescription);
|
||||||
|
if (kb is null) return null;
|
||||||
|
return new DiagnosticResponse
|
||||||
|
{
|
||||||
|
Name = SplitCamelCase(errorDescription),
|
||||||
|
Explanation = kb.Explanation,
|
||||||
|
Causes = kb.Causes,
|
||||||
|
NextSteps = kb.NextSteps,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calls Mistral directly with a generic prompt. For testing only - no DB lookup.
|
/// Calls Mistral directly with a generic prompt. For testing only - no DB lookup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task<DiagnosticResponse?> TestCallMistralAsync(string errorDescription)
|
public static async Task<DiagnosticResponse?> TestCallMistralAsync(string errorDescription, string language = "en")
|
||||||
{
|
{
|
||||||
if (!IsEnabled) return null;
|
if (!IsEnabled) return null;
|
||||||
|
|
||||||
|
var cacheKey = $"{errorDescription}|{language}";
|
||||||
|
|
||||||
// Check cache first
|
// Check cache first
|
||||||
if (Cache.TryGetValue(errorDescription, out var cached))
|
if (Cache.TryGetValue(cacheKey, out var cached))
|
||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
var prompt = BuildPrompt(errorDescription, "SodioHome", new List<string>(), "en");
|
var prompt = BuildPrompt(errorDescription, "SodioHome", new List<string>(), language);
|
||||||
var response = await CallMistralAsync(prompt);
|
var response = await CallMistralAsync(prompt);
|
||||||
|
|
||||||
if (response is not null)
|
if (response is not null)
|
||||||
Cache.TryAdd(errorDescription, response);
|
Cache.TryAdd(cacheKey, response);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
@ -132,18 +209,19 @@ public static class DiagnosticService
|
||||||
? string.Join(", ", recentErrors)
|
? string.Join(", ", recentErrors)
|
||||||
: "none";
|
: "none";
|
||||||
|
|
||||||
return $@"You are a technician for Innovenergy {productName} battery energy storage systems.
|
return $@"You are a technician for {productName} battery energy storage systems.
|
||||||
These are lithium-ion BESS units with a BMS, PV inverter, and grid inverter.
|
These are sodium-ion BESS units with a BMS, PV inverter, and grid inverter.
|
||||||
|
|
||||||
Error: {errorDescription}
|
Error: {errorDescription}
|
||||||
Other recent errors: {recentList}
|
Other recent errors: {recentList}
|
||||||
|
|
||||||
Explain for a non-technical homeowner. Keep it very short and simple:
|
Explain for a non-technical homeowner. Keep it very short and simple:
|
||||||
|
- name: 2-5 word display title for this alarm
|
||||||
- explanation: 1 short sentence, no jargon
|
- explanation: 1 short sentence, no jargon
|
||||||
- causes: 2-3 bullet points, plain language
|
- causes: 2-3 bullet points, plain language
|
||||||
- nextSteps: 2-3 simple action items a homeowner can understand
|
- nextSteps: 2-3 simple action items a homeowner can understand
|
||||||
IMPORTANT: Write all text values in {LanguageName(language)}. Reply with ONLY valid JSON, no markdown:
|
IMPORTANT: Write all text values in {LanguageName(language)}. Reply with ONLY valid JSON, no markdown:
|
||||||
{{""explanation"":""1 short sentence"",""causes"":[""...""],""nextSteps"":[""...""]}}
|
{{""name"":""short title"",""explanation"":""1 short sentence"",""causes"":[""...""],""nextSteps"":[""...""]}}
|
||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +290,7 @@ IMPORTANT: Write all text values in {LanguageName(language)}. Reply with ONLY va
|
||||||
|
|
||||||
public class DiagnosticResponse
|
public class DiagnosticResponse
|
||||||
{
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
public string Explanation { get; set; } = "";
|
public string Explanation { get; set; } = "";
|
||||||
public IReadOnlyList<string> Causes { get; set; } = Array.Empty<string>();
|
public IReadOnlyList<string> Causes { get; set; } = Array.Empty<string>();
|
||||||
public IReadOnlyList<string> NextSteps { get; set; } = Array.Empty<string>();
|
public IReadOnlyList<string> NextSteps { get; set; } = Array.Empty<string>();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ public static class ExcelDataParser
|
||||||
private const string ColGridExportToday = "Feed in energy Today";
|
private const string ColGridExportToday = "Feed in energy Today";
|
||||||
private const string ColBattChargedToday = "Daily Battery Charged";
|
private const string ColBattChargedToday = "Daily Battery Charged";
|
||||||
private const string ColBattDischargedToday = "Battery Discharged Today";
|
private const string ColBattDischargedToday = "Battery Discharged Today";
|
||||||
|
private const string ColBattSoC = "Battery 1 SoC"; // instantaneous %
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses an ESS Link Cloud Excel export file and returns one DailyEnergyData per day.
|
/// Parses an ESS Link Cloud Excel export file and returns one DailyEnergyData per day.
|
||||||
|
|
@ -79,6 +80,103 @@ public static class ExcelDataParser
|
||||||
return dailyLastRows.Values.ToList();
|
return dailyLastRows.Values.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses hourly energy snapshots from the xlsx.
|
||||||
|
/// For each hour of each day, finds the row nearest HH:00:00 and records the
|
||||||
|
/// cumulative "Today" values at that moment. The caller (BehaviorAnalyzer) then
|
||||||
|
/// diffs consecutive snapshots to get per-hour energy.
|
||||||
|
/// </summary>
|
||||||
|
public static List<HourlyEnergyData> ParseHourly(string filePath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
throw new FileNotFoundException($"Excel file not found: {filePath}");
|
||||||
|
|
||||||
|
using var workbook = new XLWorkbook(filePath);
|
||||||
|
var worksheet = workbook.Worksheet(1);
|
||||||
|
var lastRow = worksheet.LastRowUsed()?.RowNumber() ?? 0;
|
||||||
|
|
||||||
|
if (lastRow < 2)
|
||||||
|
throw new InvalidOperationException("Excel file has no data rows.");
|
||||||
|
|
||||||
|
// Build column map
|
||||||
|
var headerRow = worksheet.Row(1);
|
||||||
|
var colMap = new Dictionary<string, int>();
|
||||||
|
for (var col = 1; col <= worksheet.LastColumnUsed()?.ColumnNumber(); col++)
|
||||||
|
{
|
||||||
|
var header = headerRow.Cell(col).GetString().Trim();
|
||||||
|
if (!string.IsNullOrEmpty(header))
|
||||||
|
colMap[header] = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoC column is optional — not all exports include it
|
||||||
|
var hasSoC = colMap.ContainsKey(ColBattSoC);
|
||||||
|
|
||||||
|
// Read all rows into memory as (DateTime, cumulative values) pairs
|
||||||
|
var rawRows = new List<(DateTime Dt, double Pv, double Load, double GridIn, double BattChg, double BattDis, double SoC)>();
|
||||||
|
|
||||||
|
for (var row = 2; row <= lastRow; row++)
|
||||||
|
{
|
||||||
|
var dtStr = worksheet.Row(row).Cell(colMap[ColDateTime]).GetString().Trim();
|
||||||
|
if (string.IsNullOrEmpty(dtStr)) continue;
|
||||||
|
if (!DateTime.TryParse(dtStr, out var dt)) continue;
|
||||||
|
|
||||||
|
rawRows.Add((
|
||||||
|
dt,
|
||||||
|
GetDouble(worksheet, row, colMap[ColPvToday]),
|
||||||
|
GetDouble(worksheet, row, colMap[ColLoadToday]),
|
||||||
|
GetDouble(worksheet, row, colMap[ColGridImportToday]),
|
||||||
|
GetDouble(worksheet, row, colMap[ColBattChargedToday]),
|
||||||
|
GetDouble(worksheet, row, colMap[ColBattDischargedToday]),
|
||||||
|
hasSoC ? GetDouble(worksheet, row, colMap[ColBattSoC]) : 0
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawRows.Count == 0) return new List<HourlyEnergyData>();
|
||||||
|
|
||||||
|
// For each calendar hour that exists in the data, find the nearest row to HH:00:00
|
||||||
|
// Group rows by (date, hour) and pick the one closest to the round hour
|
||||||
|
var byHour = rawRows
|
||||||
|
.GroupBy(r => new DateTime(r.Dt.Year, r.Dt.Month, r.Dt.Day, r.Dt.Hour, 0, 0))
|
||||||
|
.OrderBy(g => g.Key)
|
||||||
|
.Select(g =>
|
||||||
|
{
|
||||||
|
var roundHour = g.Key;
|
||||||
|
var nearest = g.OrderBy(r => Math.Abs((r.Dt - roundHour).TotalSeconds)).First();
|
||||||
|
return (RoundHour: roundHour, Row: nearest);
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Diff consecutive snapshots within the same day to get per-hour energy
|
||||||
|
var result = new List<HourlyEnergyData>();
|
||||||
|
|
||||||
|
for (var i = 1; i < byHour.Count; i++)
|
||||||
|
{
|
||||||
|
var prev = byHour[i - 1];
|
||||||
|
var curr = byHour[i];
|
||||||
|
|
||||||
|
// Only diff within the same day — don't carry over across midnight
|
||||||
|
if (curr.RoundHour.Date != prev.RoundHour.Date) continue;
|
||||||
|
|
||||||
|
// Cumulative "Today" values reset at midnight, so diff is always >= 0 within a day
|
||||||
|
result.Add(new HourlyEnergyData
|
||||||
|
{
|
||||||
|
DateTime = curr.RoundHour,
|
||||||
|
Hour = curr.RoundHour.Hour,
|
||||||
|
DayOfWeek = curr.RoundHour.DayOfWeek.ToString(),
|
||||||
|
IsWeekend = curr.RoundHour.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday,
|
||||||
|
PvKwh = Math.Max(0, Math.Round(curr.Row.Pv - prev.Row.Pv, 3)),
|
||||||
|
LoadKwh = Math.Max(0, Math.Round(curr.Row.Load - prev.Row.Load, 3)),
|
||||||
|
GridImportKwh = Math.Max(0, Math.Round(curr.Row.GridIn - prev.Row.GridIn, 3)),
|
||||||
|
BatteryChargedKwh = Math.Max(0, Math.Round(curr.Row.BattChg - prev.Row.BattChg, 3)),
|
||||||
|
BatteryDischargedKwh = Math.Max(0, Math.Round(curr.Row.BattDis - prev.Row.BattDis, 3)),
|
||||||
|
BattSoC = curr.Row.SoC,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"[ExcelDataParser] Parsed {result.Count} hourly records from {filePath}");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private static double GetDouble(IXLWorksheet ws, int row, int col)
|
private static double GetDouble(IXLWorksheet ws, int row, int col)
|
||||||
{
|
{
|
||||||
var cell = ws.Row(row).Cell(col);
|
var cell = ws.Row(row).Cell(col);
|
||||||
|
|
|
||||||
|
|
@ -99,21 +99,21 @@ public static class ReportEmailService
|
||||||
Consumption: "Verbrauch",
|
Consumption: "Verbrauch",
|
||||||
GridImport: "Netzbezug",
|
GridImport: "Netzbezug",
|
||||||
GridExport: "Netzeinspeisung",
|
GridExport: "Netzeinspeisung",
|
||||||
BatteryInOut: "Batterie Ein/Aus",
|
BatteryInOut: "Batterie Laden / Entladen",
|
||||||
SolarEnergyUsed: "Genutzte Solarenergie",
|
SolarEnergyUsed: "Energie gespart",
|
||||||
StayedAtHome: "direkt genutzt",
|
StayedAtHome: "Solar + Batterie, nicht vom Netz",
|
||||||
EstMoneySaved: "Geschätzte Ersparnis",
|
EstMoneySaved: "Geschätzte Ersparnis",
|
||||||
AtRate: "bei 0.27 CHF/kWh",
|
AtRate: "bei 0.39 CHF/kWh",
|
||||||
SolarCoverage: "Solare Deckung",
|
SolarCoverage: "Eigenversorgung",
|
||||||
FromSolar: "durch Solar",
|
FromSolar: "aus Solar + Batterie",
|
||||||
BatteryEff: "Batterie-Eff.",
|
BatteryEff: "Batterie-Eff.",
|
||||||
OutVsIn: "Aus vs. Ein",
|
OutVsIn: "Entladung vs. Ladung",
|
||||||
Day: "Tag",
|
Day: "Tag",
|
||||||
Load: "Last",
|
Load: "Last",
|
||||||
GridIn: "Netz Ein",
|
GridIn: "Netz Ein",
|
||||||
GridOut: "Netz Aus",
|
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"
|
Footer: "Erstellt von <strong style=\"color:#666\">inesco Energy Monitor</strong>"
|
||||||
),
|
),
|
||||||
"fr" => new EmailStrings(
|
"fr" => new EmailStrings(
|
||||||
Title: "Rapport de performance hebdomadaire",
|
Title: "Rapport de performance hebdomadaire",
|
||||||
|
|
@ -129,21 +129,21 @@ public static class ReportEmailService
|
||||||
Consumption: "Consommation",
|
Consumption: "Consommation",
|
||||||
GridImport: "Import réseau",
|
GridImport: "Import réseau",
|
||||||
GridExport: "Export réseau",
|
GridExport: "Export réseau",
|
||||||
BatteryInOut: "Batterie Entrée/Sortie",
|
BatteryInOut: "Batterie Charge / Décharge",
|
||||||
SolarEnergyUsed: "Énergie solaire utilisée",
|
SolarEnergyUsed: "Énergie économisée",
|
||||||
StayedAtHome: "autoconsommée",
|
StayedAtHome: "solaire + batterie, non achetée au réseau",
|
||||||
EstMoneySaved: "Économies estimées",
|
EstMoneySaved: "Économies estimées",
|
||||||
AtRate: "à 0.27 CHF/kWh",
|
AtRate: "à 0.39 CHF/kWh",
|
||||||
SolarCoverage: "Couverture solaire",
|
SolarCoverage: "Autosuffisance",
|
||||||
FromSolar: "depuis le solaire",
|
FromSolar: "du solaire + batterie",
|
||||||
BatteryEff: "Eff. batterie",
|
BatteryEff: "Eff. batterie",
|
||||||
OutVsIn: "sortie vs entrée",
|
OutVsIn: "décharge vs charge",
|
||||||
Day: "Jour",
|
Day: "Jour",
|
||||||
Load: "Charge",
|
Load: "Charge",
|
||||||
GridIn: "Réseau Ent.",
|
GridIn: "Réseau Ent.",
|
||||||
GridOut: "Réseau Sor.",
|
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"
|
Footer: "Généré par <strong style=\"color:#666\">inesco Energy Monitor</strong>"
|
||||||
),
|
),
|
||||||
"it" => new EmailStrings(
|
"it" => new EmailStrings(
|
||||||
Title: "Rapporto settimanale delle prestazioni",
|
Title: "Rapporto settimanale delle prestazioni",
|
||||||
|
|
@ -159,21 +159,21 @@ public static class ReportEmailService
|
||||||
Consumption: "Consumo",
|
Consumption: "Consumo",
|
||||||
GridImport: "Import dalla rete",
|
GridImport: "Import dalla rete",
|
||||||
GridExport: "Export nella rete",
|
GridExport: "Export nella rete",
|
||||||
BatteryInOut: "Batteria Ent./Usc.",
|
BatteryInOut: "Batteria Carica / Scarica",
|
||||||
SolarEnergyUsed: "Energia solare utilizzata",
|
SolarEnergyUsed: "Energia risparmiata",
|
||||||
StayedAtHome: "rimasta in casa",
|
StayedAtHome: "solare + batteria, non acquistata dalla rete",
|
||||||
EstMoneySaved: "Risparmio stimato",
|
EstMoneySaved: "Risparmio stimato",
|
||||||
AtRate: "a 0.27 CHF/kWh",
|
AtRate: "a 0.39 CHF/kWh",
|
||||||
SolarCoverage: "Copertura solare",
|
SolarCoverage: "Autosufficienza",
|
||||||
FromSolar: "dal solare",
|
FromSolar: "da solare + batteria",
|
||||||
BatteryEff: "Eff. batteria",
|
BatteryEff: "Eff. batteria",
|
||||||
OutVsIn: "uscita vs entrata",
|
OutVsIn: "scarica vs carica",
|
||||||
Day: "Giorno",
|
Day: "Giorno",
|
||||||
Load: "Carico",
|
Load: "Carico",
|
||||||
GridIn: "Rete Ent.",
|
GridIn: "Rete Ent.",
|
||||||
GridOut: "Rete Usc.",
|
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"
|
Footer: "Generato da <strong style=\"color:#666\">inesco Energy Monitor</strong>"
|
||||||
),
|
),
|
||||||
_ => new EmailStrings(
|
_ => new EmailStrings(
|
||||||
Title: "Weekly Performance Report",
|
Title: "Weekly Performance Report",
|
||||||
|
|
@ -189,21 +189,21 @@ public static class ReportEmailService
|
||||||
Consumption: "Consumption",
|
Consumption: "Consumption",
|
||||||
GridImport: "Grid Import",
|
GridImport: "Grid Import",
|
||||||
GridExport: "Grid Export",
|
GridExport: "Grid Export",
|
||||||
BatteryInOut: "Battery In/Out",
|
BatteryInOut: "Battery Charge / Discharge",
|
||||||
SolarEnergyUsed: "Solar Energy Used",
|
SolarEnergyUsed: "Energy Saved",
|
||||||
StayedAtHome: "stayed at home",
|
StayedAtHome: "solar + battery, not bought from grid",
|
||||||
EstMoneySaved: "Est. Money Saved",
|
EstMoneySaved: "Est. Money Saved",
|
||||||
AtRate: "at 0.27 CHF/kWh",
|
AtRate: "at 0.39 CHF/kWh",
|
||||||
SolarCoverage: "Solar Coverage",
|
SolarCoverage: "Self-Sufficiency",
|
||||||
FromSolar: "from solar",
|
FromSolar: "from solar + battery",
|
||||||
BatteryEff: "Battery Eff.",
|
BatteryEff: "Battery Eff.",
|
||||||
OutVsIn: "out vs in",
|
OutVsIn: "discharge vs charge",
|
||||||
Day: "Day",
|
Day: "Day",
|
||||||
Load: "Load",
|
Load: "Load",
|
||||||
GridIn: "Grid In",
|
GridIn: "Grid In",
|
||||||
GridOut: "Grid Out",
|
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"
|
Footer: "Generated by <strong style=\"color:#666\">inesco Energy Monitor</strong>"
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -230,21 +230,44 @@ public static class ReportEmailService
|
||||||
"</ul>"
|
"</ul>"
|
||||||
: $"<p style=\"margin:0;line-height:1.6\">{FormatInsightLine(r.AiInsight)}</p>";
|
: $"<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 = "";
|
var dailyRows = "";
|
||||||
foreach (var d in r.DailyData)
|
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 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 += $@"
|
dailyRows += $@"
|
||||||
<tr style=""background:{bgColor}"">
|
<tr style=""opacity:{opacity};border-bottom:1px solid #f0f0f0"">
|
||||||
<td style=""padding:6px 10px;border-bottom:1px solid #eee"">{dayName} {d.Date}</td>
|
<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:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.PvProduction:F1}</td>
|
<td style=""padding:4px 8px"">
|
||||||
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.LoadConsumption:F1}</td>
|
<div style=""font-size:10px;color:#888;margin-bottom:3px;text-align:right"">{valueText}</div>
|
||||||
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.GridImport:F1}</td>
|
<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 style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.GridExport:F1}</td>
|
</td>
|
||||||
<td style=""padding:6px 10px;border-bottom:1px solid #eee;text-align:right"">{d.BatteryCharged:F1}/{d.BatteryDischarged:F1}</td>
|
|
||||||
</tr>";
|
</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,8 +365,8 @@ public static class ReportEmailService
|
||||||
<div style=""font-size:16px;font-weight:bold;margin-bottom:12px;color:#2c3e50"">{s.SavingsHeader}</div>
|
<div style=""font-size:16px;font-weight:bold;margin-bottom:12px;color:#2c3e50"">{s.SavingsHeader}</div>
|
||||||
<table width=""100%"" cellpadding=""0"" cellspacing=""8"">
|
<table width=""100%"" cellpadding=""0"" cellspacing=""8"">
|
||||||
<tr>
|
<tr>
|
||||||
{SavingsBox(s.SolarEnergyUsed, $"{r.CurrentWeek.TotalPvProduction - r.CurrentWeek.TotalGridExport:F1} kWh", s.StayedAtHome, "#27ae60")}
|
{SavingsBox(s.SolarEnergyUsed, $"{r.TotalEnergySaved:F1} kWh", s.StayedAtHome, "#27ae60")}
|
||||||
{SavingsBox(s.EstMoneySaved, $"~{(r.CurrentWeek.TotalPvProduction - r.CurrentWeek.TotalGridExport) * 0.27:F1} CHF", s.AtRate, "#2980b9")}
|
{SavingsBox(s.EstMoneySaved, $"~{r.TotalSavingsCHF:F0} CHF", s.AtRate, "#2980b9")}
|
||||||
{SavingsBox(s.SolarCoverage, $"{r.SelfSufficiencyPercent:F0}%", s.FromSolar, "#8e44ad")}
|
{SavingsBox(s.SolarCoverage, $"{r.SelfSufficiencyPercent:F0}%", s.FromSolar, "#8e44ad")}
|
||||||
{SavingsBox(s.BatteryEff, $"{r.BatteryEfficiencyPercent:F0}%", s.OutVsIn, "#e67e22")}
|
{SavingsBox(s.BatteryEff, $"{r.BatteryEfficiencyPercent:F0}%", s.OutVsIn, "#e67e22")}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -351,18 +374,18 @@ public static class ReportEmailService
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<!-- Daily Breakdown -->
|
<!-- Daily Breakdown (bar chart) -->
|
||||||
<tr>
|
<tr>
|
||||||
<td style=""padding:0 30px 24px"">
|
<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"">
|
<table width=""100%"" cellpadding=""0"" cellspacing=""0"" style=""border:1px solid #eee;border-radius:4px;font-size:13px"">
|
||||||
|
<!-- Legend -->
|
||||||
<tr style=""background:#f8f9fa"">
|
<tr style=""background:#f8f9fa"">
|
||||||
<th style=""padding:6px 10px;text-align:left"">{s.Day}</th>
|
<td colspan=""2"" style=""padding:8px 10px;font-size:12px"">
|
||||||
<th style=""padding:6px 10px;text-align:right"">PV</th>
|
{(showPv ? @$"<span style=""display:inline-block;width:10px;height:10px;background:#f39c12;border-radius:2px;margin-right:4px""></span>PV " : "")}
|
||||||
<th style=""padding:6px 10px;text-align:right"">{s.Load}</th>
|
<span style=""display:inline-block;width:10px;height:10px;background:#3498db;border-radius:2px;margin-right:4px""></span>{s.Load}
|
||||||
<th style=""padding:6px 10px;text-align:right"">{s.GridIn}</th>
|
{(showGrid ? @$"<span style=""display:inline-block;width:10px;height:10px;background:#e74c3c;border-radius:2px;margin-right:4px""></span>{s.GridIn}" : "")}
|
||||||
<th style=""padding:6px 10px;text-align:right"">{s.GridOut}</th>
|
</td>
|
||||||
<th style=""padding:6px 10px;text-align:right"">{s.BattInOut}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
{dailyRows}
|
{dailyRows}
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -407,10 +430,10 @@ public static class ReportEmailService
|
||||||
{
|
{
|
||||||
result = line;
|
result = line;
|
||||||
}
|
}
|
||||||
// Bold numbers followed by units
|
// Bold all numbers: time ranges (14:00–18:00), times (09:00), decimals, integers
|
||||||
result = System.Text.RegularExpressions.Regex.Replace(
|
result = System.Text.RegularExpressions.Regex.Replace(
|
||||||
result,
|
result,
|
||||||
@"(\d+[\d,.]*\s*(?:kWh|CHF|%|days?))",
|
@"(\d{1,2}:\d{2}(?:[–\-]\d{1,2}:\d{2})?|\d+[.,]\d+|\d+)",
|
||||||
"<strong>$1</strong>");
|
"<strong>$1</strong>");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using Flurl.Http;
|
using Flurl.Http;
|
||||||
using InnovEnergy.App.Backend.DataTypes;
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -9,19 +8,15 @@ public static class WeeklyReportService
|
||||||
{
|
{
|
||||||
private static readonly string TmpReportDir = Environment.CurrentDirectory + "/tmp_report/";
|
private static readonly string TmpReportDir = Environment.CurrentDirectory + "/tmp_report/";
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, string> InsightCache = new();
|
|
||||||
|
|
||||||
// Bump this version when the AI prompt changes to automatically invalidate old cache files
|
|
||||||
private const string CacheVersion = "v2";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a full weekly report for the given installation.
|
/// Generates a full weekly report for the given installation.
|
||||||
/// Caches the full report as JSON next to the xlsx. Cache is invalidated when xlsx is updated or CacheVersion changes.
|
/// Cache is invalidated automatically when the xlsx file is newer than the cache.
|
||||||
|
/// To force regeneration (e.g. after a prompt change), simply delete the cache files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task<WeeklyReportResponse> GenerateReportAsync(long installationId, string installationName, string language = "en")
|
public static async Task<WeeklyReportResponse> GenerateReportAsync(long installationId, string installationName, string language = "en")
|
||||||
{
|
{
|
||||||
var xlsxPath = TmpReportDir + installationId + ".xlsx";
|
var xlsxPath = TmpReportDir + installationId + ".xlsx";
|
||||||
var cachePath = TmpReportDir + $"{installationId}_{language}_{CacheVersion}.cache.json";
|
var cachePath = TmpReportDir + $"{installationId}_{language}.cache.json";
|
||||||
|
|
||||||
// Use cached report if xlsx hasn't changed since cache was written
|
// Use cached report if xlsx hasn't changed since cache was written
|
||||||
if (File.Exists(cachePath) && File.Exists(xlsxPath))
|
if (File.Exists(cachePath) && File.Exists(xlsxPath))
|
||||||
|
|
@ -47,8 +42,10 @@ public static class WeeklyReportService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse both daily summaries and hourly intervals from the same xlsx
|
||||||
var allDays = ExcelDataParser.Parse(xlsxPath);
|
var allDays = ExcelDataParser.Parse(xlsxPath);
|
||||||
var report = await GenerateReportFromDataAsync(allDays, installationName, language);
|
var allHourly = ExcelDataParser.ParseHourly(xlsxPath);
|
||||||
|
var report = await GenerateReportFromDataAsync(allDays, allHourly, installationName, language);
|
||||||
|
|
||||||
// Write cache
|
// Write cache
|
||||||
try
|
try
|
||||||
|
|
@ -64,15 +61,18 @@ public static class WeeklyReportService
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core report generation from daily data. Data-source agnostic.
|
/// Core report generation. Accepts both daily summaries and hourly intervals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static async Task<WeeklyReportResponse> GenerateReportFromDataAsync(
|
public static async Task<WeeklyReportResponse> GenerateReportFromDataAsync(
|
||||||
List<DailyEnergyData> allDays, string installationName, string language = "en")
|
List<DailyEnergyData> allDays,
|
||||||
|
List<HourlyEnergyData> allHourly,
|
||||||
|
string installationName,
|
||||||
|
string language = "en")
|
||||||
{
|
{
|
||||||
// Sort by date
|
// Sort by date
|
||||||
allDays = allDays.OrderBy(d => d.Date).ToList();
|
allDays = allDays.OrderBy(d => d.Date).ToList();
|
||||||
|
|
||||||
// Split into previous week and current week
|
// Split into previous week and current week (daily)
|
||||||
List<DailyEnergyData> previousWeekDays;
|
List<DailyEnergyData> previousWeekDays;
|
||||||
List<DailyEnergyData> currentWeekDays;
|
List<DailyEnergyData> currentWeekDays;
|
||||||
|
|
||||||
|
|
@ -87,10 +87,14 @@ public static class WeeklyReportService
|
||||||
currentWeekDays = allDays;
|
currentWeekDays = allDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restrict hourly data to current week only for behavioral analysis
|
||||||
|
var currentWeekStart = DateTime.Parse(currentWeekDays.First().Date);
|
||||||
|
var currentHourlyData = allHourly.Where(h => h.DateTime.Date >= currentWeekStart.Date).ToList();
|
||||||
|
|
||||||
var currentSummary = Summarize(currentWeekDays);
|
var currentSummary = Summarize(currentWeekDays);
|
||||||
var previousSummary = previousWeekDays.Count > 0 ? Summarize(previousWeekDays) : null;
|
var previousSummary = previousWeekDays.Count > 0 ? Summarize(previousWeekDays) : null;
|
||||||
|
|
||||||
// Calculate key ratios for current week
|
// Key ratios for current week
|
||||||
var selfSufficiency = currentSummary.TotalConsumption > 0
|
var selfSufficiency = currentSummary.TotalConsumption > 0
|
||||||
? Math.Round((currentSummary.TotalConsumption - currentSummary.TotalGridImport) / currentSummary.TotalConsumption * 100, 1)
|
? Math.Round((currentSummary.TotalConsumption - currentSummary.TotalGridImport) / currentSummary.TotalConsumption * 100, 1)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
@ -112,9 +116,21 @@ public static class WeeklyReportService
|
||||||
var consumptionChange = PercentChange(previousSummary?.TotalConsumption, currentSummary.TotalConsumption);
|
var consumptionChange = PercentChange(previousSummary?.TotalConsumption, currentSummary.TotalConsumption);
|
||||||
var gridImportChange = PercentChange(previousSummary?.TotalGridImport, currentSummary.TotalGridImport);
|
var gridImportChange = PercentChange(previousSummary?.TotalGridImport, currentSummary.TotalGridImport);
|
||||||
|
|
||||||
// AI insight
|
// Behavioral pattern from hourly data (pure C# — no AI)
|
||||||
var aiInsight = await GetAiInsightAsync(currentWeekDays, currentSummary, previousSummary,
|
var behavior = BehaviorAnalyzer.Analyze(currentHourlyData);
|
||||||
selfSufficiency, gridDependency, batteryEfficiency, installationName, language);
|
|
||||||
|
// Pre-computed savings — single source of truth for UI and AI
|
||||||
|
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;
|
||||||
|
var daysEquivalent = avgDailyConsumption > 0 ? Math.Round(totalEnergySaved / avgDailyConsumption, 1) : 0;
|
||||||
|
|
||||||
|
// AI insight combining daily facts + behavioral pattern
|
||||||
|
var aiInsight = await GetAiInsightAsync(
|
||||||
|
currentWeekDays, currentSummary, previousSummary,
|
||||||
|
selfSufficiency, totalEnergySaved, totalSavingsCHF,
|
||||||
|
behavior, installationName, language);
|
||||||
|
|
||||||
return new WeeklyReportResponse
|
return new WeeklyReportResponse
|
||||||
{
|
{
|
||||||
|
|
@ -123,6 +139,9 @@ public static class WeeklyReportService
|
||||||
PeriodEnd = currentWeekDays.Last().Date,
|
PeriodEnd = currentWeekDays.Last().Date,
|
||||||
CurrentWeek = currentSummary,
|
CurrentWeek = currentSummary,
|
||||||
PreviousWeek = previousSummary,
|
PreviousWeek = previousSummary,
|
||||||
|
TotalEnergySaved = totalEnergySaved,
|
||||||
|
TotalSavingsCHF = totalSavingsCHF,
|
||||||
|
DaysEquivalent = daysEquivalent,
|
||||||
SelfSufficiencyPercent = selfSufficiency,
|
SelfSufficiencyPercent = selfSufficiency,
|
||||||
SelfConsumptionPercent = selfConsumption,
|
SelfConsumptionPercent = selfConsumption,
|
||||||
BatteryEfficiencyPercent = batteryEfficiency,
|
BatteryEfficiencyPercent = batteryEfficiency,
|
||||||
|
|
@ -131,6 +150,7 @@ public static class WeeklyReportService
|
||||||
ConsumptionChangePercent = consumptionChange,
|
ConsumptionChangePercent = consumptionChange,
|
||||||
GridImportChangePercent = gridImportChange,
|
GridImportChangePercent = gridImportChange,
|
||||||
DailyData = allDays,
|
DailyData = allDays,
|
||||||
|
Behavior = behavior,
|
||||||
AiInsight = aiInsight,
|
AiInsight = aiInsight,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -163,13 +183,17 @@ public static class WeeklyReportService
|
||||||
_ => "English"
|
_ => "English"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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(
|
private static async Task<string> GetAiInsightAsync(
|
||||||
List<DailyEnergyData> currentWeek,
|
List<DailyEnergyData> currentWeek,
|
||||||
WeeklySummary current,
|
WeeklySummary current,
|
||||||
WeeklySummary? previous,
|
WeeklySummary? previous,
|
||||||
double selfSufficiency,
|
double selfSufficiency,
|
||||||
double gridDependency,
|
double totalEnergySaved,
|
||||||
double batteryEfficiency,
|
double totalSavingsCHF,
|
||||||
|
BehavioralPattern behavior,
|
||||||
string installationName,
|
string installationName,
|
||||||
string language = "en")
|
string language = "en")
|
||||||
{
|
{
|
||||||
|
|
@ -180,45 +204,106 @@ public static class WeeklyReportService
|
||||||
return "AI insight unavailable (API key not configured).";
|
return "AI insight unavailable (API key not configured).";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache key: installation + period + language
|
const double ElectricityPriceCHF = 0.39;
|
||||||
var cacheKey = $"{installationName}_{currentWeek.Last().Date}_{language}";
|
|
||||||
if (InsightCache.TryGetValue(cacheKey, out var cached))
|
|
||||||
return cached;
|
|
||||||
|
|
||||||
// Build compact prompt
|
// Detect which components are present
|
||||||
var dayLines = string.Join("\n", currentWeek.Select(d =>
|
var hasPv = currentWeek.Sum(d => d.PvProduction) > 0.5;
|
||||||
{
|
var hasBattery = currentWeek.Sum(d => d.BatteryCharged) > 0.5
|
||||||
var dayName = DateTime.Parse(d.Date).ToString("ddd");
|
|| currentWeek.Sum(d => d.BatteryDischarged) > 0.5;
|
||||||
return $"{dayName} {d.Date}: PV={d.PvProduction:F1} Load={d.LoadConsumption:F1} GridIn={d.GridImport:F1} GridOut={d.GridExport:F1} BattIn={d.BatteryCharged:F1} BattOut={d.BatteryDischarged:F1}";
|
var hasGrid = currentWeek.Sum(d => d.GridImport) > 0.5;
|
||||||
}));
|
|
||||||
|
|
||||||
var comparison = previous != null
|
var bestDay = currentWeek.OrderByDescending(d => d.PvProduction).First();
|
||||||
? $"vs Last week: PV {current.TotalPvProduction} vs {previous.TotalPvProduction}, Grid Import {current.TotalGridImport} vs {previous.TotalGridImport}, Consumption {current.TotalConsumption} vs {previous.TotalConsumption}"
|
var worstDay = currentWeek.OrderBy(d => d.PvProduction).First();
|
||||||
: "No previous week data available.";
|
var bestDayName = DateTime.Parse(bestDay.Date).ToString("dddd");
|
||||||
|
var worstDayName = DateTime.Parse(worstDay.Date).ToString("dddd");
|
||||||
|
|
||||||
var solarSavings = Math.Round(current.TotalPvProduction - current.TotalGridExport, 1);
|
var topBattDay = currentWeek.OrderByDescending(d => d.BatteryCharged).First();
|
||||||
|
var topBattDayName = DateTime.Parse(topBattDay.Date).ToString("dddd");
|
||||||
|
|
||||||
var prompt = $@"You are an energy advisor for a SodistoreHome installation: ""{installationName}"".
|
// Behavioral facts as compact lines
|
||||||
|
var peakSolarWindow = FormatHour(behavior.PeakSolarHour) + "–" + FormatHour(behavior.PeakSolarEndHour);
|
||||||
|
var avoidableSavingsCHF = Math.Round(behavior.AvoidableGridKwh * ElectricityPriceCHF, 0);
|
||||||
|
|
||||||
Write exactly 4 bullet points (each on its own line starting with ""- ""). No bold markers, no asterisks, no markdown — plain text only.
|
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 sodistore home, 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 sodistore home installation: ""{installationName}"".
|
||||||
|
|
||||||
|
Write 4 bullet points (each on its own line starting with ""- ""). No bold markers, no asterisks, no markdown — plain text only.
|
||||||
|
|
||||||
IMPORTANT FORMAT RULE: Each bullet MUST start with a short title followed by a colon, then the description. Example: ""- Title label: Description text here."" Translate the title label into {LanguageName(language)} but always keep the ""Title: description"" structure.
|
IMPORTANT FORMAT RULE: Each bullet MUST start with a short title followed by a colon, then the description. Example: ""- Title label: Description text here."" Translate the title label into {LanguageName(language)} but always keep the ""Title: description"" structure.
|
||||||
|
|
||||||
1. Solar savings: this week the system saved {solarSavings} kWh from the grid. Explain what this means in simple terms (e.g. equivalent to X days of average household use, or roughly X CHF saved at ~0.27 CHF/kWh).
|
CRITICAL: All numbers below are pre-calculated. Use these values as-is — do not recalculate, round differently, or change any number.
|
||||||
2. Best vs worst solar day: name the best and worst days with their PV kWh values. Mention likely weather reason.
|
|
||||||
3. Battery performance: was the battery well-utilized this week? Mention charge/discharge totals and any standout days.
|
|
||||||
4. Tip of the week: one specific, practical recommendation based on THIS week's patterns to save more energy or money.
|
|
||||||
|
|
||||||
Rules: Use actual day names and numbers. Keep each bullet to 1-2 sentences. Write for a homeowner, not an engineer. Do NOT use asterisks or any formatting marks.
|
SYSTEM COMPONENTS: PV={hasPv}, Battery={hasBattery}, Grid={hasGrid}
|
||||||
IMPORTANT: Write your entire response in {LanguageName(language)}.
|
|
||||||
|
|
||||||
Daily data (kWh):
|
DAILY FACTS:
|
||||||
{dayLines}
|
- Total consumption: {current.TotalConsumption:F1} kWh this week. Self-sufficiency: {selfSufficiency}%.
|
||||||
|
{pvDailyFact}
|
||||||
|
{battDailyFact}
|
||||||
|
{gridDailyFact}
|
||||||
|
|
||||||
Totals: PV={current.TotalPvProduction:F1} Load={current.TotalConsumption:F1} GridIn={current.TotalGridImport:F1} GridOut={current.TotalGridExport:F1} BattIn={current.TotalBatteryCharged:F1} BattOut={current.TotalBatteryDischarged:F1}
|
BEHAVIORAL PATTERN (from hourly data this week):
|
||||||
Solar used at home={solarSavings} kWh ({selfSufficiency}% of consumption covered by solar)
|
- Peak household load: {FormatHourSlot(behavior.PeakLoadHour)}, avg {behavior.AvgPeakLoadKwh} kWh during that hour
|
||||||
Battery-eff={batteryEfficiency}%
|
- {weekdayWeekendLine}{pvBehaviorLines}
|
||||||
{comparison}";
|
{gridBehaviorLine}
|
||||||
|
{battBehaviorLine}
|
||||||
|
|
||||||
|
INSTRUCTIONS:
|
||||||
|
{instruction1}
|
||||||
|
{instruction2}
|
||||||
|
{instruction3}
|
||||||
|
{instruction4}
|
||||||
|
|
||||||
|
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
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -226,7 +311,7 @@ Battery-eff={batteryEfficiency}%
|
||||||
{
|
{
|
||||||
model = "mistral-small-latest",
|
model = "mistral-small-latest",
|
||||||
messages = new[] { new { role = "user", content = prompt } },
|
messages = new[] { new { role = "user", content = prompt } },
|
||||||
max_tokens = 350,
|
max_tokens = 400,
|
||||||
temperature = 0.3
|
temperature = 0.3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -241,7 +326,6 @@ Battery-eff={batteryEfficiency}%
|
||||||
if (!string.IsNullOrWhiteSpace(content))
|
if (!string.IsNullOrWhiteSpace(content))
|
||||||
{
|
{
|
||||||
var insight = content.Trim();
|
var insight = content.Trim();
|
||||||
InsightCache.TryAdd(cacheKey, insight);
|
|
||||||
Console.WriteLine($"[WeeklyReportService] AI insight generated ({insight.Length} chars).");
|
Console.WriteLine($"[WeeklyReportService] AI insight generated ({insight.Length} chars).");
|
||||||
return insight;
|
return insight;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,320 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
generate_alarm_translations.py
|
||||||
|
|
||||||
|
Post-campaign script: reads AlarmTranslationsChecked.de.json (the reviewed and
|
||||||
|
AI-synthesized German content), translates into English, French, and Italian,
|
||||||
|
and writes:
|
||||||
|
|
||||||
|
Resources/AlarmTranslations.de.json ← replace with reviewed German
|
||||||
|
Resources/AlarmTranslations.en.json ← back-translated from German
|
||||||
|
Resources/AlarmTranslations.fr.json ← translated from German
|
||||||
|
Resources/AlarmTranslations.it.json ← translated from German
|
||||||
|
Services/AlarmKnowledgeBase.cs ← updated English source (keeps same structure)
|
||||||
|
|
||||||
|
Run this AFTER the review campaign is complete:
|
||||||
|
export MISTRAL_API_KEY=your_key_here
|
||||||
|
cd csharp/App/Backend
|
||||||
|
python3 generate_alarm_translations.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
from typing import Optional
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# ── Config ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
CHECKED_FILE = "Resources/AlarmTranslationsChecked.de.json"
|
||||||
|
KNOWLEDGE_BASE = "Services/AlarmKnowledgeBase.cs"
|
||||||
|
RESOURCES_DIR = "Resources"
|
||||||
|
MISTRAL_URL = "https://api.mistral.ai/v1/chat/completions"
|
||||||
|
MISTRAL_MODEL = "mistral-large-latest"
|
||||||
|
BATCH_SIZE = 5 # alarms per API call
|
||||||
|
RETRY_DELAY = 5 # seconds between retries on rate-limit
|
||||||
|
MAX_RETRIES = 3
|
||||||
|
REQUEST_TIMEOUT = (10, 90)
|
||||||
|
|
||||||
|
TARGET_LANGUAGES = {
|
||||||
|
"en": "English",
|
||||||
|
"fr": "French",
|
||||||
|
"it": "Italian",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ── Mistral API ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def call_mistral(api_key: str, prompt: str) -> Optional[str]:
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
body = {
|
||||||
|
"model": MISTRAL_MODEL,
|
||||||
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
|
"max_tokens": 1800,
|
||||||
|
"temperature": 0.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for attempt in range(1, MAX_RETRIES + 1):
|
||||||
|
try:
|
||||||
|
resp = requests.post(MISTRAL_URL, headers=headers, json=body, timeout=REQUEST_TIMEOUT)
|
||||||
|
if resp.status_code == 429:
|
||||||
|
print(f" Rate limited, waiting {RETRY_DELAY}s (attempt {attempt}/{MAX_RETRIES})...")
|
||||||
|
time.sleep(RETRY_DELAY * attempt)
|
||||||
|
continue
|
||||||
|
resp.raise_for_status()
|
||||||
|
content = resp.json()["choices"][0]["message"]["content"].strip()
|
||||||
|
if content.startswith("```"):
|
||||||
|
first_newline = content.index("\n")
|
||||||
|
content = content[first_newline + 1:]
|
||||||
|
if content.endswith("```"):
|
||||||
|
content = content[:-3].strip()
|
||||||
|
return content
|
||||||
|
except requests.RequestException as e:
|
||||||
|
print(f" HTTP error: {e} (attempt {attempt}/{MAX_RETRIES})")
|
||||||
|
time.sleep(RETRY_DELAY)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def translate_batch(api_key: str, batch: dict, target_language: str) -> Optional[dict]:
|
||||||
|
"""
|
||||||
|
Translates a batch of German alarm entries into the target language.
|
||||||
|
Input: { "AlarmKey": { "Explanation": "...", "Causes": [...], "NextSteps": [...] } }
|
||||||
|
Output: same structure in target language.
|
||||||
|
"""
|
||||||
|
prompt = f"""You are translating battery energy storage system alarm descriptions from German into {target_language}.
|
||||||
|
The source content has been reviewed by field engineers and is accurate.
|
||||||
|
Translate faithfully — keep the same number of bullet points, same meaning, plain language for homeowners.
|
||||||
|
|
||||||
|
Input JSON (German):
|
||||||
|
{json.dumps(batch, ensure_ascii=False, indent=2)}
|
||||||
|
|
||||||
|
Return ONLY a valid JSON object with the same alarm keys. Each value must have exactly:
|
||||||
|
{{
|
||||||
|
"Explanation": "translated explanation (1 sentence)",
|
||||||
|
"Causes": ["translated cause 1", ...],
|
||||||
|
"NextSteps": ["translated step 1", ...]
|
||||||
|
}}
|
||||||
|
|
||||||
|
Reply with ONLY the JSON object, no markdown, no extra text."""
|
||||||
|
|
||||||
|
raw = call_mistral(api_key, prompt)
|
||||||
|
if raw is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
return json.loads(raw)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f" JSON parse error: {e}")
|
||||||
|
print(f" Raw (first 300 chars): {raw[:300]}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ── AlarmKnowledgeBase.cs generation ────────────────────────────────────────
|
||||||
|
|
||||||
|
def parse_kb_key_sections(filepath: str) -> dict:
|
||||||
|
"""
|
||||||
|
Reads AlarmKnowledgeBase.cs and returns {key: "Sinexcel"|"Growatt"}
|
||||||
|
preserving the original section order.
|
||||||
|
"""
|
||||||
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
sinexcel_match = re.search(r'SinexcelAlarms\s*=\s*new Dictionary.*?\{(.*?)^\s*\};', content, re.DOTALL | re.MULTILINE)
|
||||||
|
growatt_match = re.search(r'GrowattAlarms\s*=\s*new Dictionary.*?\{(.*?)^\s*\};', content, re.DOTALL | re.MULTILINE)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
if sinexcel_match:
|
||||||
|
for key in re.findall(r'\["(\w+)"\]\s*=\s*new\(\)', sinexcel_match.group(1)):
|
||||||
|
result[key] = "Sinexcel"
|
||||||
|
if growatt_match:
|
||||||
|
for key in re.findall(r'\["(\w+)"\]\s*=\s*new\(\)', growatt_match.group(1)):
|
||||||
|
result[key] = "Growatt"
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def cs_escape(s: str) -> str:
|
||||||
|
"""Escapes a string for use inside a C# double-quoted string literal."""
|
||||||
|
return s.replace("\\", "\\\\").replace('"', '\\"')
|
||||||
|
|
||||||
|
|
||||||
|
def write_knowledge_base_cs(filepath: str, en_translations: dict, key_sections: dict):
|
||||||
|
"""
|
||||||
|
Writes an updated AlarmKnowledgeBase.cs using the new English translations,
|
||||||
|
preserving the original Sinexcel/Growatt section structure.
|
||||||
|
"""
|
||||||
|
sinexcel_keys = [k for k, s in key_sections.items() if s == "Sinexcel"]
|
||||||
|
growatt_keys = [k for k, s in key_sections.items() if s == "Growatt"]
|
||||||
|
|
||||||
|
def entry_block(key: str) -> str:
|
||||||
|
entry = en_translations.get(key)
|
||||||
|
if not entry:
|
||||||
|
return f' // [{key}] — no translation available\n'
|
||||||
|
exp = cs_escape(entry.get("Explanation", ""))
|
||||||
|
causes = ",\n ".join(f'"{cs_escape(c)}"' for c in entry.get("Causes", []))
|
||||||
|
steps = ",\n ".join(f'"{cs_escape(s)}"' for s in entry.get("NextSteps", []))
|
||||||
|
return (
|
||||||
|
f' ["{key}"] = new()\n'
|
||||||
|
f' {{\n'
|
||||||
|
f' Explanation = "{exp}",\n'
|
||||||
|
f' Causes = new[] {{ {causes} }},\n'
|
||||||
|
f' NextSteps = new[] {{ {steps} }}\n'
|
||||||
|
f' }},\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
lines.append("namespace InnovEnergy.App.Backend.Services;\n")
|
||||||
|
lines.append("\n")
|
||||||
|
lines.append("/// <summary>\n")
|
||||||
|
lines.append("/// Static knowledge base for Sinexcel and Growatt alarms.\n")
|
||||||
|
lines.append("/// Provides pre-defined diagnostics without requiring Mistral API calls.\n")
|
||||||
|
lines.append("/// Updated by generate_alarm_translations.py after the review campaign.\n")
|
||||||
|
lines.append("/// </summary>\n")
|
||||||
|
lines.append("public static class AlarmKnowledgeBase\n")
|
||||||
|
lines.append("{\n")
|
||||||
|
lines.append(" public static DiagnosticResponse? TryGetDiagnosis(string alarmDescription)\n")
|
||||||
|
lines.append(" {\n")
|
||||||
|
lines.append(" if (string.IsNullOrWhiteSpace(alarmDescription)) return null;\n")
|
||||||
|
lines.append(" var normalized = alarmDescription.Trim();\n")
|
||||||
|
lines.append(" if (SinexcelAlarms.TryGetValue(normalized, out var s)) return s;\n")
|
||||||
|
lines.append(" if (GrowattAlarms.TryGetValue(normalized, out var g)) return g;\n")
|
||||||
|
lines.append(" var lower = normalized.ToLowerInvariant();\n")
|
||||||
|
lines.append(" foreach (var kvp in SinexcelAlarms) if (kvp.Key.ToLowerInvariant() == lower) return kvp.Value;\n")
|
||||||
|
lines.append(" foreach (var kvp in GrowattAlarms) if (kvp.Key.ToLowerInvariant() == lower) return kvp.Value;\n")
|
||||||
|
lines.append(" return null;\n")
|
||||||
|
lines.append(" }\n")
|
||||||
|
lines.append("\n")
|
||||||
|
lines.append(" // ── Sinexcel Alarms ──────────────────────────────────────────────────────\n")
|
||||||
|
lines.append("\n")
|
||||||
|
lines.append(" private static readonly IReadOnlyDictionary<string, DiagnosticResponse> SinexcelAlarms = new Dictionary<string, DiagnosticResponse>\n")
|
||||||
|
lines.append(" {\n")
|
||||||
|
for key in sinexcel_keys:
|
||||||
|
lines.append(entry_block(key))
|
||||||
|
lines.append(" };\n")
|
||||||
|
lines.append("\n")
|
||||||
|
lines.append(" // ── Growatt Alarms ───────────────────────────────────────────────────────\n")
|
||||||
|
lines.append("\n")
|
||||||
|
lines.append(" private static readonly IReadOnlyDictionary<string, DiagnosticResponse> GrowattAlarms = new Dictionary<string, DiagnosticResponse>\n")
|
||||||
|
lines.append(" {\n")
|
||||||
|
for key in growatt_keys:
|
||||||
|
lines.append(entry_block(key))
|
||||||
|
lines.append(" };\n")
|
||||||
|
lines.append("}\n")
|
||||||
|
|
||||||
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
|
f.writelines(lines)
|
||||||
|
print(f" ✓ Wrote updated AlarmKnowledgeBase.cs ({len(sinexcel_keys)} Sinexcel + {len(growatt_keys)} Growatt keys)")
|
||||||
|
|
||||||
|
|
||||||
|
# ── Main ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def load_env_file(env_path: str) -> dict:
|
||||||
|
env = {}
|
||||||
|
try:
|
||||||
|
with open(env_path) as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith("#") and "=" in line:
|
||||||
|
k, _, v = line.partition("=")
|
||||||
|
env[k.strip()] = v.strip()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
api_key = os.environ.get("MISTRAL_API_KEY", "").strip()
|
||||||
|
if not api_key:
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
api_key = load_env_file(os.path.join(script_dir, ".env")).get("MISTRAL_API_KEY", "").strip()
|
||||||
|
|
||||||
|
if not api_key:
|
||||||
|
print("ERROR: MISTRAL_API_KEY not found in environment or .env file.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("MISTRAL_API_KEY loaded.")
|
||||||
|
|
||||||
|
# Load reviewed German source
|
||||||
|
if not os.path.exists(CHECKED_FILE):
|
||||||
|
print(f"ERROR: {CHECKED_FILE} not found. Run the review campaign first.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(CHECKED_FILE, "r", encoding="utf-8") as f:
|
||||||
|
german_source = json.load(f)
|
||||||
|
|
||||||
|
alarm_keys = list(german_source.keys())
|
||||||
|
print(f"Loaded {len(alarm_keys)} alarms from {CHECKED_FILE}.")
|
||||||
|
|
||||||
|
# Step 1: copy reviewed German as the new de.json
|
||||||
|
de_out = os.path.join(RESOURCES_DIR, "AlarmTranslations.de.json")
|
||||||
|
shutil.copy(CHECKED_FILE, de_out)
|
||||||
|
print(f"\n✓ Copied reviewed German → {de_out}")
|
||||||
|
|
||||||
|
# Step 2: translate to en, fr, it
|
||||||
|
all_translations = {} # lang_code → {key → entry}
|
||||||
|
for lang_code, lang_name in TARGET_LANGUAGES.items():
|
||||||
|
print(f"\n── Translating to {lang_name} ({lang_code}) ──")
|
||||||
|
|
||||||
|
translations = {}
|
||||||
|
failed_keys = []
|
||||||
|
|
||||||
|
batches = [
|
||||||
|
{k: german_source[k] for k in alarm_keys[i:i + BATCH_SIZE]}
|
||||||
|
for i in range(0, len(alarm_keys), BATCH_SIZE)
|
||||||
|
]
|
||||||
|
|
||||||
|
for batch_num, batch in enumerate(batches, 1):
|
||||||
|
keys_in_batch = list(batch.keys())
|
||||||
|
print(f" Batch {batch_num}/{len(batches)}: {', '.join(keys_in_batch)}")
|
||||||
|
|
||||||
|
result = translate_batch(api_key, batch, lang_name)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
print(f" FAILED batch {batch_num} — marking keys as failed")
|
||||||
|
failed_keys.extend(keys_in_batch)
|
||||||
|
continue
|
||||||
|
|
||||||
|
for key in keys_in_batch:
|
||||||
|
if key in result:
|
||||||
|
entry = result[key]
|
||||||
|
translations[key] = {
|
||||||
|
"Explanation": entry.get("Explanation", ""),
|
||||||
|
"Causes": entry.get("Causes", []),
|
||||||
|
"NextSteps": entry.get("NextSteps", []),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
print(f" WARNING: key '{key}' missing from batch result")
|
||||||
|
failed_keys.append(key)
|
||||||
|
|
||||||
|
if batch_num < len(batches):
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
all_translations[lang_code] = translations
|
||||||
|
out_file = os.path.join(RESOURCES_DIR, f"AlarmTranslations.{lang_code}.json")
|
||||||
|
with open(out_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(translations, f, ensure_ascii=False, indent=2)
|
||||||
|
print(f" ✓ Wrote {len(translations)} entries → {out_file}")
|
||||||
|
|
||||||
|
if failed_keys:
|
||||||
|
print(f" ⚠ Failed keys ({len(failed_keys)}): {failed_keys}")
|
||||||
|
|
||||||
|
# Step 3: update AlarmKnowledgeBase.cs with the new English back-translation
|
||||||
|
print("\n── Updating AlarmKnowledgeBase.cs ──")
|
||||||
|
if "en" in all_translations and os.path.exists(KNOWLEDGE_BASE):
|
||||||
|
key_sections = parse_kb_key_sections(KNOWLEDGE_BASE)
|
||||||
|
write_knowledge_base_cs(KNOWLEDGE_BASE, all_translations["en"], key_sections)
|
||||||
|
else:
|
||||||
|
print(" Skipped — en.json not generated or AlarmKnowledgeBase.cs not found.")
|
||||||
|
|
||||||
|
print("\n✓ Done. Review the output files before deploying.")
|
||||||
|
print(" Next: cd csharp/App/Backend && dotnet build && ./deploy.sh")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Binary file not shown.
|
|
@ -63,6 +63,14 @@ function Log(props: LogProps) {
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
/** "AbnormalGridVoltage" → "Abnormal Grid Voltage" */
|
||||||
|
const splitCamelCase = (s: string) =>
|
||||||
|
s.replace(/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g, ' ').trim();
|
||||||
|
|
||||||
|
/** Returns a translated alarm display name, falling back to camelCase split. */
|
||||||
|
const alarmDisplayName = (description: string) =>
|
||||||
|
intl.formatMessage({ id: `alarm_${description}`, defaultMessage: splitCamelCase(description) });
|
||||||
|
|
||||||
const [diagnoses, setDiagnoses] = useState<{ description: string; lastSeen: string; response: DiagnosticResponse }[]>([]);
|
const [diagnoses, setDiagnoses] = useState<{ description: string; lastSeen: string; response: DiagnosticResponse }[]>([]);
|
||||||
const [diagnosisLoading, setDiagnosisLoading] = useState(false);
|
const [diagnosisLoading, setDiagnosisLoading] = useState(false);
|
||||||
const [expandedDiagnoses, setExpandedDiagnoses] = useState<Set<number>>(new Set());
|
const [expandedDiagnoses, setExpandedDiagnoses] = useState<Set<number>>(new Set());
|
||||||
|
|
@ -100,15 +108,8 @@ function Log(props: LogProps) {
|
||||||
});
|
});
|
||||||
}, [updateCount]);
|
}, [updateCount]);
|
||||||
|
|
||||||
// fetch AI diagnosis for the latest 3 unique errors/warnings
|
// fetch AI diagnosis for all unique errors/warnings from the last 24 hours
|
||||||
// only when installation status is red (2) or orange (1)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// skip diagnosis if status is not alarm (2) or warning (1)
|
|
||||||
if (props.status !== 1 && props.status !== 2) {
|
|
||||||
setDiagnoses([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter to last 24 hours only
|
// filter to last 24 hours only
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const cutoff = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
const cutoff = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
||||||
|
|
@ -122,13 +123,13 @@ function Log(props: LogProps) {
|
||||||
})
|
})
|
||||||
.sort((a, b) => (b.date + ' ' + b.time).localeCompare(a.date + ' ' + a.time));
|
.sort((a, b) => (b.date + ' ' + b.time).localeCompare(a.date + ' ' + a.time));
|
||||||
|
|
||||||
|
// deduplicate — keep the most-recent occurrence of each unique description
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const targets: ErrorMessage[] = [];
|
const targets: ErrorMessage[] = [];
|
||||||
for (const item of all) {
|
for (const item of all) {
|
||||||
if (!seen.has(item.description)) {
|
if (!seen.has(item.description)) {
|
||||||
seen.add(item.description);
|
seen.add(item.description);
|
||||||
targets.push(item);
|
targets.push(item);
|
||||||
if (targets.length >= 3) break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +147,7 @@ function Log(props: LogProps) {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
targets.map(target =>
|
targets.map(target =>
|
||||||
axiosConfig
|
axiosConfig
|
||||||
.get(`/DiagnoseError?installationId=${props.id}&errorDescription=${encodeURIComponent(target.description)}`)
|
.get(`/DiagnoseError?installationId=${props.id}&errorDescription=${encodeURIComponent(target.description)}&language=${intl.locale}`)
|
||||||
.then((res: AxiosResponse<DiagnosticResponse>) => {
|
.then((res: AxiosResponse<DiagnosticResponse>) => {
|
||||||
if (res.status === 204 || !res.data || !res.data.explanation) return null;
|
if (res.status === 204 || !res.data || !res.data.explanation) return null;
|
||||||
return { description: target.description, lastSeen: target.date + ' ' + target.time, response: res.data };
|
return { description: target.description, lastSeen: target.date + ' ' + target.time, response: res.data };
|
||||||
|
|
@ -158,7 +159,7 @@ function Log(props: LogProps) {
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
setDiagnosisLoading(false);
|
setDiagnosisLoading(false);
|
||||||
});
|
});
|
||||||
}, [errors, warnings, props.status]);
|
}, [errors, warnings]);
|
||||||
|
|
||||||
const handleErrorButtonPressed = () => {
|
const handleErrorButtonPressed = () => {
|
||||||
setErrorButtonPressed(!errorButtonPressed);
|
setErrorButtonPressed(!errorButtonPressed);
|
||||||
|
|
@ -233,7 +234,7 @@ function Log(props: LogProps) {
|
||||||
setDemoLoading(true);
|
setDemoLoading(true);
|
||||||
setDemoResult(null);
|
setDemoResult(null);
|
||||||
axiosConfigWithoutToken
|
axiosConfigWithoutToken
|
||||||
.get(`/TestDiagnoseError?errorDescription=${encodeURIComponent(alarm)}`)
|
.get(`/TestDiagnoseError?errorDescription=${encodeURIComponent(alarm)}&language=${intl.locale}`)
|
||||||
.then((res: AxiosResponse<TestDiagnoseResult>) => {
|
.then((res: AxiosResponse<TestDiagnoseResult>) => {
|
||||||
setDemoResult(res.data);
|
setDemoResult(res.data);
|
||||||
})
|
})
|
||||||
|
|
@ -253,296 +254,6 @@ function Log(props: LogProps) {
|
||||||
return <Chip label="Not available" size="small" color="default" />;
|
return <Chip label="Not available" size="small" color="default" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const warningDescriptionMap: { [key: string]: string } = {
|
|
||||||
// BMS warnings
|
|
||||||
"TaM1": "TaM1: BMS temperature high",
|
|
||||||
"TbM1": "TbM1: Battery temperature high",
|
|
||||||
"VBm1": "VBm1: Bus voltage low",
|
|
||||||
"VBM1": "VBM1: Bus voltage high",
|
|
||||||
"IDM1": "IDM1: Discharge current high",
|
|
||||||
"vsm1": "vsm1: String voltage low",
|
|
||||||
"vsM1": "vsM1: String voltage high",
|
|
||||||
"iCM1": "iCM1: Charge current high",
|
|
||||||
"iDM1": "iDM1: Discharge current high",
|
|
||||||
"MID1": "MID1: String voltages unbalanced",
|
|
||||||
"BLPW": "BLPW: Not enough charging power on bus",
|
|
||||||
"CCBF": "CCBF: Internal charger hardware failure",
|
|
||||||
"Ah_W": "Ah_W: String SOC low",
|
|
||||||
"MPMM": "MPMM: Midpoint wiring problem",
|
|
||||||
"TCdi": "TCdi: Temperature difference between strings high",
|
|
||||||
"LMPW": "LMPW: String voltages unbalance warning",
|
|
||||||
"TOCW": "TOCW: Top of Charge requested",
|
|
||||||
|
|
||||||
// Sinexcel warnings (WARNING/INFO severity)
|
|
||||||
"Inverted sequenceof grid voltage": "Grid phase sequence reversed",
|
|
||||||
"Excessivelyhigh ambient temperature": "Ambient temperature too high",
|
|
||||||
"Excessive radiator temperature": "Radiator/heatsink temperature high",
|
|
||||||
"Island protection": "Island protection active (auto-recovers)",
|
|
||||||
"Battery 1over voltage": "Battery 1 voltage too high",
|
|
||||||
"Battery 1under voltage": "Battery 1 voltage too low",
|
|
||||||
"Battery 1discharge end": "Battery 1 discharge complete (auto-recovers)",
|
|
||||||
"Battery 1inverted": "Battery 1 polarity reversed!",
|
|
||||||
"Battery 2over voltage": "Battery 2 voltage too high",
|
|
||||||
"Battery 2under voltage": "Battery 2 voltage too low",
|
|
||||||
"Battery 2discharge end": "Battery 2 discharge complete (auto-recovers)",
|
|
||||||
"Battery 2inverted": "Battery 2 polarity reversed!",
|
|
||||||
"PV 1notaccessed": "PV string 1 not accessible",
|
|
||||||
"PV 1over voltage": "PV string 1 voltage too high",
|
|
||||||
"PV 2notaccessed": "PV string 2 not accessible",
|
|
||||||
"PV 2over voltage": "PV string 2 voltage too high",
|
|
||||||
"DC busover voltage": "DC bus voltage too high",
|
|
||||||
"DC busunder voltage": "DC bus voltage too low",
|
|
||||||
"Inverter soft start failure": "Inverter soft-start failed",
|
|
||||||
"Battery 1soft start failure": "Battery 1 soft-start failed",
|
|
||||||
"Battery 2soft start failure": "Battery 2 soft-start failed",
|
|
||||||
"Output voltageDC overlimit": "DC component in output voltage high",
|
|
||||||
"Output currentDC overlimit": "DC component in output current high",
|
|
||||||
"Poorgrounding": "Poor ground connection detected",
|
|
||||||
"PV 1soft startfailure": "PV 1 soft-start failed",
|
|
||||||
"PV 2soft startfailure": "PV 2 soft-start failed",
|
|
||||||
"PCBover temperature": "PCB temperature too high",
|
|
||||||
"DC converter over temperature": "DC converter temperature high",
|
|
||||||
"Busslow over voltage": "Slow bus over-voltage",
|
|
||||||
"DC converter over voltage": "DC converter voltage high",
|
|
||||||
"DC converter over current": "DC converter current high",
|
|
||||||
"DC converter resonator over current": "DC converter resonator overcurrent",
|
|
||||||
"PV 1insufficient power": "PV 1 power insufficient (auto-recovers)",
|
|
||||||
"PV 2insufficient power": "PV 2 power insufficient (auto-recovers)",
|
|
||||||
"Battery 1insufficient power": "Battery 1 power insufficient (auto-recovers)",
|
|
||||||
"Battery 2insufficiency power": "Battery 2 power insufficient",
|
|
||||||
"Lithium battery 1 chargeforbidden": "Lithium battery 1 charging forbidden",
|
|
||||||
"Lithium battery 1 dischargeforbidden": "Lithium battery 1 discharging forbidden",
|
|
||||||
"Lithium battery 2 chargeforbidden": "Lithium battery 2 charging forbidden",
|
|
||||||
"Lithium battery 2 dischargeforbidden": "Lithium battery 2 discharging forbidden",
|
|
||||||
"Lithium battery 1full": "Lithium battery 1 fully charged",
|
|
||||||
"Lithium battery 1 dischargeend": "Lithium battery 1 discharge end",
|
|
||||||
"Lithium battery 2full": "Lithium battery 2 fully charged",
|
|
||||||
"Lithium battery 2 dischargeend": "Lithium battery 2 discharge end",
|
|
||||||
"Inverter over temperaturealarm": "Inverter over-temperature alarm",
|
|
||||||
"Inverter over temperature": "Inverter temperature high",
|
|
||||||
"DC converter over temperaturealarm": "DC converter over-temperature alarm",
|
|
||||||
"Systemderating": "System power derating active",
|
|
||||||
"PVaccessmethod erroralarm": "PV access method error",
|
|
||||||
"Parallelmodule missing": "Parallel module missing",
|
|
||||||
"Duplicatemachine numbersforparallel modules": "Duplicate parallel module IDs",
|
|
||||||
"Para meterconflictin parallelmodule": "Parameter conflict in parallel modules",
|
|
||||||
"Reservedalarms 4": "Reserved alarm 4",
|
|
||||||
"InverterSealPulse": "Inverter seal pulse active",
|
|
||||||
"PV 3over voltage": "PV 3 voltage too high",
|
|
||||||
"PV 3average current anomaly": "PV 3 current anomaly",
|
|
||||||
"PV 4over voltage": "PV 4 voltage too high",
|
|
||||||
"PV 4average current anomaly": "PV 4 current anomaly",
|
|
||||||
"PV 3soft startfailure": "PV 3 soft-start failed",
|
|
||||||
"PV 4soft startfailure": "PV 4 soft-start failed",
|
|
||||||
"Batteryaccessmethod error": "Battery access method error",
|
|
||||||
"Reservedalarms 5": "Reserved alarm 5",
|
|
||||||
"Battery 1backup prohibited": "Battery 1 backup prohibited",
|
|
||||||
"Battery 2backup prohibited": "Battery 2 backup prohibited",
|
|
||||||
"Bus soft startfailure": "Bus soft-start failed",
|
|
||||||
"Insufficient photovoltaic power": "Insufficient PV power",
|
|
||||||
"Photovoltaic 1 over current": "PV 1 overcurrent",
|
|
||||||
"Photovoltaic 2 over current": "PV 2 overcurrent",
|
|
||||||
"Photovoltaic 3 over current": "PV 3 overcurrent",
|
|
||||||
"Photovoltaic 4 over current": "PV 4 overcurrent",
|
|
||||||
"Battery 1over current": "Battery 1 overcurrent",
|
|
||||||
"Battery 2over current": "Battery 2 overcurrent",
|
|
||||||
"Battery 1charging sealingwave": "Battery 1 charge limiting",
|
|
||||||
"Battery 2charging sealingwave": "Battery 2 charge limiting",
|
|
||||||
|
|
||||||
// Growatt warnings
|
|
||||||
"Warning 200": "String fault",
|
|
||||||
"Warning 201": "PV string/PID terminals abnormal",
|
|
||||||
"Warning 203": "PV1 or PV2 short circuited",
|
|
||||||
"Warning 208": "DC fuse blown",
|
|
||||||
"Warning 209": "DC input voltage too high",
|
|
||||||
"Warning 219": "PID function abnormal",
|
|
||||||
"Warning 220": "PV string disconnected",
|
|
||||||
"Warning 221": "PV string current unbalanced",
|
|
||||||
"Warning 300": "No grid connection / grid power failure",
|
|
||||||
"Warning 301": "Grid voltage out of range",
|
|
||||||
"Warning 302": "Grid frequency out of range",
|
|
||||||
"Warning 303": "System overload",
|
|
||||||
"Warning 308": "Meter disconnected",
|
|
||||||
"Warning 309": "Meter L/N reversed",
|
|
||||||
"Warning 310": "N-PE voltage abnormal",
|
|
||||||
"Warning 311": "Phase sequence error (auto-adjusts)",
|
|
||||||
"Warning 400": "Fan failure",
|
|
||||||
"Warning 401": "Meter abnormal",
|
|
||||||
"Warning 402": "Optimizer communication abnormal",
|
|
||||||
"Warning 407": "Over-temperature",
|
|
||||||
"Warning 408": "NTC temperature sensor broken",
|
|
||||||
"Warning 411": "Sync signal abnormal",
|
|
||||||
"Warning 412": "Grid connection requirements not met",
|
|
||||||
"Warning 500": "Inverter-battery communication failed",
|
|
||||||
"Warning 501": "Battery disconnected",
|
|
||||||
"Warning 502": "Battery voltage too high",
|
|
||||||
"Warning 503": "Battery voltage too low",
|
|
||||||
"Warning 504": "Battery terminals reversed",
|
|
||||||
"Warning 505": "Lead-acid battery temp sensor disconnected",
|
|
||||||
"Warning 506": "Battery temperature out of range",
|
|
||||||
"Warning 507": "BMS fault: charging/discharging failed",
|
|
||||||
"Warning 508": "Lithium battery overload protection",
|
|
||||||
"Warning 509": "BMS communication abnormal",
|
|
||||||
"Warning 510": "BAT SPD function abnormal",
|
|
||||||
"Warning 600": "Output DC component bias abnormal",
|
|
||||||
"Warning 601": "High DC in output voltage",
|
|
||||||
"Warning 602": "Off-grid output voltage too low",
|
|
||||||
"Warning 603": "Off-grid output voltage too high",
|
|
||||||
"Warning 604": "Off-grid output overcurrent",
|
|
||||||
"Warning 605": "Off-grid bus voltage too low",
|
|
||||||
"Warning 606": "Off-grid output overload",
|
|
||||||
"Warning 609": "Balanced circuit abnormal"
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorDescriptionMap: { [key: string]: string } = {
|
|
||||||
// BMS errors
|
|
||||||
"Tam": "Tam: Recoverable, BMS temperature too low",
|
|
||||||
"TaM2": "TaM2: Recoverable, BMS temperature too high",
|
|
||||||
"Tbm": "Tbm: Recoverable, Battery temperature too low",
|
|
||||||
"TbM2": "TbM2: Recoverable, Battery temperature too high",
|
|
||||||
"VBm2": "VBm2: Recoverable, Recoverable: Bus voltage too low",
|
|
||||||
"VBM2": "VBM2: Recoverable,Recoverable: Bus voltage too high",
|
|
||||||
"IDM2": "IDM2: Recoverable, Discharge current too high",
|
|
||||||
"ISOB": "ISOB: Unrecoverable, Electrical insulation failure",
|
|
||||||
"MSWE": "MSWE: Unrecoverable, Main switch failure",
|
|
||||||
"FUSE": "FUSE: Unrecoverable, Main fuse blown",
|
|
||||||
"HTRE": "HTRE: Recoverable, Battery failed to warm up",
|
|
||||||
"TCPE": "TCPE: Unrecoverable, Temperature sensor failure",
|
|
||||||
"STRE": "STRE: Recoverable, Voltage measurement circuit fails",
|
|
||||||
"CME": "CME: Recoverable, Current sensor failure",
|
|
||||||
"HWFL": "HWFL: Recoverable, BMS hardware failure",
|
|
||||||
"HWEM": "HWEM: Recoverable, Hardware protection tripped",
|
|
||||||
"ThM": "ThM: Recoverable, Heatsink temperature too high",
|
|
||||||
"vsm2": "vsm2: Unrecoverable, Low string voltage failure",
|
|
||||||
"vsM2": "vsM2: Recoverable, String voltage too high",
|
|
||||||
"iCM2": "iCM2: Unrecoverable, Charge current too high",
|
|
||||||
"iDM2": "iDM2: Recoverable, Discharge current too high",
|
|
||||||
"MID2": "MID2: Recoverable, String voltage unbalance too high",
|
|
||||||
"HTFS": "HTFS: Recoverable, Unrecoverable: Heater Fuse Blown",
|
|
||||||
"DATA": "DATA: Recoverable, Unrecoverable: Parameters out of range",
|
|
||||||
"LMPA": "LMPA: Unrecoverable, String voltages unbalance alarm",
|
|
||||||
"HEBT": "HEBT: Recoverable, oss of heartbeat",
|
|
||||||
|
|
||||||
// Sinexcel errors (ERROR severity - require manual intervention)
|
|
||||||
"Abnormal grid voltage": "Grid voltage abnormal",
|
|
||||||
"Abnormal grid frequency": "Grid frequency abnormal",
|
|
||||||
"Grid voltage phase loss": "Grid phase loss detected",
|
|
||||||
"Abnormal output voltage": "Output voltage abnormal",
|
|
||||||
"Abnormal output frequency": "Output frequency abnormal",
|
|
||||||
"Abnormalnullline": "Null/neutral line abnormal",
|
|
||||||
"Insulation fault": "Insulation fault detected",
|
|
||||||
"Leakage protection fault": "Leakage/ground fault protection tripped",
|
|
||||||
"Auxiliary power fault": "Auxiliary power supply fault",
|
|
||||||
"Fan fault": "Cooling fan fault",
|
|
||||||
"Model capacity fault": "Model/capacity configuration fault",
|
|
||||||
"Abnormal lightning arrester": "Surge protection device abnormal",
|
|
||||||
"Battery 1not connected": "Battery 1 not connected",
|
|
||||||
"Battery 2not connected": "Battery 2 not connected",
|
|
||||||
"AbnormalPV 1current sharing": "PV 1 current sharing abnormal",
|
|
||||||
"AbnormalPV 2current sharing": "PV 2 current sharing abnormal",
|
|
||||||
"DC bus voltage unbalance": "DC bus voltage unbalance",
|
|
||||||
"System output overload": "System output overloaded",
|
|
||||||
"Inverter overload": "Inverter overloaded",
|
|
||||||
"Inverter overload timeout": "Inverter overload timeout",
|
|
||||||
"Battery 1overload timeout": "Battery 1 overload timeout",
|
|
||||||
"Battery 2overload timeout": "Battery 2 overload timeout",
|
|
||||||
"DSP 1para meter setting fault": "DSP 1 parameter setting fault",
|
|
||||||
"DSP 2para meter setting fault": "DSP 2 parameter setting fault",
|
|
||||||
"DSPversion compatibility fault": "DSP version compatibility fault",
|
|
||||||
"CPLDversion compatibility fault": "CPLD version compatibility fault",
|
|
||||||
"CPLD communication fault": "CPLD communication fault",
|
|
||||||
"DSP communication fault": "DSP communication fault",
|
|
||||||
"Relayself-checkfails": "Relay self-check failed",
|
|
||||||
"Abnormal inverter": "Abnormal inverter condition",
|
|
||||||
"Balancedcircuit overload timeout": "Balance circuit overload timeout",
|
|
||||||
"PV 1overload timeout": "PV 1 overload timeout",
|
|
||||||
"PV 2overload timeout": "PV 2 overload timeout",
|
|
||||||
"Abnormaloff-grid output voltage": "Off-grid output voltage abnormal",
|
|
||||||
"Parallel communicationalarm": "Parallel communication alarm",
|
|
||||||
"Inverter relayopen": "Inverter relay open",
|
|
||||||
"PV 3not connected": "PV 3 not connected",
|
|
||||||
"PV 4not connected": "PV 4 not connected",
|
|
||||||
"PV 3overload timeout": "PV 3 overload timeout",
|
|
||||||
"PV 4overload timeout": "PV 4 overload timeout",
|
|
||||||
"Abnormal diesel generator voltage": "Diesel generator voltage abnormal",
|
|
||||||
"Abnormal diesel generator frequency": "Diesel generator frequency abnormal",
|
|
||||||
"Diesel generator voltageoutof phase": "Diesel generator out of phase",
|
|
||||||
"Lead battery temperature abnormality": "Lead battery temperature abnormal",
|
|
||||||
"Abnormal grid current": "Grid current abnormal",
|
|
||||||
"Generator overload": "Generator overloaded",
|
|
||||||
"Opencircuitof power grid relay": "Grid relay open circuit",
|
|
||||||
"Shortcircuitof power grid relay": "Grid relay short circuit",
|
|
||||||
"generator Relayopencircuit": "Generator relay open circuit",
|
|
||||||
"generator Relayshortcircuit": "Generator relay short circuit",
|
|
||||||
"Load power overload": "Load power overload",
|
|
||||||
"Abnormal leakage self-check": "Leakage self-check abnormal",
|
|
||||||
|
|
||||||
// Sinexcel PROTECTION errors (require service - do not restart)
|
|
||||||
"PV 1power tube fault": "PV 1 power tube fault - Contact Service",
|
|
||||||
"PV 2power tube fault": "PV 2 power tube fault - Contact Service",
|
|
||||||
"Battery 1power tube fault": "Battery 1 power tube fault - Contact Service",
|
|
||||||
"Battery 2power tube fault": "Battery 2 power tube fault - Contact Service",
|
|
||||||
"Inverter power tube fault": "Inverter power tube fault - Contact Service",
|
|
||||||
"Hardware bus over voltage": "Hardware bus overvoltage - Contact Service",
|
|
||||||
"Hardware over current": "Hardware overcurrent - Contact Service",
|
|
||||||
"DC converter hardware over voltage": "DC converter hardware overvoltage - Contact Service",
|
|
||||||
"DC converter hardware over current": "DC converter hardware overcurrent - Contact Service",
|
|
||||||
"Inverter relayshort circuit": "Inverter relay short circuit - Contact Service",
|
|
||||||
"Reverse meter connection": "Meter connected in reverse - Contact Service",
|
|
||||||
"PV 3power tube failure": "PV 3 power tube failure - Contact Service",
|
|
||||||
"PV 4power tube Failure": "PV 4 power tube failure - Contact Service",
|
|
||||||
"PV 3reverse connection": "PV 3 reverse connection - Contact Service",
|
|
||||||
"PV 4reverse connection": "PV 4 reverse connection - Contact Service",
|
|
||||||
"Diesel generator voltage reverse sequence": "Generator phase reversed - Contact Service",
|
|
||||||
|
|
||||||
// Growatt errors (PROTECTION severity)
|
|
||||||
"Error 309": "Grid ROCOF abnormal",
|
|
||||||
"Error 311": "Export limitation fail-safe",
|
|
||||||
"Error 400": "DCI bias abnormal",
|
|
||||||
"Error 402": "High DC in output current",
|
|
||||||
"Error 404": "Bus voltage sampling abnormal",
|
|
||||||
"Error 405": "Relay fault",
|
|
||||||
"Error 408": "Over-temperature protection",
|
|
||||||
"Error 409": "Bus voltage abnormal",
|
|
||||||
"Error 411": "Internal communication failure",
|
|
||||||
"Error 412": "Temperature sensor disconnected",
|
|
||||||
"Error 413": "IGBT drive fault",
|
|
||||||
"Error 414": "EEPROM error",
|
|
||||||
"Error 415": "Auxiliary power supply abnormal",
|
|
||||||
"Error 416": "DC/AC overcurrent protection",
|
|
||||||
"Error 417": "Communication protocol mismatch",
|
|
||||||
"Error 418": "DSP/COM firmware mismatch",
|
|
||||||
"Error 419": "DSP software/hardware mismatch",
|
|
||||||
"Error 421": "CPLD abnormal",
|
|
||||||
"Error 422": "Redundancy sampling inconsistent",
|
|
||||||
"Error 423": "PWM pass-through signal failure",
|
|
||||||
"Error 425": "AFCI self-test failure",
|
|
||||||
"Error 426": "PV current sampling abnormal",
|
|
||||||
"Error 427": "AC current sampling abnormal",
|
|
||||||
"Error 429": "BUS soft-boot failure",
|
|
||||||
"Error 430": "EPO fault",
|
|
||||||
"Error 431": "Monitoring chip BOOT verification failed",
|
|
||||||
"Error 500": "BMS-inverter communication failed",
|
|
||||||
"Error 501": "BMS: battery charge/discharge failed",
|
|
||||||
"Error 503": "Battery voltage exceeds threshold",
|
|
||||||
"Error 504": "Battery temperature out of range",
|
|
||||||
"Error 506": "Battery open-circuited",
|
|
||||||
"Error 507": "Battery overload protection",
|
|
||||||
"Error 508": "BUS2 voltage abnormal",
|
|
||||||
"Error 509": "BAT charge overcurrent protection",
|
|
||||||
"Error 510": "BAT discharge overcurrent protection",
|
|
||||||
"Error 511": "BAT soft start failed",
|
|
||||||
"Error 601": "Off-grid bus voltage low",
|
|
||||||
"Error 602": "Abnormal voltage at off-grid terminal",
|
|
||||||
"Error 603": "Off-grid soft start failed",
|
|
||||||
"Error 604": "Off-grid output voltage abnormal",
|
|
||||||
"Error 605": "Balanced circuit self-test failed",
|
|
||||||
"Error 606": "High DC in output voltage",
|
|
||||||
"Error 608": "Off-grid parallel signal abnormal",
|
|
||||||
"AFCI Fault": "Arc fault detected - Check PV connections",
|
|
||||||
"GFCI High": "High leakage current detected",
|
|
||||||
"PV Voltage High": "DC input voltage exceeds limit"
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
|
|
@ -613,7 +324,7 @@ function Log(props: LogProps) {
|
||||||
<Box sx={{ mt: 2 }}>
|
<Box sx={{ mt: 2 }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: '8px', mb: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: '8px', mb: 1 }}>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
<strong>{demoResult.alarm}</strong>
|
<strong>{splitCamelCase(demoResult.alarm)}</strong>
|
||||||
</Typography>
|
</Typography>
|
||||||
{sourceChip(demoResult.source)}
|
{sourceChip(demoResult.source)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -667,7 +378,7 @@ function Log(props: LogProps) {
|
||||||
<Box sx={{ padding: '16px' }}>
|
<Box sx={{ padding: '16px' }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: '8px', mb: 1 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: '8px', mb: 1 }}>
|
||||||
<Typography variant="subtitle2" fontWeight="bold" color="primary">
|
<Typography variant="subtitle2" fontWeight="bold" color="primary">
|
||||||
{diag.description}
|
{diag.response.name || alarmDisplayName(diag.description)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
<FormattedMessage id="lastSeen" defaultMessage="Last seen" />: {diag.lastSeen}
|
<FormattedMessage id="lastSeen" defaultMessage="Last seen" />: {diag.lastSeen}
|
||||||
|
|
@ -724,7 +435,7 @@ function Log(props: LogProps) {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleErrorButtonPressed}
|
onClick={handleErrorButtonPressed}
|
||||||
sx={{ marginTop: '20px', backgroundColor: errorButtonPressed ? '#808080' : 'default'}}
|
sx={{ marginTop: '20px', backgroundColor: errorButtonPressed ? '#808080' : 'default', textTransform: 'none' }}
|
||||||
>
|
>
|
||||||
<FormattedMessage id="Show Errors" defaultMessage="Show Errors" />
|
<FormattedMessage id="Show Errors" defaultMessage="Show Errors" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -914,7 +625,7 @@ function Log(props: LogProps) {
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{errorDescriptionMap[error.description] || error.description}
|
{alarmDisplayName(error.description)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -1035,7 +746,7 @@ function Log(props: LogProps) {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleWarningButtonPressed}
|
onClick={handleWarningButtonPressed}
|
||||||
sx={{ marginTop: '20px', backgroundColor: warningButtonPressed ? '#808080' : 'default'}}
|
sx={{ marginTop: '20px', backgroundColor: warningButtonPressed ? '#808080' : 'default', textTransform: 'none' }}
|
||||||
|
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|
@ -1229,7 +940,7 @@ function Log(props: LogProps) {
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{warningDescriptionMap[warning.description] || warning.description}
|
{alarmDisplayName(warning.description)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ interface WeeklyReportResponse {
|
||||||
periodEnd: string;
|
periodEnd: string;
|
||||||
currentWeek: WeeklySummary;
|
currentWeek: WeeklySummary;
|
||||||
previousWeek: WeeklySummary | null;
|
previousWeek: WeeklySummary | null;
|
||||||
|
totalEnergySaved: number;
|
||||||
|
totalSavingsCHF: number;
|
||||||
|
daysEquivalent: number;
|
||||||
selfSufficiencyPercent: number;
|
selfSufficiencyPercent: number;
|
||||||
selfConsumptionPercent: number;
|
selfConsumptionPercent: number;
|
||||||
batteryEfficiencyPercent: number;
|
batteryEfficiencyPercent: number;
|
||||||
|
|
@ -54,25 +57,25 @@ interface WeeklyReportResponse {
|
||||||
aiInsight: string;
|
aiInsight: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Matches: time ranges (14:00–18:00), times (09:00), decimals (126.4 / 1,3), integers (34)
|
||||||
|
// Any number in any language gets bolded — no unit matching needed
|
||||||
|
const BOLD_PATTERN = /(\d{1,2}:\d{2}(?:[–\-]\d{1,2}:\d{2})?|\d+[.,]\d+|\d+)/g;
|
||||||
|
const isBold = (s: string) => /\d/.test(s);
|
||||||
|
|
||||||
// Renders a bullet line: bolds the "Title" part before the first colon, and numbers with units
|
// Renders a bullet line: bolds the "Title" part before the first colon, and numbers with units
|
||||||
function FormattedBullet({ text }: { text: string }) {
|
function FormattedBullet({ text }: { text: string }) {
|
||||||
const colonIdx = text.indexOf(':');
|
const colonIdx = text.indexOf(':');
|
||||||
if (colonIdx > 0) {
|
if (colonIdx > 0) {
|
||||||
const title = text.slice(0, colonIdx);
|
const title = text.slice(0, colonIdx);
|
||||||
const rest = text.slice(colonIdx + 1); // e.g. " This week, your system saved 120.9 kWh..."
|
const rest = text.slice(colonIdx + 1); // e.g. " This week, your system saved 120.9 kWh..."
|
||||||
// Bold numbers+units in the rest
|
const restParts = rest.split(BOLD_PATTERN).map((p, i) =>
|
||||||
const restParts = rest.split(/(\d+[\d,.]*\s*(?:kWh|CHF|%|days?))/g).map((p, i) =>
|
isBold(p) ? <strong key={i}>{p}</strong> : <span key={i}>{p}</span>
|
||||||
/\d+[\d,.]*\s*(?:kWh|CHF|%|days?)/.test(p)
|
|
||||||
? <strong key={i}>{p}</strong>
|
|
||||||
: <span key={i}>{p}</span>
|
|
||||||
);
|
);
|
||||||
return <><strong>{title}</strong>:{restParts}</>;
|
return <><strong>{title}</strong>:{restParts}</>;
|
||||||
}
|
}
|
||||||
// No colon — just bold numbers
|
// No colon — just bold figures
|
||||||
const parts = text.split(/(\d+[\d,.]*\s*(?:kWh|CHF|%|days?))/g).map((p, i) =>
|
const parts = text.split(BOLD_PATTERN).map((p, i) =>
|
||||||
/\d+[\d,.]*\s*(?:kWh|CHF|%|days?)/.test(p)
|
isBold(p) ? <strong key={i}>{p}</strong> : <span key={i}>{p}</span>
|
||||||
? <strong key={i}>{p}</strong>
|
|
||||||
: <span key={i}>{p}</span>
|
|
||||||
);
|
);
|
||||||
return <>{parts}</>;
|
return <>{parts}</>;
|
||||||
}
|
}
|
||||||
|
|
@ -159,6 +162,10 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
|
||||||
const cur = report.currentWeek;
|
const cur = report.currentWeek;
|
||||||
const prev = report.previousWeek;
|
const prev = report.previousWeek;
|
||||||
|
|
||||||
|
// Backend: currentWeek = last 7 days, previousWeek = everything before
|
||||||
|
const currentWeekDayCount = Math.min(7, report.dailyData.length);
|
||||||
|
const previousWeekDayCount = Math.max(1, report.dailyData.length - currentWeekDayCount);
|
||||||
|
|
||||||
const formatChange = (pct: number) =>
|
const formatChange = (pct: number) =>
|
||||||
pct === 0 ? '—' : pct > 0 ? `+${pct.toFixed(1)}%` : `${pct.toFixed(1)}%`;
|
pct === 0 ? '—' : pct > 0 ? `+${pct.toFixed(1)}%` : `${pct.toFixed(1)}%`;
|
||||||
|
|
||||||
|
|
@ -173,9 +180,9 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
|
||||||
.map((line) => line.replace(/^[\d]+[.)]\s*/, '').replace(/^[-*]\s*/, '').trim())
|
.map((line) => line.replace(/^[\d]+[.)]\s*/, '').replace(/^[-*]\s*/, '').trim())
|
||||||
.filter((line) => line.length > 0);
|
.filter((line) => line.length > 0);
|
||||||
|
|
||||||
// Savings-focused KPI values
|
// Read pre-computed values from backend — no arithmetic in the frontend
|
||||||
const solarSavingsKwh = Math.round((cur.totalPvProduction - cur.totalGridExport) * 10) / 10;
|
const totalEnergySavedKwh = report.totalEnergySaved;
|
||||||
const estimatedSavingsCHF = Math.round(solarSavingsKwh * 0.27 * 10) / 10;
|
const totalSavingsCHF = report.totalSavingsCHF;
|
||||||
|
|
||||||
// Find max value for daily bar chart scaling
|
// Find max value for daily bar chart scaling
|
||||||
const maxDailyValue = Math.max(
|
const maxDailyValue = Math.max(
|
||||||
|
|
@ -270,15 +277,16 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
|
||||||
<Grid item xs={6} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<SavingsCard
|
<SavingsCard
|
||||||
label={intl.formatMessage({ id: 'solarEnergyUsed' })}
|
label={intl.formatMessage({ id: 'solarEnergyUsed' })}
|
||||||
value={`${solarSavingsKwh} kWh`}
|
value={`${totalEnergySavedKwh} kWh`}
|
||||||
subtitle={intl.formatMessage({ id: 'solarStayedHome' })}
|
subtitle={intl.formatMessage({ id: 'solarStayedHome' })}
|
||||||
color="#27ae60"
|
color="#27ae60"
|
||||||
|
hint={report.daysEquivalent > 0 ? `≈ ${report.daysEquivalent} ${intl.formatMessage({ id: 'daysOfYourUsage' })}` : undefined}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={6} sm={3}>
|
<Grid item xs={6} sm={3}>
|
||||||
<SavingsCard
|
<SavingsCard
|
||||||
label={intl.formatMessage({ id: 'estMoneySaved' })}
|
label={intl.formatMessage({ id: 'estMoneySaved' })}
|
||||||
value={`~${estimatedSavingsCHF} CHF`}
|
value={`~${totalSavingsCHF} CHF`}
|
||||||
subtitle={intl.formatMessage({ id: 'atCHFRate' })}
|
subtitle={intl.formatMessage({ id: 'atCHFRate' })}
|
||||||
color="#2980b9"
|
color="#2980b9"
|
||||||
/>
|
/>
|
||||||
|
|
@ -329,6 +337,18 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
|
||||||
{prev && <td style={{ textAlign: 'right', color: '#888' }}>{prev.totalConsumption.toFixed(1)} kWh</td>}
|
{prev && <td style={{ textAlign: 'right', color: '#888' }}>{prev.totalConsumption.toFixed(1)} kWh</td>}
|
||||||
{prev && <td style={{ textAlign: 'right', color: changeColor(report.consumptionChangePercent, true) }}>{formatChange(report.consumptionChangePercent)}</td>}
|
{prev && <td style={{ textAlign: 'right', color: changeColor(report.consumptionChangePercent, true) }}>{formatChange(report.consumptionChangePercent)}</td>}
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr style={{ background: '#fafafa' }}>
|
||||||
|
<td style={{ color: '#888', paddingLeft: '20px', fontSize: '13px' }}>
|
||||||
|
<FormattedMessage id="avgDailyConsumption" defaultMessage="Avg Daily Consumption" />
|
||||||
|
</td>
|
||||||
|
<td style={{ textAlign: 'right', color: '#888', fontSize: '13px' }}>
|
||||||
|
{(cur.totalConsumption / currentWeekDayCount).toFixed(1)} kWh
|
||||||
|
</td>
|
||||||
|
{prev && <td style={{ textAlign: 'right', color: '#bbb', fontSize: '13px' }}>
|
||||||
|
{(prev.totalConsumption / previousWeekDayCount).toFixed(1)} kWh
|
||||||
|
</td>}
|
||||||
|
{prev && <td />}
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><FormattedMessage id="gridImport" defaultMessage="Grid Import" /></td>
|
<td><FormattedMessage id="gridImport" defaultMessage="Grid Import" /></td>
|
||||||
<td style={{ textAlign: 'right', fontWeight: 'bold' }}>{cur.totalGridImport.toFixed(1)} kWh</td>
|
<td style={{ textAlign: 'right', fontWeight: 'bold' }}>{cur.totalGridImport.toFixed(1)} kWh</td>
|
||||||
|
|
@ -423,7 +443,7 @@ function WeeklyReport({ installationId }: WeeklyReportProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SavingsCard({ label, value, subtitle, color }: { label: string; value: string; subtitle: string; color: string }) {
|
function SavingsCard({ label, value, subtitle, color, hint }: { label: string; value: string; subtitle: string; color: string; hint?: string }) {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -442,6 +462,11 @@ function SavingsCard({ label, value, subtitle, color }: { label: string; value:
|
||||||
<Typography variant="caption" sx={{ color: '#888' }}>
|
<Typography variant="caption" sx={{ color: '#888' }}>
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{hint && (
|
||||||
|
<Typography variant="caption" sx={{ display: 'block', color, fontWeight: 'bold', mt: 0.5 }}>
|
||||||
|
{hint}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export interface Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DiagnosticResponse {
|
export interface DiagnosticResponse {
|
||||||
|
name: string;
|
||||||
explanation: string;
|
explanation: string;
|
||||||
causes: string[];
|
causes: string[];
|
||||||
nextSteps: string[];
|
nextSteps: string[];
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,16 @@
|
||||||
"reportTitle": "Wöchentlicher Leistungsbericht",
|
"reportTitle": "Wöchentlicher Leistungsbericht",
|
||||||
"weeklyInsights": "Wöchentliche Einblicke",
|
"weeklyInsights": "Wöchentliche Einblicke",
|
||||||
"weeklySavings": "Ihre Einsparungen diese Woche",
|
"weeklySavings": "Ihre Einsparungen diese Woche",
|
||||||
"solarEnergyUsed": "Genutzte Solarenergie",
|
"solarEnergyUsed": "Energie gespart",
|
||||||
"solarStayedHome": "Ihrer Solarenergie blieb zu Hause",
|
"solarStayedHome": "Solar + Batterie, nicht vom Netz",
|
||||||
|
"daysOfYourUsage": "Tage Ihres Verbrauchs",
|
||||||
"estMoneySaved": "Geschätzte Ersparnisse",
|
"estMoneySaved": "Geschätzte Ersparnisse",
|
||||||
"atCHFRate": "bei 0,27 CHF/kWh Ø",
|
"atCHFRate": "bei 0,39 CHF/kWh Ø",
|
||||||
"solarCoverage": "Solarabdeckung",
|
"solarCoverage": "Eigenversorgung",
|
||||||
"fromSolarSub": "des Verbrauchs aus Solar",
|
"fromSolarSub": "aus Solar + Batterie",
|
||||||
|
"avgDailyConsumption": "Ø Tagesverbrauch",
|
||||||
"batteryEfficiency": "Batterieeffizienz",
|
"batteryEfficiency": "Batterieeffizienz",
|
||||||
"batteryEffSub": "Energie aus vs. Energie ein",
|
"batteryEffSub": "Entladung vs. Ladung",
|
||||||
"weeklySummary": "Wöchentliche Zusammenfassung",
|
"weeklySummary": "Wöchentliche Zusammenfassung",
|
||||||
"metric": "Kennzahl",
|
"metric": "Kennzahl",
|
||||||
"thisWeek": "Diese Woche",
|
"thisWeek": "Diese Woche",
|
||||||
|
|
@ -114,7 +116,7 @@
|
||||||
"consumption": "Verbrauch",
|
"consumption": "Verbrauch",
|
||||||
"gridImport": "Netzbezug",
|
"gridImport": "Netzbezug",
|
||||||
"gridExport": "Netzeinspeisung",
|
"gridExport": "Netzeinspeisung",
|
||||||
"batteryInOut": "Batterie Ein / Aus",
|
"batteryInOut": "Batterie Laden / Entladen",
|
||||||
"dailyBreakdown": "Tägliche Aufschlüsselung",
|
"dailyBreakdown": "Tägliche Aufschlüsselung",
|
||||||
"prevWeek": "(Vorwoche)",
|
"prevWeek": "(Vorwoche)",
|
||||||
"sendReport": "Bericht senden",
|
"sendReport": "Bericht senden",
|
||||||
|
|
@ -142,5 +144,239 @@
|
||||||
"demo_custom_group": "Benutzerdefiniert (kann Mistral KI verwenden)",
|
"demo_custom_group": "Benutzerdefiniert (kann Mistral KI verwenden)",
|
||||||
"demo_custom_option": "Benutzerdefinierten Alarm eingeben…",
|
"demo_custom_option": "Benutzerdefinierten Alarm eingeben…",
|
||||||
"demo_custom_placeholder": "z.B. UnknownBatteryFault",
|
"demo_custom_placeholder": "z.B. UnknownBatteryFault",
|
||||||
"demo_diagnose_button": "Diagnostizieren"
|
"demo_diagnose_button": "Diagnostizieren",
|
||||||
|
"alarm_AbnormalGridVoltage": "Unnormale Netzspannung",
|
||||||
|
"alarm_AbnormalGridFrequency": "Unnormale Netzfrequenz",
|
||||||
|
"alarm_InvertedSequenceOfGridVoltage": "Falsche Phasenreihenfolge",
|
||||||
|
"alarm_GridVoltagePhaseLoss": "Phasenausfall im Netz",
|
||||||
|
"alarm_AbnormalGridCurrent": "Unnormaler Netzstrom",
|
||||||
|
"alarm_AbnormalOutputVoltage": "Ungewöhnliche Ausgangsspannung",
|
||||||
|
"alarm_AbnormalOutputFrequency": "Ungewöhnliche Ausgangsfrequenz",
|
||||||
|
"alarm_AbnormalNullLine": "Fehlerhafter Nullleiter",
|
||||||
|
"alarm_AbnormalOffGridOutputVoltage": "Ungewöhnliche Backup-Spannung",
|
||||||
|
"alarm_ExcessivelyHighAmbientTemperature": "Zu hohe Umgebungstemperatur",
|
||||||
|
"alarm_ExcessiveRadiatorTemperature": "Überhitzter Kühlkörper",
|
||||||
|
"alarm_PcbOvertemperature": "Überhitzte Leiterplatte",
|
||||||
|
"alarm_DcConverterOvertemperature": "Überhitzter DC-Wandler",
|
||||||
|
"alarm_InverterOvertemperatureAlarm": "Warnung: Überhitzung",
|
||||||
|
"alarm_InverterOvertemperature": "Wechselrichter überhitzt",
|
||||||
|
"alarm_DcConverterOvertemperatureAlarm": "Übertemperaturalarm DC-Wandler",
|
||||||
|
"alarm_InsulationFault": "Isolationsfehler",
|
||||||
|
"alarm_LeakageProtectionFault": "Leckschutzfehler",
|
||||||
|
"alarm_AbnormalLeakageSelfCheck": "Anomaler Leckstrom-Selbsttest",
|
||||||
|
"alarm_PoorGrounding": "Schlechte Erdung",
|
||||||
|
"alarm_FanFault": "Lüfterfehler",
|
||||||
|
"alarm_AuxiliaryPowerFault": "Hilfsstromversorgung Fehler",
|
||||||
|
"alarm_ModelCapacityFault": "Modellkapazitätsfehler",
|
||||||
|
"alarm_AbnormalLightningArrester": "Überspannungsschutz Fehler",
|
||||||
|
"alarm_IslandProtection": "Inselbetrieb Schutz",
|
||||||
|
"alarm_Battery1NotConnected": "Batterie 1 nicht verbunden",
|
||||||
|
"alarm_Battery1Overvoltage": "Batterie 1 Überspannung",
|
||||||
|
"alarm_Battery1Undervoltage": "Batterie 1 Unterspannung",
|
||||||
|
"alarm_Battery1DischargeEnd": "Batterie 1 Entladung beendet",
|
||||||
|
"alarm_Battery1Inverted": "Batterie 1 Polarität vertauscht",
|
||||||
|
"alarm_Battery1OverloadTimeout": "Batterie 1 Überlastung",
|
||||||
|
"alarm_Battery1SoftStartFailure": "Batterie 1 Startfehler",
|
||||||
|
"alarm_Battery1PowerTubeFault": "Batterie 1 Leistungsteil defekt",
|
||||||
|
"alarm_Battery1InsufficientPower": "Batterie 1 Leistung unzureichend",
|
||||||
|
"alarm_Battery1BackupProhibited": "Batterie 1 Backup gesperrt",
|
||||||
|
"alarm_Battery2NotConnected": "Batterie 2 nicht verbunden",
|
||||||
|
"alarm_Battery2Overvoltage": "Batterie 2 Überspannung",
|
||||||
|
"alarm_Battery2Undervoltage": "Batterie 2 Unterspannung",
|
||||||
|
"alarm_Battery2DischargeEnd": "Batterie 2 Entladung beendet",
|
||||||
|
"alarm_Battery2Inverted": "Batterie 2 falsch angeschlossen",
|
||||||
|
"alarm_Battery2OverloadTimeout": "Batterie 2 Überlastung",
|
||||||
|
"alarm_Battery2SoftStartFailure": "Batterie 2 Startfehler",
|
||||||
|
"alarm_Battery2PowerTubeFault": "Batterie 2 Leistungsteil defekt",
|
||||||
|
"alarm_Battery2InsufficientPower": "Batterie 2 Leistung unzureichend",
|
||||||
|
"alarm_Battery2BackupProhibited": "Batterie 2 Backup gesperrt",
|
||||||
|
"alarm_LithiumBattery1ChargeForbidden": "Lithium-Batterie 1 Ladeverbot",
|
||||||
|
"alarm_LithiumBattery1DischargeForbidden": "Lithium-Batterie 1 Entladeverbot",
|
||||||
|
"alarm_LithiumBattery2ChargeForbidden": "Lithium-Batterie 2 Ladeverbot",
|
||||||
|
"alarm_LithiumBattery2DischargeForbidden": "Lithium-Batterie 2 Entladeverbot",
|
||||||
|
"alarm_LithiumBattery1Full": "Lithium-Batterie 1 voll",
|
||||||
|
"alarm_LithiumBattery1DischargeEnd": "Lithium-Batterie 1 entladen",
|
||||||
|
"alarm_LithiumBattery2Full": "Lithium-Batterie 2 voll",
|
||||||
|
"alarm_LithiumBattery2DischargeEnd": "Lithium-Batterie 2 entladen",
|
||||||
|
"alarm_LeadBatteryTemperatureAbnormality": "Batterietemperatur abnormal",
|
||||||
|
"alarm_BatteryAccessMethodError": "Batteriezugriffsfehler",
|
||||||
|
"alarm_Pv1NotAccessed": "PV1 nicht erreichbar",
|
||||||
|
"alarm_Pv1Overvoltage": "PV1 Überspannung",
|
||||||
|
"alarm_AbnormalPv1CurrentSharing": "Ungleichmäßiger PV1-Strom",
|
||||||
|
"alarm_Pv1PowerTubeFault": "PV1 Leistungstubus defekt",
|
||||||
|
"alarm_Pv1SoftStartFailure": "PV1 Soft-Start fehlgeschlagen",
|
||||||
|
"alarm_Pv1OverloadTimeout": "PV1-Überlastung",
|
||||||
|
"alarm_Pv1InsufficientPower": "PV1-Schwacher Strom",
|
||||||
|
"alarm_Photovoltaic1Overcurrent": "PV1-Überstrom",
|
||||||
|
"alarm_Pv2NotAccessed": "PV2-Nicht erkannt",
|
||||||
|
"alarm_Pv2Overvoltage": "PV2-Überspannung",
|
||||||
|
"alarm_AbnormalPv2CurrentSharing": "Ungewöhnliche Stromverteilung PV2",
|
||||||
|
"alarm_Pv2PowerTubeFault": "PV2-Leistungsrohrfehler",
|
||||||
|
"alarm_Pv2SoftStartFailure": "PV2-Softstart fehlgeschlagen",
|
||||||
|
"alarm_Pv2OverloadTimeout": "PV2-Überlastung Timeout",
|
||||||
|
"alarm_Pv2InsufficientPower": "Unzureichende Leistung PV2",
|
||||||
|
"alarm_Pv3NotConnected": "PV3 nicht verbunden",
|
||||||
|
"alarm_Pv3Overvoltage": "PV3 Überspannung",
|
||||||
|
"alarm_Pv3AverageCurrentAnomaly": "PV3 Stromanomalie",
|
||||||
|
"alarm_Pv3PowerTubeFailure": "PV3 Leistungselektronik defekt",
|
||||||
|
"alarm_Pv3SoftStartFailure": "PV3 Startfehler",
|
||||||
|
"alarm_Pv3OverloadTimeout": "PV3-Überlastung",
|
||||||
|
"alarm_Pv3ReverseConnection": "PV3-Falschpolung",
|
||||||
|
"alarm_Pv4NotConnected": "PV4 Nicht Verbunden",
|
||||||
|
"alarm_Pv4Overvoltage": "PV4 Überspannung",
|
||||||
|
"alarm_Pv4AverageCurrentAnomaly": "PV4 Stromanomalie",
|
||||||
|
"alarm_Pv4PowerTubeFailure": "PV4-Leistungsrohr defekt",
|
||||||
|
"alarm_Pv4SoftStartFailure": "PV4-Softstart fehlgeschlagen",
|
||||||
|
"alarm_Pv4OverloadTimeout": "PV4-Überlastung",
|
||||||
|
"alarm_Pv4ReverseConnection": "PV4 falsch angeschlossen",
|
||||||
|
"alarm_InsufficientPhotovoltaicPower": "Zu wenig Solarstrom",
|
||||||
|
"alarm_DcBusOvervoltage": "DC-Bus Überspannung",
|
||||||
|
"alarm_DcBusUndervoltage": "DC-Bus Unterspannung",
|
||||||
|
"alarm_DcBusVoltageUnbalance": "DC-Bus Spannungsungleichgewicht",
|
||||||
|
"alarm_BusSlowOvervoltage": "Langsame DC-Bus Überspannung",
|
||||||
|
"alarm_HardwareBusOvervoltage": "Hardware DC-Bus Überspannung",
|
||||||
|
"alarm_BusSoftStartFailure": "Fehler beim sanften Start",
|
||||||
|
"alarm_InverterPowerTubeFault": "Wechselrichter-Leistungshalbleiter defekt",
|
||||||
|
"alarm_HardwareOvercurrent": "Hardware-Überstrom",
|
||||||
|
"alarm_DcConverterOvervoltage": "DC-Wandler Überspannung",
|
||||||
|
"alarm_DcConverterHardwareOvervoltage": "DC-Wandler Hardware-Überspannung",
|
||||||
|
"alarm_DcConverterOvercurrent": "DC-Wandler Überstrom",
|
||||||
|
"alarm_DcConverterHardwareOvercurrent": "DC-Wandler Hardware-Überstrom",
|
||||||
|
"alarm_DcConverterResonatorOvercurrent": "DC-Wandler Resonanz-Überstrom",
|
||||||
|
"alarm_SystemOutputOverload": "Systemausgang überlastet",
|
||||||
|
"alarm_InverterOverload": "Wechselrichter überlastet",
|
||||||
|
"alarm_InverterOverloadTimeout": "Wechselrichter-Überlastung",
|
||||||
|
"alarm_LoadPowerOverload": "Überlastung der Lastleistung",
|
||||||
|
"alarm_BalancedCircuitOverloadTimeout": "Phasenausgleich-Überlastung",
|
||||||
|
"alarm_InverterSoftStartFailure": "Wechselrichter-Softstart-Fehler",
|
||||||
|
"alarm_Dsp1ParameterSettingFault": "DSP-Parameter-Fehler",
|
||||||
|
"alarm_Dsp2ParameterSettingFault": "DSP2 Parameterfehler",
|
||||||
|
"alarm_DspVersionCompatibilityFault": "DSP-Versionen nicht kompatibel",
|
||||||
|
"alarm_CpldVersionCompatibilityFault": "CPLD-Version nicht kompatibel",
|
||||||
|
"alarm_CpldCommunicationFault": "CPLD-Kommunikationsfehler",
|
||||||
|
"alarm_DspCommunicationFault": "DSP-Kommunikationsfehler",
|
||||||
|
"alarm_OutputVoltageDcOverlimit": "DC-Spannung zu hoch",
|
||||||
|
"alarm_OutputCurrentDcOverlimit": "DC-Strom zu hoch",
|
||||||
|
"alarm_RelaySelfCheckFails": "Relais-Selbsttest fehlgeschlagen",
|
||||||
|
"alarm_InverterRelayOpen": "Wechselrichter-Relais offen",
|
||||||
|
"alarm_InverterRelayShortCircuit": "Wechselrichter-Relais Kurzschluss",
|
||||||
|
"alarm_OpenCircuitOfPowerGridRelay": "Netzrelais offen",
|
||||||
|
"alarm_ShortCircuitOfPowerGridRelay": "Netzrelais kurzgeschlossen",
|
||||||
|
"alarm_GeneratorRelayOpenCircuit": "Generatorrelais offen",
|
||||||
|
"alarm_GeneratorRelayShortCircuit": "Generatorrelais kurzgeschlossen",
|
||||||
|
"alarm_AbnormalInverter": "Wechselrichter abnormal",
|
||||||
|
"alarm_ParallelCommunicationAlarm": "Parallelkommunikationsalarm",
|
||||||
|
"alarm_ParallelModuleMissing": "Parallelmodul fehlt",
|
||||||
|
"alarm_DuplicateMachineNumbersForParallelModules": "Doppelte Gerätenummern",
|
||||||
|
"alarm_ParameterConflictInParallelModule": "Parameterkonflikt im Parallelmodul",
|
||||||
|
"alarm_SystemDerating": "Systemleistung reduziert",
|
||||||
|
"alarm_PvAccessMethodErrorAlarm": "PV-Zugriffsfehler",
|
||||||
|
"alarm_ReservedAlarms4": "Reservierter Alarm 4",
|
||||||
|
"alarm_ReservedAlarms5": "Reservierter Alarm 5",
|
||||||
|
"alarm_ReverseMeterConnection": "Zähler falsch angeschlossen",
|
||||||
|
"alarm_InverterSealPulse": "Wechselrichter-Leistungsbegrenzung",
|
||||||
|
"alarm_AbnormalDieselGeneratorVoltage": "Ungewöhnliche Dieselgenerator-Spannung",
|
||||||
|
"alarm_AbnormalDieselGeneratorFrequency": "Ungewöhnliche Dieselgenerator-Frequenz",
|
||||||
|
"alarm_DieselGeneratorVoltageReverseSequence": "Falsche Phasenfolge des Generators",
|
||||||
|
"alarm_DieselGeneratorVoltageOutOfPhase": "Generator nicht synchronisiert",
|
||||||
|
"alarm_GeneratorOverload": "Generator überlastet",
|
||||||
|
"alarm_StringFault": "PV-String-Fehler",
|
||||||
|
"alarm_PvStringPidQuickConnectAbnormal": "PV-String-Anschluss defekt",
|
||||||
|
"alarm_DcSpdFunctionAbnormal": "DC-Überspannungsschutz defekt",
|
||||||
|
"alarm_PvShortCircuited": "PV-String kurzgeschlossen",
|
||||||
|
"alarm_PvBoostDriverAbnormal": "PV-Boost-Treiber defekt",
|
||||||
|
"alarm_AcSpdFunctionAbnormal": "AC-Überspannungsschutz defekt",
|
||||||
|
"alarm_DcFuseBlown": "DC-Sicherung durchgebrannt",
|
||||||
|
"alarm_DcInputVoltageTooHigh": "DC-Eingangsspannung zu hoch",
|
||||||
|
"alarm_PvReversed": "PV-Polarität vertauscht",
|
||||||
|
"alarm_PidFunctionAbnormal": "PID-Schutzfunktion gestört",
|
||||||
|
"alarm_PvStringDisconnected": "PV-String getrennt",
|
||||||
|
"alarm_PvStringCurrentUnbalanced": "PV-String Strom unausgeglichen",
|
||||||
|
"alarm_NoUtilityGrid": "Kein Stromnetz",
|
||||||
|
"alarm_GridVoltageOutOfRange": "Netzspannung außerhalb des Bereichs",
|
||||||
|
"alarm_GridFrequencyOutOfRange": "Netzfrequenz außerhalb des Bereichs",
|
||||||
|
"alarm_Overload": "Überlastung",
|
||||||
|
"alarm_MeterDisconnected": "Stromzähler getrennt",
|
||||||
|
"alarm_MeterReverselyConnected": "Zähler falsch angeschlossen",
|
||||||
|
"alarm_LinePeVoltageAbnormal": "Abnormale PE-Spannung",
|
||||||
|
"alarm_PhaseSequenceError": "Phasenfolgefehler",
|
||||||
|
"alarm_FanFailure": "Lüfterausfall",
|
||||||
|
"alarm_MeterAbnormal": "Störungsanzeige Zähler",
|
||||||
|
"alarm_OptimizerCommunicationAbnormal": "Kommunikationsstörung Optimierer",
|
||||||
|
"alarm_OverTemperature": "Überhitzung",
|
||||||
|
"alarm_OverTemperatureAlarm": "Überhitzungswarnung",
|
||||||
|
"alarm_NtcTemperatureSensorBroken": "Temperatursensor defekt",
|
||||||
|
"alarm_SyncSignalAbnormal": "Synchronisationsfehler",
|
||||||
|
"alarm_GridStartupConditionsNotMet": "Netzstartbedingungen nicht erfüllt",
|
||||||
|
"alarm_BatteryCommunicationFailure": "Batteriekommunikation fehlgeschlagen",
|
||||||
|
"alarm_BatteryDisconnected": "Batterie getrennt",
|
||||||
|
"alarm_BatteryVoltageTooHigh": "Batteriespannung zu hoch",
|
||||||
|
"alarm_BatteryVoltageTooLow": "Batteriespannung zu niedrig",
|
||||||
|
"alarm_BatteryReverseConnected": "Batterie falsch angeschlossen",
|
||||||
|
"alarm_LeadAcidTempSensorDisconnected": "Temperatursensor nicht angeschlossen",
|
||||||
|
"alarm_BatteryTemperatureOutOfRange": "Batterietemperatur außerhalb des Bereichs",
|
||||||
|
"alarm_BmsFault": "BMS-Fehler",
|
||||||
|
"alarm_LithiumBatteryOverload": "Batterie-Überlastung",
|
||||||
|
"alarm_BmsCommunicationAbnormal": "BMS-Kommunikationsfehler",
|
||||||
|
"alarm_BatterySpdAbnormal": "Batterie-Überspannungsschutz",
|
||||||
|
"alarm_OutputDcComponentBiasAbnormal": "DC-Versatz im Ausgang",
|
||||||
|
"alarm_DcComponentOverHighOutputVoltage": "DC-Komponente zu hohe Ausgangsspannung",
|
||||||
|
"alarm_OffGridOutputVoltageTooLow": "Netzunabhängige Ausgangsspannung zu niedrig",
|
||||||
|
"alarm_OffGridOutputVoltageTooHigh": "Netzunabhängige Ausgangsspannung zu hoch",
|
||||||
|
"alarm_OffGridOutputOverCurrent": "Netzunabhängiger Ausgangsüberstrom",
|
||||||
|
"alarm_OffGridOutputOverload": "Netzunabhängiger Ausgang überlastet",
|
||||||
|
"alarm_BalancedCircuitAbnormal": "Phasenausgleich gestört",
|
||||||
|
"alarm_ExportLimitationFailSafe": "Exportbegrenzung Notaus",
|
||||||
|
"alarm_DcBiasAbnormal": "DC-Vorspannung abnormal",
|
||||||
|
"alarm_HighDcComponentOutputCurrent": "Hohe DC-Komponente im Ausgangsstrom",
|
||||||
|
"alarm_BusVoltageSamplingAbnormal": "Spannungsmessung defekt",
|
||||||
|
"alarm_RelayFault": "Relaisfehler",
|
||||||
|
"alarm_BusVoltageAbnormal": "Gleichspannung abnormal",
|
||||||
|
"alarm_InternalCommunicationFailure": "Interne Kommunikation ausgefallen",
|
||||||
|
"alarm_TemperatureSensorDisconnected": "Temperatursensor getrennt",
|
||||||
|
"alarm_IgbtDriveFault": "IGBT-Ansteuerungsfehler",
|
||||||
|
"alarm_EepromError": "EEPROM-Fehler",
|
||||||
|
"alarm_AuxiliaryPowerAbnormal": "Hilfsstromversorgung abnormal",
|
||||||
|
"alarm_DcAcOvercurrentProtection": "Überstromschutz aktiviert",
|
||||||
|
"alarm_CommunicationProtocolMismatch": "Kommunikationsprotokoll-Fehler",
|
||||||
|
"alarm_DspComFirmwareMismatch": "Firmware-Inkompatibilität DSP/COM",
|
||||||
|
"alarm_DspSoftwareHardwareMismatch": "DSP-Software-Hardware-Inkompatibilität",
|
||||||
|
"alarm_CpldAbnormal": "CPLD-Fehler",
|
||||||
|
"alarm_RedundancySamplingInconsistent": "Inkonsistente redundante Messungen",
|
||||||
|
"alarm_PwmPassThroughSignalFailure": "PWM-Signalweg ausgefallen",
|
||||||
|
"alarm_AfciSelfTestFailure": "AFCI-Selbsttest fehlgeschlagen",
|
||||||
|
"alarm_PvCurrentSamplingAbnormal": "PV-Strommessung abnormal",
|
||||||
|
"alarm_AcCurrentSamplingAbnormal": "AC-Strommessung abnormal",
|
||||||
|
"alarm_BusSoftbootFailure": "DC-Bus-Vorstart fehlgeschlagen",
|
||||||
|
"alarm_EpoFault": "EPO-Fehler (Notaus)",
|
||||||
|
"alarm_MonitoringChipBootVerificationFailed": "Überwachungs-Chip Startfehler",
|
||||||
|
"alarm_BmsCommunicationFailure": "BMS-Kommunikationsfehler",
|
||||||
|
"alarm_BmsChargeDischargeFailure": "BMS-Lade-/Entladefehler",
|
||||||
|
"alarm_BatteryVoltageLow": "Batteriespannung zu niedrig",
|
||||||
|
"alarm_BatteryVoltageHigh": "Batteriespannung zu hoch",
|
||||||
|
"alarm_BatteryTemperatureAbnormal": "Batterietemperatur ungewöhnlich",
|
||||||
|
"alarm_BatteryReversed": "Batterie verkehrt herum",
|
||||||
|
"alarm_BatteryOpenCircuit": "Batteriekreis offen",
|
||||||
|
"alarm_BatteryOverloadProtection": "Batterieüberlastungsschutz",
|
||||||
|
"alarm_Bus2VoltageAbnormal": "Bus2-Spannung ungewöhnlich",
|
||||||
|
"alarm_BatteryChargeOcp": "Batterieladung Überstrom",
|
||||||
|
"alarm_BatteryDischargeOcp": "Batterieentladung Überstrom",
|
||||||
|
"alarm_BatterySoftStartFailed": "Batterie-Softstart fehlgeschlagen",
|
||||||
|
"alarm_EpsOutputShortCircuited": "EPS-Ausgang kurzgeschlossen",
|
||||||
|
"alarm_OffGridBusVoltageLow": "Netzunabhängige Busspannung zu niedrig",
|
||||||
|
"alarm_OffGridTerminalVoltageAbnormal": "Abnormale Spannung am Netzausgang",
|
||||||
|
"alarm_SoftStartFailed": "Sanfter Start fehlgeschlagen",
|
||||||
|
"alarm_OffGridOutputVoltageAbnormal": "Abnormale Ausgangsspannung im Netzmodus",
|
||||||
|
"alarm_BalancedCircuitSelfTestFailed": "Ausgleichsschaltungstest fehlgeschlagen",
|
||||||
|
"alarm_HighDcComponentOutputVoltage": "Hohe Gleichspannungskomponente im Ausgang",
|
||||||
|
"alarm_OffGridParallelSignalAbnormal": "Parallelsignalstörung",
|
||||||
|
"alarm_AFCIFault": "Lichtbogenfehler",
|
||||||
|
"alarm_GFCIHigh": "Erhöhter Fehlerstrom",
|
||||||
|
"alarm_PVVoltageHigh": "PV-Spannung zu hoch",
|
||||||
|
"alarm_OffGridBusVoltageTooLow": "Off-Grid-Busspannung zu niedrig",
|
||||||
|
"Information": "Informationen",
|
||||||
|
"allInstallations": "Alle Installationen",
|
||||||
|
"group": "Gruppe",
|
||||||
|
"groups": "Gruppen",
|
||||||
|
"requiredOrderNumber": "Pflichtbestellnummer"
|
||||||
}
|
}
|
||||||
|
|
@ -80,14 +80,16 @@
|
||||||
"reportTitle": "Weekly Performance Report",
|
"reportTitle": "Weekly Performance Report",
|
||||||
"weeklyInsights": "Weekly Insights",
|
"weeklyInsights": "Weekly Insights",
|
||||||
"weeklySavings": "Your Savings This Week",
|
"weeklySavings": "Your Savings This Week",
|
||||||
"solarEnergyUsed": "Solar Energy Used",
|
"solarEnergyUsed": "Energy Saved",
|
||||||
"solarStayedHome": "of your solar stayed at home",
|
"solarStayedHome": "solar + battery, not bought from grid",
|
||||||
|
"daysOfYourUsage": "days of your usage",
|
||||||
"estMoneySaved": "Est. Money Saved",
|
"estMoneySaved": "Est. Money Saved",
|
||||||
"atCHFRate": "at 0.27 CHF/kWh avg.",
|
"atCHFRate": "at 0.39 CHF/kWh avg.",
|
||||||
"solarCoverage": "Solar Coverage",
|
"solarCoverage": "Self-Sufficiency",
|
||||||
"fromSolarSub": "of consumption from solar",
|
"fromSolarSub": "from solar + battery",
|
||||||
|
"avgDailyConsumption": "Avg Daily Consumption",
|
||||||
"batteryEfficiency": "Battery Efficiency",
|
"batteryEfficiency": "Battery Efficiency",
|
||||||
"batteryEffSub": "energy out vs energy in",
|
"batteryEffSub": "discharge vs charge",
|
||||||
"weeklySummary": "Weekly Summary",
|
"weeklySummary": "Weekly Summary",
|
||||||
"metric": "Metric",
|
"metric": "Metric",
|
||||||
"thisWeek": "This Week",
|
"thisWeek": "This Week",
|
||||||
|
|
@ -96,7 +98,7 @@
|
||||||
"consumption": "Consumption",
|
"consumption": "Consumption",
|
||||||
"gridImport": "Grid Import",
|
"gridImport": "Grid Import",
|
||||||
"gridExport": "Grid Export",
|
"gridExport": "Grid Export",
|
||||||
"batteryInOut": "Battery In / Out",
|
"batteryInOut": "Battery Charge / Discharge",
|
||||||
"dailyBreakdown": "Daily Breakdown",
|
"dailyBreakdown": "Daily Breakdown",
|
||||||
"prevWeek": "(prev week)",
|
"prevWeek": "(prev week)",
|
||||||
"sendReport": "Send Report",
|
"sendReport": "Send Report",
|
||||||
|
|
|
||||||
|
|
@ -92,14 +92,16 @@
|
||||||
"reportTitle": "Rapport de performance hebdomadaire",
|
"reportTitle": "Rapport de performance hebdomadaire",
|
||||||
"weeklyInsights": "Aperçus hebdomadaires",
|
"weeklyInsights": "Aperçus hebdomadaires",
|
||||||
"weeklySavings": "Vos économies cette semaine",
|
"weeklySavings": "Vos économies cette semaine",
|
||||||
"solarEnergyUsed": "Énergie solaire utilisée",
|
"solarEnergyUsed": "Énergie économisée",
|
||||||
"solarStayedHome": "de votre solaire est resté à la maison",
|
"solarStayedHome": "solaire + batterie, non achetée au réseau",
|
||||||
|
"daysOfYourUsage": "jours de votre consommation",
|
||||||
"estMoneySaved": "Économies estimées",
|
"estMoneySaved": "Économies estimées",
|
||||||
"atCHFRate": "à 0,27 CHF/kWh moy.",
|
"atCHFRate": "à 0,39 CHF/kWh moy.",
|
||||||
"solarCoverage": "Couverture solaire",
|
"solarCoverage": "Autosuffisance",
|
||||||
"fromSolarSub": "de la consommation provenant du solaire",
|
"fromSolarSub": "du solaire + batterie",
|
||||||
|
"avgDailyConsumption": "Conso. quotidienne moy.",
|
||||||
"batteryEfficiency": "Efficacité de la batterie",
|
"batteryEfficiency": "Efficacité de la batterie",
|
||||||
"batteryEffSub": "énergie sortante vs énergie entrante",
|
"batteryEffSub": "décharge vs charge",
|
||||||
"weeklySummary": "Résumé hebdomadaire",
|
"weeklySummary": "Résumé hebdomadaire",
|
||||||
"metric": "Métrique",
|
"metric": "Métrique",
|
||||||
"thisWeek": "Cette semaine",
|
"thisWeek": "Cette semaine",
|
||||||
|
|
@ -108,7 +110,7 @@
|
||||||
"consumption": "Consommation",
|
"consumption": "Consommation",
|
||||||
"gridImport": "Importation réseau",
|
"gridImport": "Importation réseau",
|
||||||
"gridExport": "Exportation réseau",
|
"gridExport": "Exportation réseau",
|
||||||
"batteryInOut": "Batterie Entrée / Sortie",
|
"batteryInOut": "Batterie Charge / Décharge",
|
||||||
"dailyBreakdown": "Répartition quotidienne",
|
"dailyBreakdown": "Répartition quotidienne",
|
||||||
"prevWeek": "(semaine précédente)",
|
"prevWeek": "(semaine précédente)",
|
||||||
"sendReport": "Envoyer le rapport",
|
"sendReport": "Envoyer le rapport",
|
||||||
|
|
@ -136,5 +138,245 @@
|
||||||
"demo_custom_group": "Personnalisé (peut utiliser Mistral IA)",
|
"demo_custom_group": "Personnalisé (peut utiliser Mistral IA)",
|
||||||
"demo_custom_option": "Saisir une alarme personnalisée…",
|
"demo_custom_option": "Saisir une alarme personnalisée…",
|
||||||
"demo_custom_placeholder": "ex. UnknownBatteryFault",
|
"demo_custom_placeholder": "ex. UnknownBatteryFault",
|
||||||
"demo_diagnose_button": "Diagnostiquer"
|
"demo_diagnose_button": "Diagnostiquer",
|
||||||
|
"alarm_AbnormalGridVoltage": "Tension réseau anormale",
|
||||||
|
"alarm_AbnormalGridFrequency": "Fréquence réseau anormale",
|
||||||
|
"alarm_InvertedSequenceOfGridVoltage": "Séquence de tension inversée",
|
||||||
|
"alarm_GridVoltagePhaseLoss": "Perte de phase réseau",
|
||||||
|
"alarm_AbnormalGridCurrent": "Courant réseau anormal",
|
||||||
|
"alarm_AbnormalOutputVoltage": "Tension de sortie anormale",
|
||||||
|
"alarm_AbnormalOutputFrequency": "Fréquence de sortie anormale",
|
||||||
|
"alarm_AbnormalNullLine": "Ligne neutre anormale",
|
||||||
|
"alarm_AbnormalOffGridOutputVoltage": "Tension de sortie hors réseau anormale",
|
||||||
|
"alarm_ExcessivelyHighAmbientTemperature": "Température ambiante trop élevée",
|
||||||
|
"alarm_ExcessiveRadiatorTemperature": "Température excessive du radiateur",
|
||||||
|
"alarm_PcbOvertemperature": "Température excessive PCB",
|
||||||
|
"alarm_DcConverterOvertemperature": "Température excessive convertisseur DC",
|
||||||
|
"alarm_InverterOvertemperatureAlarm": "Alarme température onduleur",
|
||||||
|
"alarm_InverterOvertemperature": "Température onduleur excessive",
|
||||||
|
"alarm_DcConverterOvertemperatureAlarm": "Alarme surchauffe convertisseur DC",
|
||||||
|
"alarm_InsulationFault": "Défaut d'isolation",
|
||||||
|
"alarm_LeakageProtectionFault": "Défaut protection fuite",
|
||||||
|
"alarm_AbnormalLeakageSelfCheck": "Auto-test fuite anormale",
|
||||||
|
"alarm_PoorGrounding": "Mise à la terre insuffisante",
|
||||||
|
"alarm_FanFault": "Défaut du ventilateur",
|
||||||
|
"alarm_AuxiliaryPowerFault": "Défaut d'alimentation auxiliaire",
|
||||||
|
"alarm_ModelCapacityFault": "Défaut de configuration",
|
||||||
|
"alarm_AbnormalLightningArrester": "Paratonnerre défectueux",
|
||||||
|
"alarm_IslandProtection": "Protection d'îlotage",
|
||||||
|
"alarm_Battery1NotConnected": "Batterie 1 non connectée",
|
||||||
|
"alarm_Battery1Overvoltage": "Tension batterie 1 trop élevée",
|
||||||
|
"alarm_Battery1Undervoltage": "Tension batterie 1 trop basse",
|
||||||
|
"alarm_Battery1DischargeEnd": "Fin de décharge batterie 1",
|
||||||
|
"alarm_Battery1Inverted": "Polarité batterie 1 inversée",
|
||||||
|
"alarm_Battery1OverloadTimeout": "Dépassement de charge Batterie 1",
|
||||||
|
"alarm_Battery1SoftStartFailure": "Échec démarrage Batterie 1",
|
||||||
|
"alarm_Battery1PowerTubeFault": "Défaut électronique Batterie 1",
|
||||||
|
"alarm_Battery1InsufficientPower": "Puissance insuffisante Batterie 1",
|
||||||
|
"alarm_Battery1BackupProhibited": "Sauvegarde interdite Batterie 1",
|
||||||
|
"alarm_Battery2NotConnected": "Batterie 2 non connectée",
|
||||||
|
"alarm_Battery2Overvoltage": "Tension batterie 2 élevée",
|
||||||
|
"alarm_Battery2Undervoltage": "Tension batterie 2 basse",
|
||||||
|
"alarm_Battery2DischargeEnd": "Fin décharge batterie 2",
|
||||||
|
"alarm_Battery2Inverted": "Polarité batterie 2 inversée",
|
||||||
|
"alarm_Battery2OverloadTimeout": "Dépassement de charge Batterie 2",
|
||||||
|
"alarm_Battery2SoftStartFailure": "Échec démarrage Batterie 2",
|
||||||
|
"alarm_Battery2PowerTubeFault": "Défaut électronique Batterie 2",
|
||||||
|
"alarm_Battery2InsufficientPower": "Puissance insuffisante Batterie 2",
|
||||||
|
"alarm_Battery2BackupProhibited": "Sauvegarde interdite Batterie 2",
|
||||||
|
"alarm_LithiumBattery1ChargeForbidden": "Charge batterie lithium 1 interdite",
|
||||||
|
"alarm_LithiumBattery1DischargeForbidden": "Décharge batterie lithium 1 interdite",
|
||||||
|
"alarm_LithiumBattery2ChargeForbidden": "Charge batterie lithium 2 interdite",
|
||||||
|
"alarm_LithiumBattery2DischargeForbidden": "Décharge batterie lithium 2 interdite",
|
||||||
|
"alarm_LithiumBattery1Full": "Batterie lithium 1 pleine",
|
||||||
|
"alarm_LithiumBattery1DischargeEnd": "Fin de décharge batterie lithium 1",
|
||||||
|
"alarm_LithiumBattery2Full": "Batterie lithium 2 pleine",
|
||||||
|
"alarm_LithiumBattery2DischargeEnd": "Fin de décharge batterie lithium 2",
|
||||||
|
"alarm_LeadBatteryTemperatureAbnormality": "Température anormale batterie plomb",
|
||||||
|
"alarm_BatteryAccessMethodError": "Erreur de méthode d'accès batterie",
|
||||||
|
"alarm_Pv1NotAccessed": "Chaîne PV1 non accessible",
|
||||||
|
"alarm_Pv1Overvoltage": "Survoltage PV1",
|
||||||
|
"alarm_AbnormalPv1CurrentSharing": "Partage de courant PV1 anormal",
|
||||||
|
"alarm_Pv1PowerTubeFault": "Défaut du tube de puissance PV1",
|
||||||
|
"alarm_Pv1SoftStartFailure": "Échec de démarrage doux PV1",
|
||||||
|
"alarm_Pv1OverloadTimeout": "Dépassement de charge PV1",
|
||||||
|
"alarm_Pv1InsufficientPower": "Puissance PV1 insuffisante",
|
||||||
|
"alarm_Photovoltaic1Overcurrent": "Surintensité PV1",
|
||||||
|
"alarm_Pv2NotAccessed": "Chaîne PV2 inaccessible",
|
||||||
|
"alarm_Pv2Overvoltage": "Survoltage PV2",
|
||||||
|
"alarm_AbnormalPv2CurrentSharing": "Partage de courant anormal PV2",
|
||||||
|
"alarm_Pv2PowerTubeFault": "Défaillance du tube de puissance PV2",
|
||||||
|
"alarm_Pv2SoftStartFailure": "Échec de démarrage progressif PV2",
|
||||||
|
"alarm_Pv2OverloadTimeout": "Dépassement de charge PV2",
|
||||||
|
"alarm_Pv2InsufficientPower": "Puissance insuffisante PV2",
|
||||||
|
"alarm_Pv3NotConnected": "PV3 non connecté",
|
||||||
|
"alarm_Pv3Overvoltage": "Survoltage PV3",
|
||||||
|
"alarm_Pv3AverageCurrentAnomaly": "Anomalie courant PV3",
|
||||||
|
"alarm_Pv3PowerTubeFailure": "Défaillance tube PV3",
|
||||||
|
"alarm_Pv3SoftStartFailure": "Échec démarrage PV3",
|
||||||
|
"alarm_Pv3OverloadTimeout": "Dépassement de charge PV3",
|
||||||
|
"alarm_Pv3ReverseConnection": "Connexion inversée PV3",
|
||||||
|
"alarm_Pv4NotConnected": "Chaîne PV4 non connectée",
|
||||||
|
"alarm_Pv4Overvoltage": "Survoltage PV4",
|
||||||
|
"alarm_Pv4AverageCurrentAnomaly": "Anomalie de courant PV4",
|
||||||
|
"alarm_Pv4PowerTubeFailure": "Défaillance du tube de puissance PV4",
|
||||||
|
"alarm_Pv4SoftStartFailure": "Échec du démarrage progressif PV4",
|
||||||
|
"alarm_Pv4OverloadTimeout": "Dépassement de charge PV4",
|
||||||
|
"alarm_Pv4ReverseConnection": "Connexion inversée PV4",
|
||||||
|
"alarm_InsufficientPhotovoltaicPower": "Puissance photovoltaïque insuffisante",
|
||||||
|
"alarm_DcBusOvervoltage": "Tension DC trop élevée",
|
||||||
|
"alarm_DcBusUndervoltage": "Tension DC trop basse",
|
||||||
|
"alarm_DcBusVoltageUnbalance": "Déséquilibre tension DC",
|
||||||
|
"alarm_BusSlowOvervoltage": "Tension DC lente excessive",
|
||||||
|
"alarm_HardwareBusOvervoltage": "Tension DC critique",
|
||||||
|
"alarm_BusSoftStartFailure": "Échec démarrage progressif",
|
||||||
|
"alarm_InverterPowerTubeFault": "Défaut tube de puissance",
|
||||||
|
"alarm_HardwareOvercurrent": "Surintensité matérielle",
|
||||||
|
"alarm_DcConverterOvervoltage": "Survoltage convertisseur DC",
|
||||||
|
"alarm_DcConverterHardwareOvervoltage": "Survoltage matériel convertisseur DC",
|
||||||
|
"alarm_DcConverterOvercurrent": "Surintensité convertisseur CC",
|
||||||
|
"alarm_DcConverterHardwareOvercurrent": "Surintensité matérielle convertisseur CC",
|
||||||
|
"alarm_DcConverterResonatorOvercurrent": "Surintensité résonateur convertisseur CC",
|
||||||
|
"alarm_SystemOutputOverload": "Surcharge de sortie système",
|
||||||
|
"alarm_InverterOverload": "Surcharge onduleur",
|
||||||
|
"alarm_InverterOverloadTimeout": "Dépassement de charge de l'onduleur",
|
||||||
|
"alarm_LoadPowerOverload": "Surcharge de puissance de charge",
|
||||||
|
"alarm_BalancedCircuitOverloadTimeout": "Dépassement de charge du circuit équilibré",
|
||||||
|
"alarm_InverterSoftStartFailure": "Échec de démarrage progressif de l'onduleur",
|
||||||
|
"alarm_Dsp1ParameterSettingFault": "Défaillance de paramétrage DSP 1",
|
||||||
|
"alarm_Dsp2ParameterSettingFault": "Paramètre DSP2 incorrect",
|
||||||
|
"alarm_DspVersionCompatibilityFault": "Incompatibilité version DSP",
|
||||||
|
"alarm_CpldVersionCompatibilityFault": "Incompatibilité version CPLD",
|
||||||
|
"alarm_CpldCommunicationFault": "Échec communication CPLD",
|
||||||
|
"alarm_DspCommunicationFault": "Échec communication DSP",
|
||||||
|
"alarm_OutputVoltageDcOverlimit": "Tension de sortie DC excessive",
|
||||||
|
"alarm_OutputCurrentDcOverlimit": "Courant de sortie DC excessif",
|
||||||
|
"alarm_RelaySelfCheckFails": "Auto-test relais échoué",
|
||||||
|
"alarm_InverterRelayOpen": "Relais de l'onduleur ouvert",
|
||||||
|
"alarm_InverterRelayShortCircuit": "Relais de l'onduleur en court-circuit",
|
||||||
|
"alarm_OpenCircuitOfPowerGridRelay": "Relais du réseau ouvert",
|
||||||
|
"alarm_ShortCircuitOfPowerGridRelay": "Court-circuit du relais réseau",
|
||||||
|
"alarm_GeneratorRelayOpenCircuit": "Relais du générateur ouvert",
|
||||||
|
"alarm_GeneratorRelayShortCircuit": "Court-circuit du relais générateur",
|
||||||
|
"alarm_AbnormalInverter": "Onduleur anormal",
|
||||||
|
"alarm_ParallelCommunicationAlarm": "Alarme de communication parallèle",
|
||||||
|
"alarm_ParallelModuleMissing": "Module parallèle manquant",
|
||||||
|
"alarm_DuplicateMachineNumbersForParallelModules": "Numéros de machine en double",
|
||||||
|
"alarm_ParameterConflictInParallelModule": "Conflit de paramètres parallèle",
|
||||||
|
"alarm_SystemDerating": "Réduction de puissance du système",
|
||||||
|
"alarm_PvAccessMethodErrorAlarm": "Erreur méthode d'accès PV",
|
||||||
|
"alarm_ReservedAlarms4": "Alarme réservée 4",
|
||||||
|
"alarm_ReservedAlarms5": "Alarme réservée 5",
|
||||||
|
"alarm_ReverseMeterConnection": "Connexion du compteur inversée",
|
||||||
|
"alarm_InverterSealPulse": "Impulsion de scellement de l'onduleur",
|
||||||
|
"alarm_AbnormalDieselGeneratorVoltage": "Tension anormale du générateur diesel",
|
||||||
|
"alarm_AbnormalDieselGeneratorFrequency": "Fréquence anormale du générateur diesel",
|
||||||
|
"alarm_DieselGeneratorVoltageReverseSequence": "Séquence de phase inversée du générateur",
|
||||||
|
"alarm_DieselGeneratorVoltageOutOfPhase": "Déphasage du générateur",
|
||||||
|
"alarm_GeneratorOverload": "Surcharge du générateur",
|
||||||
|
"alarm_StringFault": "Défaut de chaîne",
|
||||||
|
"alarm_PvStringPidQuickConnectAbnormal": "Connexion rapide anormale",
|
||||||
|
"alarm_DcSpdFunctionAbnormal": "Problème de protection DC",
|
||||||
|
"alarm_PvShortCircuited": "Court-circuit PV",
|
||||||
|
"alarm_PvBoostDriverAbnormal": "Problème de convertisseur",
|
||||||
|
"alarm_AcSpdFunctionAbnormal": "Problème de protection contre les surtensions AC",
|
||||||
|
"alarm_DcFuseBlown": "Fusible DC grillé",
|
||||||
|
"alarm_DcInputVoltageTooHigh": "Tension DC d'entrée trop élevée",
|
||||||
|
"alarm_PvReversed": "Polarité PV inversée",
|
||||||
|
"alarm_PidFunctionAbnormal": "Problème de fonction PID",
|
||||||
|
"alarm_PvStringDisconnected": "Chaîne PV déconnectée",
|
||||||
|
"alarm_PvStringCurrentUnbalanced": "Déséquilibre de courant PV",
|
||||||
|
"alarm_NoUtilityGrid": "Réseau électrique absent",
|
||||||
|
"alarm_GridVoltageOutOfRange": "Tension réseau hors plage",
|
||||||
|
"alarm_GridFrequencyOutOfRange": "Fréquence réseau hors plage",
|
||||||
|
"alarm_Overload": "Surcharge",
|
||||||
|
"alarm_MeterDisconnected": "Compteur déconnecté",
|
||||||
|
"alarm_MeterReverselyConnected": "Compteur inversé",
|
||||||
|
"alarm_LinePeVoltageAbnormal": "Tension anormale",
|
||||||
|
"alarm_PhaseSequenceError": "Séquence de phase erronée",
|
||||||
|
"alarm_FanFailure": "Défaillance du ventilateur",
|
||||||
|
"alarm_MeterAbnormal": "Compteur anormal",
|
||||||
|
"alarm_OptimizerCommunicationAbnormal": "Communication optimiseur anormale",
|
||||||
|
"alarm_OverTemperature": "Température excessive",
|
||||||
|
"alarm_OverTemperatureAlarm": "Alarme température élevée",
|
||||||
|
"alarm_NtcTemperatureSensorBroken": "Capteur de température défectueux",
|
||||||
|
"alarm_SyncSignalAbnormal": "Signal de synchronisation anormal",
|
||||||
|
"alarm_GridStartupConditionsNotMet": "Conditions de démarrage réseau non remplies",
|
||||||
|
"alarm_BatteryCommunicationFailure": "Échec de communication batterie",
|
||||||
|
"alarm_BatteryDisconnected": "Batterie déconnectée",
|
||||||
|
"alarm_BatteryVoltageTooHigh": "Tension batterie trop élevée",
|
||||||
|
"alarm_BatteryVoltageTooLow": "Tension batterie trop basse",
|
||||||
|
"alarm_BatteryReverseConnected": "Batterie branchée à l'envers",
|
||||||
|
"alarm_LeadAcidTempSensorDisconnected": "Capteur température batterie plomb désactivé",
|
||||||
|
"alarm_BatteryTemperatureOutOfRange": "Température batterie hors plage",
|
||||||
|
"alarm_BmsFault": "Défaillance BMS",
|
||||||
|
"alarm_LithiumBatteryOverload": "Surcharge batterie lithium",
|
||||||
|
"alarm_BmsCommunicationAbnormal": "Communication BMS anormale",
|
||||||
|
"alarm_BatterySpdAbnormal": "Défaillance SPD batterie",
|
||||||
|
"alarm_OutputDcComponentBiasAbnormal": "Biais DC de sortie anormal",
|
||||||
|
"alarm_DcComponentOverHighOutputVoltage": "Tension de sortie trop élevée",
|
||||||
|
"alarm_OffGridOutputVoltageTooLow": "Tension de sortie hors réseau trop basse",
|
||||||
|
"alarm_OffGridOutputVoltageTooHigh": "Tension de sortie hors réseau trop élevée",
|
||||||
|
"alarm_OffGridOutputOverCurrent": "Courant de sortie hors réseau trop élevé",
|
||||||
|
"alarm_OffGridOutputOverload": "Surcharge sortie hors réseau",
|
||||||
|
"alarm_BalancedCircuitAbnormal": "Circuit équilibré anormal",
|
||||||
|
"alarm_ExportLimitationFailSafe": "Sécurité limite d'exportation",
|
||||||
|
"alarm_DcBiasAbnormal": "Biais DC anormal",
|
||||||
|
"alarm_HighDcComponentOutputCurrent": "Composante DC élevée courant de sortie",
|
||||||
|
"alarm_BusVoltageSamplingAbnormal": "Tension d'alimentation anormale",
|
||||||
|
"alarm_RelayFault": "Défaillance du relais",
|
||||||
|
"alarm_BusVoltageAbnormal": "Tension d'alimentation anormale",
|
||||||
|
"alarm_InternalCommunicationFailure": "Échec de communication interne",
|
||||||
|
"alarm_TemperatureSensorDisconnected": "Capteur de température déconnecté",
|
||||||
|
"alarm_IgbtDriveFault": "Défaillance de l'IGBT",
|
||||||
|
"alarm_EepromError": "Erreur EEPROM",
|
||||||
|
"alarm_AuxiliaryPowerAbnormal": "Alimentation auxiliaire anormale",
|
||||||
|
"alarm_DcAcOvercurrentProtection": "Protection contre les surintensités",
|
||||||
|
"alarm_CommunicationProtocolMismatch": "Incompatibilité de protocole",
|
||||||
|
"alarm_DspComFirmwareMismatch": "Incompatibilité firmware DSP/COM",
|
||||||
|
"alarm_DspSoftwareHardwareMismatch": "Incompatibilité logiciel DSP/matériel",
|
||||||
|
"alarm_CpldAbnormal": "CPLD anormal",
|
||||||
|
"alarm_RedundancySamplingInconsistent": "Échantillonnage redondant incohérent",
|
||||||
|
"alarm_PwmPassThroughSignalFailure": "Échec signal PWM",
|
||||||
|
"alarm_AfciSelfTestFailure": "Échec auto-test AFCI",
|
||||||
|
"alarm_PvCurrentSamplingAbnormal": "Mesure PV anormale",
|
||||||
|
"alarm_AcCurrentSamplingAbnormal": "Mesure AC anormale",
|
||||||
|
"alarm_BusSoftbootFailure": "Échec démarrage DC",
|
||||||
|
"alarm_EpoFault": "Défaillance EPO",
|
||||||
|
"alarm_MonitoringChipBootVerificationFailed": "Échec vérification démarrage",
|
||||||
|
"alarm_BmsCommunicationFailure": "Échec communication BMS",
|
||||||
|
"alarm_BmsChargeDischargeFailure": "Échec charge/décharge BMS",
|
||||||
|
"alarm_BatteryVoltageLow": "Tension batterie faible",
|
||||||
|
"alarm_BatteryVoltageHigh": "Tension batterie élevée",
|
||||||
|
"alarm_BatteryTemperatureAbnormal": "Température anormale de la batterie",
|
||||||
|
"alarm_BatteryReversed": "Batterie inversée",
|
||||||
|
"alarm_BatteryOpenCircuit": "Circuit batterie ouvert",
|
||||||
|
"alarm_BatteryOverloadProtection": "Protection contre la surcharge",
|
||||||
|
"alarm_Bus2VoltageAbnormal": "Tension anormale Bus2",
|
||||||
|
"alarm_BatteryChargeOcp": "Surintensité charge batterie",
|
||||||
|
"alarm_BatteryDischargeOcp": "Surintensité décharge batterie",
|
||||||
|
"alarm_BatterySoftStartFailed": "Démarrage en douceur échoué",
|
||||||
|
"alarm_EpsOutputShortCircuited": "Circuit de secours en court-circuit",
|
||||||
|
"alarm_OffGridBusVoltageLow": "Tension bus hors réseau basse",
|
||||||
|
"alarm_OffGridTerminalVoltageAbnormal": "Tension anormale terminal hors réseau",
|
||||||
|
"alarm_SoftStartFailed": "Démarrage progressif échoué",
|
||||||
|
"alarm_OffGridOutputVoltageAbnormal": "Tension de sortie hors réseau anormale",
|
||||||
|
"alarm_BalancedCircuitSelfTestFailed": "Autotest circuit équilibré échoué",
|
||||||
|
"alarm_HighDcComponentOutputVoltage": "Tension de sortie à composante CC élevée",
|
||||||
|
"alarm_OffGridParallelSignalAbnormal": "Signal parallèle hors réseau anormal",
|
||||||
|
"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",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
|
|
@ -103,14 +103,16 @@
|
||||||
"reportTitle": "Rapporto settimanale sulle prestazioni",
|
"reportTitle": "Rapporto settimanale sulle prestazioni",
|
||||||
"weeklyInsights": "Approfondimenti settimanali",
|
"weeklyInsights": "Approfondimenti settimanali",
|
||||||
"weeklySavings": "I tuoi risparmi questa settimana",
|
"weeklySavings": "I tuoi risparmi questa settimana",
|
||||||
"solarEnergyUsed": "Energia solare utilizzata",
|
"solarEnergyUsed": "Energia risparmiata",
|
||||||
"solarStayedHome": "della tua energia solare è rimasta a casa",
|
"solarStayedHome": "solare + batteria, non acquistata dalla rete",
|
||||||
|
"daysOfYourUsage": "giorni del tuo consumo",
|
||||||
"estMoneySaved": "Risparmio stimato",
|
"estMoneySaved": "Risparmio stimato",
|
||||||
"atCHFRate": "a 0,27 CHF/kWh media",
|
"atCHFRate": "a 0,39 CHF/kWh media",
|
||||||
"solarCoverage": "Copertura solare",
|
"solarCoverage": "Autosufficienza",
|
||||||
"fromSolarSub": "del consumo da fonte solare",
|
"fromSolarSub": "da solare + batteria",
|
||||||
|
"avgDailyConsumption": "Consumo medio giornaliero",
|
||||||
"batteryEfficiency": "Efficienza della batteria",
|
"batteryEfficiency": "Efficienza della batteria",
|
||||||
"batteryEffSub": "energia in uscita vs energia in entrata",
|
"batteryEffSub": "scarica vs carica",
|
||||||
"weeklySummary": "Riepilogo settimanale",
|
"weeklySummary": "Riepilogo settimanale",
|
||||||
"metric": "Metrica",
|
"metric": "Metrica",
|
||||||
"thisWeek": "Questa settimana",
|
"thisWeek": "Questa settimana",
|
||||||
|
|
@ -119,7 +121,7 @@
|
||||||
"consumption": "Consumo",
|
"consumption": "Consumo",
|
||||||
"gridImport": "Importazione rete",
|
"gridImport": "Importazione rete",
|
||||||
"gridExport": "Esportazione rete",
|
"gridExport": "Esportazione rete",
|
||||||
"batteryInOut": "Batteria Entrata / Uscita",
|
"batteryInOut": "Batteria Carica / Scarica",
|
||||||
"dailyBreakdown": "Ripartizione giornaliera",
|
"dailyBreakdown": "Ripartizione giornaliera",
|
||||||
"prevWeek": "(settimana precedente)",
|
"prevWeek": "(settimana precedente)",
|
||||||
"sendReport": "Invia rapporto",
|
"sendReport": "Invia rapporto",
|
||||||
|
|
@ -147,5 +149,234 @@
|
||||||
"demo_custom_group": "Personalizzato (potrebbe usare Mistral IA)",
|
"demo_custom_group": "Personalizzato (potrebbe usare Mistral IA)",
|
||||||
"demo_custom_option": "Inserisci allarme personalizzato…",
|
"demo_custom_option": "Inserisci allarme personalizzato…",
|
||||||
"demo_custom_placeholder": "es. UnknownBatteryFault",
|
"demo_custom_placeholder": "es. UnknownBatteryFault",
|
||||||
"demo_diagnose_button": "Diagnostica"
|
"demo_diagnose_button": "Diagnostica",
|
||||||
|
"alarm_AbnormalGridVoltage": "Tensione di rete anomala",
|
||||||
|
"alarm_AbnormalGridFrequency": "Frequenza di rete anomala",
|
||||||
|
"alarm_InvertedSequenceOfGridVoltage": "Sequenza di fase invertita",
|
||||||
|
"alarm_GridVoltagePhaseLoss": "Fase di rete mancante",
|
||||||
|
"alarm_AbnormalGridCurrent": "Corrente di rete anomala",
|
||||||
|
"alarm_AbnormalOutputVoltage": "Tensione di uscita anomala",
|
||||||
|
"alarm_AbnormalOutputFrequency": "Frequenza di uscita anomala",
|
||||||
|
"alarm_AbnormalNullLine": "Linea neutra anomala",
|
||||||
|
"alarm_AbnormalOffGridOutputVoltage": "Tensione di uscita off-grid anomala",
|
||||||
|
"alarm_ExcessivelyHighAmbientTemperature": "Temperatura ambiente eccessivamente alta",
|
||||||
|
"alarm_ExcessiveRadiatorTemperature": "Temperatura radiatore eccessiva",
|
||||||
|
"alarm_PcbOvertemperature": "Temperatura PCB eccessiva",
|
||||||
|
"alarm_DcConverterOvertemperature": "Temperatura convertitore DC eccessiva",
|
||||||
|
"alarm_InverterOvertemperatureAlarm": "Allarme temperatura inverter elevata",
|
||||||
|
"alarm_InverterOvertemperature": "Temperatura inverter eccessiva",
|
||||||
|
"alarm_DcConverterOvertemperatureAlarm": "Allarme sovratemperatura convertitore DC",
|
||||||
|
"alarm_InsulationFault": "Guasto isolamento",
|
||||||
|
"alarm_LeakageProtectionFault": "Guasto protezione dispersione",
|
||||||
|
"alarm_AbnormalLeakageSelfCheck": "Autocontrollo dispersione anomalo",
|
||||||
|
"alarm_PoorGrounding": "Messa a terra insufficiente",
|
||||||
|
"alarm_FanFault": "Guasto Ventola",
|
||||||
|
"alarm_AuxiliaryPowerFault": "Guasto Alimentazione Ausiliaria",
|
||||||
|
"alarm_ModelCapacityFault": "Guasto Configurazione Modello",
|
||||||
|
"alarm_AbnormalLightningArrester": "Parasurtense Anomalo",
|
||||||
|
"alarm_IslandProtection": "Protezione Isola",
|
||||||
|
"alarm_Battery1NotConnected": "Batteria 1 non collegata",
|
||||||
|
"alarm_Battery1Overvoltage": "Batteria 1 sovratensione",
|
||||||
|
"alarm_Battery1Undervoltage": "Batteria 1 sottotensione",
|
||||||
|
"alarm_Battery1DischargeEnd": "Batteria 1 scarica",
|
||||||
|
"alarm_Battery1Inverted": "Batteria 1 polarità invertita",
|
||||||
|
"alarm_Battery1OverloadTimeout": "Timeout sovraccarico batteria 1",
|
||||||
|
"alarm_Battery1SoftStartFailure": "Avvio morbido fallito batteria 1",
|
||||||
|
"alarm_Battery1PowerTubeFault": "Guasto modulo potenza batteria 1",
|
||||||
|
"alarm_Battery1InsufficientPower": "Potenza insufficiente batteria 1",
|
||||||
|
"alarm_Battery1BackupProhibited": "Backup vietato batteria 1",
|
||||||
|
"alarm_Battery2NotConnected": "Batteria 2 non collegata",
|
||||||
|
"alarm_Battery2Overvoltage": "Sovratensione batteria 2",
|
||||||
|
"alarm_Battery2Undervoltage": "Sottotensione batteria 2",
|
||||||
|
"alarm_Battery2DischargeEnd": "Fine scarica batteria 2",
|
||||||
|
"alarm_Battery2Inverted": "Polarità invertita batteria 2",
|
||||||
|
"alarm_Battery2OverloadTimeout": "Timeout sovraccarico Batteria 2",
|
||||||
|
"alarm_Battery2SoftStartFailure": "Avvio morbido fallito Batteria 2",
|
||||||
|
"alarm_Battery2PowerTubeFault": "Guasto modulo potenza Batteria 2",
|
||||||
|
"alarm_Battery2InsufficientPower": "Potenza insufficiente Batteria 2",
|
||||||
|
"alarm_Battery2BackupProhibited": "Backup vietato Batteria 2",
|
||||||
|
"alarm_LithiumBattery1ChargeForbidden": "Carica Batteria Litio 1 Bloccata",
|
||||||
|
"alarm_LithiumBattery1DischargeForbidden": "Scarica Batteria Litio 1 Bloccata",
|
||||||
|
"alarm_LithiumBattery2ChargeForbidden": "Carica Batteria Litio 2 Bloccata",
|
||||||
|
"alarm_LithiumBattery2DischargeForbidden": "Scarica Batteria Litio 2 Bloccata",
|
||||||
|
"alarm_LithiumBattery1Full": "Batteria Litio 1 Piena",
|
||||||
|
"alarm_LithiumBattery1DischargeEnd": "Fine scarica batteria litio 1",
|
||||||
|
"alarm_LithiumBattery2Full": "Batteria litio 2 piena",
|
||||||
|
"alarm_LithiumBattery2DischargeEnd": "Fine scarica batteria litio 2",
|
||||||
|
"alarm_LeadBatteryTemperatureAbnormality": "Temperatura batteria piombo anomala",
|
||||||
|
"alarm_BatteryAccessMethodError": "Errore metodo accesso batteria",
|
||||||
|
"alarm_Pv1NotAccessed": "PV1 non accessibile",
|
||||||
|
"alarm_Pv1Overvoltage": "Sovratensione PV1",
|
||||||
|
"alarm_AbnormalPv1CurrentSharing": "Corrente PV1 anomala",
|
||||||
|
"alarm_Pv1PowerTubeFault": "Guasto tubo di potenza PV1",
|
||||||
|
"alarm_Pv1SoftStartFailure": "Avvio morbido PV1 fallito",
|
||||||
|
"alarm_Pv1OverloadTimeout": "Sovraccarico PV1",
|
||||||
|
"alarm_Pv1InsufficientPower": "Bassa potenza PV1",
|
||||||
|
"alarm_Photovoltaic1Overcurrent": "Sovracorrente PV1",
|
||||||
|
"alarm_Pv2NotAccessed": "PV2 non rilevato",
|
||||||
|
"alarm_Pv2Overvoltage": "Sovratensione PV2",
|
||||||
|
"alarm_AbnormalPv2CurrentSharing": "Condivisione Corrente PV2 Anomala",
|
||||||
|
"alarm_Pv2PowerTubeFault": "Guasto Tubo di Potenza PV2",
|
||||||
|
"alarm_Pv2SoftStartFailure": "Avvio Morbido PV2 Fallito",
|
||||||
|
"alarm_Pv2OverloadTimeout": "Sovraccarico PV2 Timeout",
|
||||||
|
"alarm_Pv2InsufficientPower": "Potenza Insufficiente PV2",
|
||||||
|
"alarm_Pv3NotConnected": "PV3 non connesso",
|
||||||
|
"alarm_Pv3Overvoltage": "Sovratensione PV3",
|
||||||
|
"alarm_Pv3AverageCurrentAnomaly": "Corrente PV3 anomala",
|
||||||
|
"alarm_Pv3PowerTubeFailure": "Guasto tubo di potenza PV3",
|
||||||
|
"alarm_Pv3SoftStartFailure": "Avvio morbido PV3 fallito",
|
||||||
|
"alarm_Pv3OverloadTimeout": "Sovraccarico PV3",
|
||||||
|
"alarm_Pv3ReverseConnection": "Connessione Inversa PV3",
|
||||||
|
"alarm_Pv4NotConnected": "PV4 Non Collegato",
|
||||||
|
"alarm_Pv4Overvoltage": "Sovratensione PV4",
|
||||||
|
"alarm_Pv4AverageCurrentAnomaly": "Anomalia Corrente PV4",
|
||||||
|
"alarm_Pv4PowerTubeFailure": "Guasto Tubo di Potenza PV4",
|
||||||
|
"alarm_Pv4SoftStartFailure": "Avvio Morbido PV4 Fallito",
|
||||||
|
"alarm_Pv4OverloadTimeout": "Sovraccarico PV4",
|
||||||
|
"alarm_Pv4ReverseConnection": "Connessione Inversa PV4",
|
||||||
|
"alarm_InsufficientPhotovoltaicPower": "Potenza Fotovoltaica Insufficiente",
|
||||||
|
"alarm_DcBusOvervoltage": "Sovratensione Bus DC",
|
||||||
|
"alarm_DcBusUndervoltage": "Sottotensione Bus DC",
|
||||||
|
"alarm_DcBusVoltageUnbalance": "Squilibrio Tensione Bus DC",
|
||||||
|
"alarm_BusSlowOvervoltage": "Sovratensione Lenta Bus",
|
||||||
|
"alarm_HardwareBusOvervoltage": "Sovratensione Critica Bus",
|
||||||
|
"alarm_BusSoftStartFailure": "Avvio morbido fallito",
|
||||||
|
"alarm_InverterPowerTubeFault": "Guasto al modulo di potenza",
|
||||||
|
"alarm_HardwareOvercurrent": "Sovracorrente hardware",
|
||||||
|
"alarm_DcConverterOvervoltage": "Sovratensione convertitore DC",
|
||||||
|
"alarm_DcConverterHardwareOvervoltage": "Sovratensione hardware convertitore",
|
||||||
|
"alarm_DcConverterOvercurrent": "Sovraccarico convertitore DC",
|
||||||
|
"alarm_DcConverterHardwareOvercurrent": "Sovraccarico hardware convertitore DC",
|
||||||
|
"alarm_DcConverterResonatorOvercurrent": "Sovraccarico risonatore convertitore DC",
|
||||||
|
"alarm_SystemOutputOverload": "Sovraccarico uscita sistema",
|
||||||
|
"alarm_InverterOverload": "Sovraccarico inverter",
|
||||||
|
"alarm_InverterOverloadTimeout": "Sovraccarico Inverter",
|
||||||
|
"alarm_LoadPowerOverload": "Sovraccarico Carico",
|
||||||
|
"alarm_BalancedCircuitOverloadTimeout": "Sovraccarico Circuito Bilanciato",
|
||||||
|
"alarm_InverterSoftStartFailure": "Avvio Inverter Fallito",
|
||||||
|
"alarm_Dsp1ParameterSettingFault": "Parametri DSP Errati",
|
||||||
|
"alarm_Dsp2ParameterSettingFault": "Errore configurazione parametri DSP 2",
|
||||||
|
"alarm_DspVersionCompatibilityFault": "Errore compatibilità versione DSP",
|
||||||
|
"alarm_CpldVersionCompatibilityFault": "Errore compatibilità versione CPLD",
|
||||||
|
"alarm_CpldCommunicationFault": "Errore comunicazione CPLD",
|
||||||
|
"alarm_DspCommunicationFault": "Errore comunicazione DSP",
|
||||||
|
"alarm_OutputVoltageDcOverlimit": "Tensione DC in uscita eccessiva",
|
||||||
|
"alarm_OutputCurrentDcOverlimit": "Corrente DC in uscita eccessiva",
|
||||||
|
"alarm_RelaySelfCheckFails": "Autotest relè fallito",
|
||||||
|
"alarm_InverterRelayOpen": "Relè inverter aperto",
|
||||||
|
"alarm_InverterRelayShortCircuit": "Relè inverter in cortocircuito",
|
||||||
|
"alarm_OpenCircuitOfPowerGridRelay": "Relè di rete aperto",
|
||||||
|
"alarm_ShortCircuitOfPowerGridRelay": "Relè di rete in cortocircuito",
|
||||||
|
"alarm_GeneratorRelayOpenCircuit": "Relè del generatore aperto",
|
||||||
|
"alarm_GeneratorRelayShortCircuit": "Relè del generatore in cortocircuito",
|
||||||
|
"alarm_AbnormalInverter": "Inverter anomalo",
|
||||||
|
"alarm_ParallelCommunicationAlarm": "Allarme Comunicazione Parallela",
|
||||||
|
"alarm_ParallelModuleMissing": "Modulo Parallelo Mancante",
|
||||||
|
"alarm_DuplicateMachineNumbersForParallelModules": "Numeri Duplicati Moduli Paralleli",
|
||||||
|
"alarm_ParameterConflictInParallelModule": "Conflitto Parametri Modulo Parallelo",
|
||||||
|
"alarm_SystemDerating": "Riduzione Prestazioni Sistema",
|
||||||
|
"alarm_PvAccessMethodErrorAlarm": "Errore Metodo Accesso PV",
|
||||||
|
"alarm_ReservedAlarms4": "Allarme Riservato 4",
|
||||||
|
"alarm_ReservedAlarms5": "Allarme Riservato 5",
|
||||||
|
"alarm_ReverseMeterConnection": "Contatore Inverso",
|
||||||
|
"alarm_InverterSealPulse": "Impulso Sigillo Inverter",
|
||||||
|
"alarm_AbnormalDieselGeneratorVoltage": "Tensione anomala del generatore",
|
||||||
|
"alarm_AbnormalDieselGeneratorFrequency": "Frequenza anomala del generatore",
|
||||||
|
"alarm_DieselGeneratorVoltageReverseSequence": "Sequenza di fase invertita",
|
||||||
|
"alarm_DieselGeneratorVoltageOutOfPhase": "Generatore fuori fase",
|
||||||
|
"alarm_GeneratorOverload": "Sovraccarico del generatore",
|
||||||
|
"alarm_StringFault": "Guasto Stringa",
|
||||||
|
"alarm_PvStringPidQuickConnectAbnormal": "Connessione Rapida Anomala",
|
||||||
|
"alarm_DcSpdFunctionAbnormal": "Protezione SPD Anomala",
|
||||||
|
"alarm_PvShortCircuited": "Cortocircuito PV",
|
||||||
|
"alarm_PvBoostDriverAbnormal": "Driver di Boost Anomalo",
|
||||||
|
"alarm_AcSpdFunctionAbnormal": "Funzione SPD AC anomala",
|
||||||
|
"alarm_DcFuseBlown": "Fusibile DC saltato",
|
||||||
|
"alarm_DcInputVoltageTooHigh": "Tensione DC in ingresso troppo alta",
|
||||||
|
"alarm_PvReversed": "Polarità PV invertita",
|
||||||
|
"alarm_PidFunctionAbnormal": "Funzione PID anomala",
|
||||||
|
"alarm_PvStringDisconnected": "Stringa PV disconnessa",
|
||||||
|
"alarm_PvStringCurrentUnbalanced": "Corrente stringa PV squilibrata",
|
||||||
|
"alarm_NoUtilityGrid": "Nessuna rete elettrica",
|
||||||
|
"alarm_GridVoltageOutOfRange": "Tensione rete fuori limite",
|
||||||
|
"alarm_GridFrequencyOutOfRange": "Frequenza rete fuori limite",
|
||||||
|
"alarm_Overload": "Sovraccarico",
|
||||||
|
"alarm_MeterDisconnected": "Contatore scollegato",
|
||||||
|
"alarm_MeterReverselyConnected": "Contatore collegato al contrario",
|
||||||
|
"alarm_LinePeVoltageAbnormal": "Tensione anomala PE",
|
||||||
|
"alarm_PhaseSequenceError": "Errore sequenza fase",
|
||||||
|
"alarm_FanFailure": "Guasto Ventilatore",
|
||||||
|
"alarm_MeterAbnormal": "Contatore Anomalo",
|
||||||
|
"alarm_OptimizerCommunicationAbnormal": "Comunicazione Ottimizzatore Anomala",
|
||||||
|
"alarm_OverTemperature": "Temperatura Eccessiva",
|
||||||
|
"alarm_OverTemperatureAlarm": "Allarme Temperatura Eccessiva",
|
||||||
|
"alarm_NtcTemperatureSensorBroken": "Sensore temperatura guasto",
|
||||||
|
"alarm_SyncSignalAbnormal": "Segnale di sincronizzazione anomalo",
|
||||||
|
"alarm_GridStartupConditionsNotMet": "Condizioni di avvio rete non soddisfatte",
|
||||||
|
"alarm_BatteryCommunicationFailure": "Comunicazione batteria fallita",
|
||||||
|
"alarm_BatteryDisconnected": "Batteria scollegata",
|
||||||
|
"alarm_BatteryVoltageTooHigh": "Tensione batteria troppo alta",
|
||||||
|
"alarm_BatteryVoltageTooLow": "Tensione batteria troppo bassa",
|
||||||
|
"alarm_BatteryReverseConnected": "Batteria collegata al contrario",
|
||||||
|
"alarm_LeadAcidTempSensorDisconnected": "Sensore temperatura piombo acido scollegato",
|
||||||
|
"alarm_BatteryTemperatureOutOfRange": "Temperatura batteria fuori range",
|
||||||
|
"alarm_BmsFault": "Guasto BMS",
|
||||||
|
"alarm_LithiumBatteryOverload": "Sovraccarico Batteria Litio",
|
||||||
|
"alarm_BmsCommunicationAbnormal": "Comunicazione BMS Anomala",
|
||||||
|
"alarm_BatterySpdAbnormal": "SPD Batteria Anomalo",
|
||||||
|
"alarm_OutputDcComponentBiasAbnormal": "Bias DC di Uscita Anomalo",
|
||||||
|
"alarm_DcComponentOverHighOutputVoltage": "Tensione di uscita DC troppo alta",
|
||||||
|
"alarm_OffGridOutputVoltageTooLow": "Tensione di uscita off-grid troppo bassa",
|
||||||
|
"alarm_OffGridOutputVoltageTooHigh": "Tensione di uscita off-grid troppo alta",
|
||||||
|
"alarm_OffGridOutputOverCurrent": "Corrente di uscita off-grid troppo alta",
|
||||||
|
"alarm_OffGridOutputOverload": "Sovraccarico Uscita Off-Grid",
|
||||||
|
"alarm_BalancedCircuitAbnormal": "Circuiti Squilibrati Anomali",
|
||||||
|
"alarm_ExportLimitationFailSafe": "Limite Esportazione Sicurezza",
|
||||||
|
"alarm_DcBiasAbnormal": "Bias DC Anomalo",
|
||||||
|
"alarm_HighDcComponentOutputCurrent": "Alta Componente DC Corrente",
|
||||||
|
"alarm_BusVoltageSamplingAbnormal": "Campionamento tensione anomalo",
|
||||||
|
"alarm_RelayFault": "Guasto al relè",
|
||||||
|
"alarm_BusVoltageAbnormal": "Tensione bus anomala",
|
||||||
|
"alarm_InternalCommunicationFailure": "Comunicazione interna guasta",
|
||||||
|
"alarm_TemperatureSensorDisconnected": "Sensore temperatura scollegato",
|
||||||
|
"alarm_IgbtDriveFault": "Guasto guida IGBT",
|
||||||
|
"alarm_EepromError": "Errore EEPROM",
|
||||||
|
"alarm_AuxiliaryPowerAbnormal": "Alimentazione ausiliaria anomala",
|
||||||
|
"alarm_DcAcOvercurrentProtection": "Protezione sovracorrente DC/AC",
|
||||||
|
"alarm_CommunicationProtocolMismatch": "Protocollo di comunicazione non corrispondente",
|
||||||
|
"alarm_DspComFirmwareMismatch": "Incompatibilità firmware DSP/COM",
|
||||||
|
"alarm_DspSoftwareHardwareMismatch": "Incompatibilità software/hardware DSP",
|
||||||
|
"alarm_CpldAbnormal": "Anomalia CPLD",
|
||||||
|
"alarm_RedundancySamplingInconsistent": "Campionamento ridondante inconsistente",
|
||||||
|
"alarm_PwmPassThroughSignalFailure": "Guasto segnale PWM",
|
||||||
|
"alarm_AfciSelfTestFailure": "Test AFCI fallito",
|
||||||
|
"alarm_PvCurrentSamplingAbnormal": "Corrente PV anomala",
|
||||||
|
"alarm_AcCurrentSamplingAbnormal": "Corrente AC anomala",
|
||||||
|
"alarm_BusSoftbootFailure": "Avvio bus fallito",
|
||||||
|
"alarm_EpoFault": "Guasto EPO",
|
||||||
|
"alarm_MonitoringChipBootVerificationFailed": "Verifica avvio chip monitoraggio fallita",
|
||||||
|
"alarm_BmsCommunicationFailure": "Comunicazione BMS fallita",
|
||||||
|
"alarm_BmsChargeDischargeFailure": "Carica/scarica BMS bloccata",
|
||||||
|
"alarm_BatteryVoltageLow": "Tensione batteria bassa",
|
||||||
|
"alarm_BatteryVoltageHigh": "Tensione batteria alta",
|
||||||
|
"alarm_BatteryTemperatureAbnormal": "Temperatura batteria anomala",
|
||||||
|
"alarm_BatteryReversed": "Batteria invertita",
|
||||||
|
"alarm_BatteryOpenCircuit": "Circolazione batteria aperta",
|
||||||
|
"alarm_BatteryOverloadProtection": "Protezione sovraccarico batteria",
|
||||||
|
"alarm_Bus2VoltageAbnormal": "Tensione Bus2 anomala",
|
||||||
|
"alarm_BatteryChargeOcp": "Sovraccarico carica batteria",
|
||||||
|
"alarm_BatteryDischargeOcp": "Sovraccarico scarica batteria",
|
||||||
|
"alarm_BatterySoftStartFailed": "Avvio batteria fallito",
|
||||||
|
"alarm_EpsOutputShortCircuited": "Uscita EPS in cortocircuito",
|
||||||
|
"alarm_OffGridBusVoltageLow": "Tensione bus off-grid bassa",
|
||||||
|
"alarm_OffGridTerminalVoltageAbnormal": "Tensione terminale anomala",
|
||||||
|
"alarm_SoftStartFailed": "Avvio morbido fallito",
|
||||||
|
"alarm_OffGridOutputVoltageAbnormal": "Tensione di uscita anomala",
|
||||||
|
"alarm_BalancedCircuitSelfTestFailed": "Autotest circuito bilanciato fallito",
|
||||||
|
"alarm_HighDcComponentOutputVoltage": "Tensione di uscita DC elevata",
|
||||||
|
"alarm_OffGridParallelSignalAbnormal": "Segnale parallelo off-grid anomalo",
|
||||||
|
"alarm_AFCIFault": "Guasto AFCI",
|
||||||
|
"alarm_GFCIHigh": "Corrente di guasto a terra elevata",
|
||||||
|
"alarm_PVVoltageHigh": "Tensione PV elevata",
|
||||||
|
"alarm_OffGridBusVoltageTooLow": "Tensione Bus Fuori Rete Troppo Bassa"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue