GenesisStatus: - taken POWERMON_RemainingSeconds,

ProductionUiCordonel: - check EOL remaining lifetime from firmware POWERMON_RemainingSeconds
This commit is contained in:
Thomas Wiedebusch
2025-08-11 16:51:19 +02:00
parent 46e2ceca04
commit 82ae52eb3c
11 changed files with 92 additions and 54 deletions
+1 -1
View File
@@ -13,4 +13,4 @@ using System.Reflection;
//
//[assembly: AssemblyVersion("1.2.*.0")]
[assembly: AssemblyVersion("2.7.4.*")]
[assembly: AssemblyVersion("2.7.5.*")]
+1
View File
@@ -33,6 +33,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cordonel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cordonels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=CUST/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DIAVASO/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dispached/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=DNMAX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Drabesch/@EntryIndexedValue">True</s:Boolean>
@@ -18469,7 +18469,7 @@
},
"description": "",
"version": {
"first": 69,
"first": 72,
"last": 72
},
"statictype": "dynamic",
@@ -7,6 +7,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
/// </summary>
public class GenesisStatus
{
/// <summary>
/// Remaining lifetime for Cordonel in years based on FW calculation.
/// </summary>
public Double? FwCalculatedRemainingLifeTimeYears { get; set; }
/// <summary>
/// Remaining lifetime for Cordonel in seconds based on FW calculation.
/// </summary>
public UInt64? FwCalculatedRemainingLifeTime_s { get; set; }
/// <summary>
/// Remaining lifetime for Cordonel in years based on battery drainage.
/// </summary>
@@ -280,6 +280,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
/// <remarks date="2024-Nov-15" author="Thomas Wiedebusch">
/// - errorMsg.
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - Readout FW based calculation of remaining lifetime in seconds.
/// </remarks>
public static Boolean BuildLifeTimeInformation(IGenesisMeter currentGenesis, GenesisStatus status, out String errorMsg)
{
Boolean retVal;
@@ -302,6 +305,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
status.InitialBatteryLoad_mAh = RegisterConverter.ByteArrayToValue<UInt32>(
currentGenesis.ReadRegister(Register.Powermon.BatteryInitialLoad));
var nullCheck = currentGenesis.ReadRegister(Register.Powermon.RemainingSeconds);
if (nullCheck == null)
status.FwCalculatedRemainingLifeTime_s = null;
else
status.FwCalculatedRemainingLifeTime_s =
RegisterConverter.ByteArrayToValue<UInt32>(nullCheck);
currentGenesis.Logout();
retVal = CalculateLifeTime(status);
@@ -337,6 +347,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
/// <remarks date="2025-Mar-25" author="Thomas Wiedebusch">
/// - Calculate storage months.
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - Calculate FW based calculation of remaining lifetime in years.
/// </remarks>
public static Boolean CalculateLifeTime(GenesisStatus status)
{
// Mark as false if the basic inputs are missed
@@ -361,6 +374,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
var estimatedLifeTime_s = status.ExceededLifeTime_s / drainedBatteryLoad_rel;
var remainingLifetime_s = estimatedLifeTime_s - status.ExceededLifeTime_s;
status.RemainingLifeTimeYears = remainingLifetime_s * YEARS_PER_SECONDS;
status.FwCalculatedRemainingLifeTimeYears = status.FwCalculatedRemainingLifeTime_s * YEARS_PER_SECONDS;
// Calculate an alternative threshold for remaining battery load based on the quiescent current and a supplement
// for production purpose. Those values can be assigned in the Cordonel requirements.
@@ -94,6 +94,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
public static readonly String BatteryInitialLoad = "POWERMON_BatteryMilliAHrRating";
public static readonly String BatteryExceededSeconds = "POWERMON_TotalUsedSeconds";
public static readonly String StoreConfiguration = "POWERMON_StoreConfiguration";
public static readonly String RemainingSeconds = "POWERMON_RemainingSeconds";
}
@@ -11,7 +11,6 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Logic.ProductionOrderCore.TestResults;
using Xylem.Common.Production.ProductionUiCordonel.Model;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericModules;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses;
@@ -78,6 +77,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
/// <remarks date="2025-Apr-06" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - Moved EOL creation to ExecPasswordFile.
/// </remarks>
public override StatusReturn PreExecuteProcess()
{
if (Meter == null || string.IsNullOrEmpty(Meter.PcbId) || Meter.PcbId.Length < GenesisMeter.MinPcbIdLength)
@@ -89,13 +91,13 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Some statistics for GUI and internal processing
SignalRunningState(MaxActualProgressSteps);
// Get new EOL progress from DB. All fields except the Id, StartDate of EOL and the PcbId are null!
if (!EOLHandler.GetNewEolProgress(Meter.PcbId, EolProgress, out var error))
{
Meter.WriteLog(error);
ErrorMsgDispatcher(Resources.StrErrorMsgCreateEolProgress);
return StatusReturn.Failed;
}
//// Get new EOL progress from DB. All fields except the Id, StartDate of EOL and the PcbId are null!
//if (!EOLHandler.GetNewEolProgress(Meter.PcbId, EolProgress, out var error))
//{
// Meter.WriteLog(error);
// ErrorMsgDispatcher(Resources.StrErrorMsgCreateEolProgress);
// return StatusReturn.Failed;
//}
// Exit if meanwhile cancellation is required
if (CancellationToken.IsCancellationRequested)
@@ -105,7 +107,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Get the requirement (Standard or special)
if (!GenesisStatusHandler.GetCordonelRequirementInfoFromDb(Meter.PcbId, ProductionRequirements,
out error) || ProductionRequirements == null)
out var error) || ProductionRequirements == null)
{
Meter.WriteLog(error);
ErrorMsgDispatcher(Resources.StrErrorMsgProductionRequirements);
@@ -104,16 +104,14 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
var stateContainer = new List<ProcessStateStruct>
{
#region ----------------------------------- GENERIC-STATES---------------------------------------------
// Detection of Cordonel has to be completed before assigning next state, so leave to automatic
// to change the state after successfully execution. The detection is the base for all others.
new ProcessStateStruct(
productionProcess: new DetectCordonel(Resources.StrStateDetectCordonel),
processState: ProcessState.DetectCordonel,
processInfo: Resources.StrStateDetectCordonel,
productionProcessNo: 0,
// CheckNewMeter will exit with repeated detect or connect
nextStateOnSuccess: ProcessState.CheckNewMeter),
// Precondition: - The detection process has to be completed as the PcbId is needed.
new ProcessStateStruct(
productionProcess: new ConnectCordonel(Resources.StrStateConnectCordonel),
processState: ProcessState.ConnectCordonel,
@@ -121,8 +119,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
productionProcessNo: 1,
nextStateOnSuccess: ProcessState.GetSerialNumberAndRadioAddress),
// Precondition: - The detection process has to be completed as the PcbId is needed.
// AVOID to change the process state on completion as parallel process is active!
new ProcessStateStruct(
productionProcess: new GetSerialNumberAndRadioAddress(Resources.StrStateGetSerialAndRadioAddress),
processState: ProcessState.GetSerialNumberAndRadioAddress,
@@ -133,10 +129,6 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Kick off parallel process execution
kickOffParallelState: ProcessState.GetProgrammingParameters),
// Precondition: - The connection process has to be completed as a readout of some register
// values from the Cordonel are needed to check the update capability:
// - Wait on completed connection process before starting this process.
// AVOID to change the process state on completion as parallel process is active!
new ProcessStateStruct(
productionProcess: new GetFinalParametrization(Resources.StrStateGetProgrammingParameters),
processState: ProcessState.GetProgrammingParameters,
@@ -145,29 +137,11 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
// Avoid automatic change after completion as parallel process is active
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
// Kick off parallel process execution
kickOffParallelState: ProcessState.CheckProductionState,
// Wait until this process has been successfully completed
waitForSingleProcess: ProcessState.ConnectCordonel),
kickOffParallelState: ProcessState.ProcessPasswordFile),
#endregion -------------------------------- GENERIC-STATES --------------------------------------------
#region ----------------------------------- EOL-STATES ------------------------------------------------
// Precondition: - The connection process has to be completed as a readout of some register
// values from the Cordonel are needed to check the update capability:
// - Wait on completed connection process before starting this process.
// AVOID to change the process state on completion as parallel process is active!
new ProcessStateStruct(
productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
processState: ProcessState.CheckProductionState,
processInfo: Resources.StrStateCheckProductionState,
productionProcessNo: 4,
// Avoid automatic change after completion as parallel process is active
nextStateOnSuccess: BaseProductionProcess.DoNotChangeStateAfterCompletion,
// Kick off parallel process execution
kickOffParallelState: ProcessState.ProcessPasswordFile,
// Wait until this process has been successfully completed
waitForSingleProcess: ProcessState.ConnectCordonel),
// Precondition: - The connection process has to be completed as a password change in the DB
// will take place: Skeleton to Password Level 8. Not waiting for completion may cause side
// effects on login. Wait for all processes to complete.
@@ -177,27 +151,32 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
productionProcess: new ExecPasswordFile(Resources.StrStatePasswordFile),
processState: ProcessState.ProcessPasswordFile,
processInfo: Resources.StrStatePasswordFile,
productionProcessNo: 5,
productionProcessNo: 4,
nextStateOnSuccess: ProcessState.ExecFinalParametrization,
// Wait for completion of all processes to avoid side effects
waitForAllProcesses: true),
// This writes all setups to the device, it has to be executed exclusively with automatic
new ProcessStateStruct(
new ProcessStateStruct(
productionProcess: new ExecFinalParametrization(Resources.StrStateFinalParametrization),
processState: ProcessState.ExecFinalParametrization,
processInfo: Resources.StrStateFinalParametrization,
productionProcessNo: 6,
productionProcessNo: 5,
nextStateOnSuccess: ProcessState.ExecStoreConfiguration),
// Precondition: - The final parametrization has to be finished as this shall be stored
// to non-volatile memory and checked if remaining valid after the reboot.
// Store configuration has to be executed exclusively with automatic
new ProcessStateStruct(
productionProcess: new ExecStoreConfiguration(Resources.StrStateStoreConfiguration),
processState: ProcessState.ExecStoreConfiguration,
processInfo: Resources.StrStateStoreConfiguration,
productionProcessNo: 7,
nextStateOnSuccess: ProcessState.RebootCordonel),
productionProcessNo: 6,
nextStateOnSuccess: ProcessState.CheckProductionState),
// Parametrization has to be completed as those needed to check e.g. the remaining FW based lifetime.
new ProcessStateStruct(
productionProcess: new CheckProductionState(Resources.StrStateCheckProductionState),
processState: ProcessState.CheckProductionState,
processInfo: Resources.StrStateCheckProductionState,
productionProcessNo: 7,
nextStateOnSuccess: ProcessState.RebootCordonel),
// Precondition: - The store configuration has to be executed to safe all settings
// to non-volatile memory and checked if remaining valid after the reboot.
@@ -8,6 +8,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Logic.ProductionOrderCore;
using Xylem.Common.Production.ProductionUiCordonel.Model;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
using Xylem.Common.Production.ProductionUiCordonel.Properties;
using Xylem.Common.Production.ProductionUiCordonel.UserControls;
@@ -89,8 +90,19 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr
/// <remarks date="2025-Apr-15" author="Thomas Wiedebusch">
/// - Retries for installation of password file.
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - Moved EOL creation from CHeckProductionState as this is the first entry for the configuration.
/// </remarks>
public override StatusReturn ExecuteProcess()
{
// Get new EOL progress from DB. All fields except the Id, StartDate of EOL and the PcbId are null!
if (!EOLHandler.GetNewEolProgress(Meter.PcbId, EolProgress, out var error))
{
Meter.WriteLog(error);
ErrorMsgDispatcher(Resources.StrErrorMsgCreateEolProgress);
return StatusReturn.Failed;
}
// Uncheck executed process to leave the result open needed for retries
EolProgress.PasswordFileInstalledCheck = null;
@@ -32,6 +32,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
/// <remarks date="2025-Mai-15" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - FW based calculation of remaining lifetime in years.
/// </remarks>
public static StatusReturn CheckRemainingLifetime(IGenesisMeter meter, CordonelRequirements productionRequirements,
GenesisStatus productionStatus, out String feedbackMsg, Boolean assemblyLine = false)
{
@@ -58,11 +61,22 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
var strStation = assemblyLine
? $"{productionRequirements.RequiredLifeTimeYearsAssembly:F2} "
: $"{productionRequirements.RequiredLifeTimeYearsShipping:F2} ";
// Take the FW based calculation into account
var strFwCalculatedLifeTimeYears = "";
if (productionStatus.FwCalculatedRemainingLifeTimeYears != null)
{
strFwCalculatedLifeTimeYears =
$@" - {Resources.StrMsgRemainingLifeTime}: " +
$"{productionStatus.FwCalculatedRemainingLifeTimeYears:F2} " +
$"{Resources.StrMsgYears} (Firmware)";
}
// Build message for required versus calculated lifetime
var lifeTime = $"{Resources.StrMsgRemainingLifeTime}: " +
// Actual calculated lifetime based on readings from meter
// Actual SW calculated lifetime based on readings from meter
$"{productionStatus.RemainingLifeTimeYears:F2} " +
$"{Resources.StrMsgYears}" +
$"{Resources.StrMsgYears} (Software)" +
// Optional FW calculation
strFwCalculatedLifeTimeYears +
$" - {Resources.StrMsgRequiredLifeTime}: " +
// Required lifetime from special or standard requirement
strStation +
@@ -72,7 +86,9 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
if ((assemblyLine &&
productionRequirements.RequiredLifeTimeYearsAssembly > productionStatus.RemainingLifeTimeYears) ||
(!assemblyLine &&
productionRequirements.RequiredLifeTimeYearsShipping > productionStatus.RemainingLifeTimeYears))
(productionRequirements.RequiredLifeTimeYearsShipping > productionStatus.RemainingLifeTimeYears ||
// internally in FW calculated remaining lifetime visual for customer in DIAVASO
productionRequirements.RequiredLifeTimeYearsShipping > productionStatus.FwCalculatedRemainingLifeTimeYears)))
{
feedbackMsg = $"{Resources.StrErrorMsg}: {lifeTime}";
return StatusReturn.Failed;
@@ -218,9 +234,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Gener
// Create an output message addon for alternative power consumption calculation
var strAlternativeCalc = productionStatus.AlternativeRequiredBatteryLoadPercent == null
? ""
: $" - {Resources.StrMsgRequirementAbsolutLimitDrainedBattery}: " + strStation +
$" ({Resources.StrMsgAlternativeDrainedBatteryCalculation})";
? "" : $" - {Resources.StrMsgRequirementAbsolutLimitDrainedBattery}: " + strStation ;
var strBatLoad = $"{Resources.StrMsgDrainedBattery}: " +
// Actual calculated battery load based on readings from meter
@@ -991,6 +991,9 @@ namespace Xylem.Common.Ui.GenesisToolBox
/// <remarks date="2025-Mar-15" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2025-Aug-11" author="Thomas Wiedebusch">
/// - Added FW based calculation of lifetime in years.
/// </remarks>
private Boolean BuildGenesisStatus(out String msg)
{
msg = "";
@@ -1017,6 +1020,8 @@ namespace Xylem.Common.Ui.GenesisToolBox
sbMSG.AppendLine("");
sbMSG.AppendLine($"Actual storage months: {genesisStatus.StorageMonths:F1}");
sbMSG.AppendLine($"Remaining life time in years: {genesisStatus.RemainingLifeTimeYears:F2}");
if (genesisStatus.FwCalculatedRemainingLifeTimeYears != null)
sbMSG.AppendLine($"Remaining life time in years (FW): {genesisStatus.FwCalculatedRemainingLifeTimeYears:F2}");
sbMSG.AppendLine($"Totally drained battery load in %: {genesisStatus.DrainedBatteryLoadPercent:F2}");
msg = sbMSG.ToString();