427 lines
20 KiB
C#
427 lines
20 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Data;
|
|||
|
|
using System.Data.SqlClient;
|
|||
|
|
using System.Globalization;
|
|||
|
|
using System.Linq;
|
|||
|
|
using DTS.Common.Enums;
|
|||
|
|
using DTS.Common.Interface.Sensors;
|
|||
|
|
using DTS.Common.Storage;
|
|||
|
|
using DTS.Common.Utilities.Logging;
|
|||
|
|
|
|||
|
|
namespace DTS.SensorDB
|
|||
|
|
{
|
|||
|
|
public class SensorCalibrationList
|
|||
|
|
{
|
|||
|
|
private static List<SensorCalibration> _cachedCalibrations = null;
|
|||
|
|
|
|||
|
|
public static void SetCachedCalibrations(SensorCalibration[] cachedCals)
|
|||
|
|
{
|
|||
|
|
_cachedCalibrations = null == cachedCals ? null : new List<SensorCalibration>(cachedCals);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void ClearCachedCalibrations()
|
|||
|
|
{
|
|||
|
|
_cachedCalibrations = null;
|
|||
|
|
_calibrationList?._calibrations?.Clear();
|
|||
|
|
}
|
|||
|
|
// I'm not sure we ever want to call this constructor? we probably always want to get all?
|
|||
|
|
//22287 Calibration error in Edit Test Setup when DataPRO is initiated and Sensors tab is not clicked first.
|
|||
|
|
//private SensorCalibrationList(string sensorSerialNumber)
|
|||
|
|
//{
|
|||
|
|
// _calibrations = new Dictionary<string, List<SensorCalibration>>();
|
|||
|
|
// var hr = DbOperations.SensorCalibrationsGet(null, sensorSerialNumber, out var records);
|
|||
|
|
// if( 0 == hr && null != records && records.Any())
|
|||
|
|
// {
|
|||
|
|
// foreach( var record in records)
|
|||
|
|
// {
|
|||
|
|
// var sc = new SensorCalibration(record);
|
|||
|
|
// if (!_calibrations.ContainsKey(sc.SerialNumber))
|
|||
|
|
// {
|
|||
|
|
// _calibrations.Add(sc.SerialNumber, new List<SensorCalibration>());
|
|||
|
|
// }
|
|||
|
|
// _calibrations[sc.SerialNumber].Add(sc);
|
|||
|
|
// }
|
|||
|
|
// }
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
protected SensorCalibrationList(ISensorCalDbRecord[] records)
|
|||
|
|
{
|
|||
|
|
_calibrations = new Dictionary<string, List<SensorCalibration>>();
|
|||
|
|
if (null != records && records.Any())
|
|||
|
|
{
|
|||
|
|
foreach (var record in records)
|
|||
|
|
{
|
|||
|
|
var sc = new SensorCalibration(record);
|
|||
|
|
if (!_calibrations.ContainsKey(sc.SerialNumber))
|
|||
|
|
{
|
|||
|
|
_calibrations.Add(sc.SerialNumber, new List<SensorCalibration>());
|
|||
|
|
}
|
|||
|
|
_calibrations[sc.SerialNumber].Add(sc);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private readonly Dictionary<string, List<SensorCalibration>> _calibrations;
|
|||
|
|
private static readonly object LOCK = new object();
|
|||
|
|
|
|||
|
|
private static SensorCalibrationList _calibrationList;
|
|||
|
|
public static void Reload()
|
|||
|
|
{
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void Reload(ISensorCalDbRecord[] records)
|
|||
|
|
{
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(records);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static ISensorCalDbRecord[] GetSensorCalibrationsFromDb()
|
|||
|
|
{
|
|||
|
|
var hr = DbOperations.SensorCalibrationsGet(null, null, out var records);
|
|||
|
|
if (hr == 0) { return records; }
|
|||
|
|
return new ISensorCalDbRecord[0];
|
|||
|
|
}
|
|||
|
|
public static SensorCalibration GetLatestCalibrationBySerialNumber(SensorData sd, ISensorCalDbRecord[] sensorCalDbRecords = null)
|
|||
|
|
{
|
|||
|
|
if (null == sd) { return null; }
|
|||
|
|
if (sd.IsDigitalInput() || sd.IsSquib() || sd.IsDigitalOutput()) { return SensorCalibration.NewDigitalSC(sd.IsDigitalInput() ? sd.DIUnits : "V"); }
|
|||
|
|
if (null != _cachedCalibrations)
|
|||
|
|
{
|
|||
|
|
var matches = from sc in _cachedCalibrations where sc.SerialNumber == sd.SerialNumber select sc;
|
|||
|
|
var sensorCalibrations = matches as SensorCalibration[] ?? matches.ToArray();
|
|||
|
|
if (sensorCalibrations.Any())
|
|||
|
|
{
|
|||
|
|
return ValidateAndGetSensorCalibrationFromCache(sensorCalibrations);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
AssignCalibrationListFromFb(ref sensorCalDbRecords);
|
|||
|
|
if (_calibrationList._calibrations.ContainsKey(sd.SerialNumber) && _calibrationList._calibrations[sd.SerialNumber].Count > 0)
|
|||
|
|
{
|
|||
|
|
return ValidateAndGetSensorCalibration(sd);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static SensorCalibration ValidateAndGetSensorCalibrationFromCache(SensorCalibration[] sensorCalibrations)
|
|||
|
|
{
|
|||
|
|
SensorCalibration cal = null;
|
|||
|
|
foreach (var sc in sensorCalibrations)
|
|||
|
|
{
|
|||
|
|
if (null == cal || cal.CalibrationDate < sc.CalibrationDate || cal.CalibrationDate == sc.CalibrationDate && cal.ModifyDate < sc.ModifyDate) { cal = sc; }
|
|||
|
|
}
|
|||
|
|
return cal;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void AssignCalibrationListFromFb(ref ISensorCalDbRecord[] sensorCalDbRecords)
|
|||
|
|
{
|
|||
|
|
if ((null == _calibrationList) || (_calibrationList._calibrations == null) || (!_calibrationList._calibrations.Any()))
|
|||
|
|
{
|
|||
|
|
if (sensorCalDbRecords == null)
|
|||
|
|
{
|
|||
|
|
sensorCalDbRecords = GetSensorCalibrationsFromDb();
|
|||
|
|
}
|
|||
|
|
_calibrationList = new SensorCalibrationList(sensorCalDbRecords);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static SensorCalibration ValidateAndGetSensorCalibration(SensorData sd)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var item = _calibrationList._calibrations[sd.SerialNumber].Aggregate((i1, i2) =>
|
|||
|
|
{
|
|||
|
|
if (i1.CalibrationDate > i2.CalibrationDate)
|
|||
|
|
{
|
|||
|
|
return i1;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return i1.CalibrationDate == i2.CalibrationDate && i1.ModifyDate > i2.ModifyDate ? i1 : i2;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return new SensorCalibration(item);//for safety reasons, don't return the original
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
APILogger.Log(ex);
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static SensorCalibration NewEmbeddedSC(string units)
|
|||
|
|
{
|
|||
|
|
return SensorCalibration.NewEmbeddedSC(units);
|
|||
|
|
}
|
|||
|
|
public static SensorCalibration GetLatestCalibrationBySerialNumberAndExcitation(SensorData sd, ExcitationVoltageOptions.ExcitationVoltageOption exc)
|
|||
|
|
{
|
|||
|
|
if (null == sd) { return null; }
|
|||
|
|
if (sd.IsDigitalInput() || sd.IsSquib() || sd.IsDigitalOutput()) { return SensorCalibration.NewDigitalSC(sd.IsDigitalInput() ? sd.DIUnits : "V"); }
|
|||
|
|
if (sd.IsTestSpecificEmbedded) { return SensorCalibration.NewEmbeddedSC(sd.Calibration?.EngineeringUnits ?? "V"); } //TODO: REMOVE THIS HACK when we have proper get cal functions
|
|||
|
|
if (sd.IsTestSpecificThermo) { return SensorCalibration.NewEmbeddedSC(sd.Calibration?.EngineeringUnits ?? "C"); }
|
|||
|
|
if (null != _cachedCalibrations && _cachedCalibrations.Any())
|
|||
|
|
{
|
|||
|
|
var matches = from sc in _cachedCalibrations where sc.SerialNumber == sd.SerialNumber select sc;
|
|||
|
|
var sensorCalibrations = matches as SensorCalibration[] ?? matches.ToArray();
|
|||
|
|
if (sensorCalibrations.Any())
|
|||
|
|
{
|
|||
|
|
SensorCalibration cal = null;
|
|||
|
|
|
|||
|
|
foreach (var sc in sensorCalibrations)
|
|||
|
|
{
|
|||
|
|
if (sc.IsProportional)
|
|||
|
|
{
|
|||
|
|
var bOk = Array.Exists(sc.Records.Records, record => record.Excitation == exc);
|
|||
|
|
|
|||
|
|
if (!bOk) { continue; }
|
|||
|
|
}
|
|||
|
|
if (null == cal) { cal = sc; }
|
|||
|
|
else if (sc.CalibrationDate > cal.CalibrationDate) { cal = sc; }
|
|||
|
|
else if (sc.CalibrationDate == cal.CalibrationDate && sc.ModifyDate > cal.ModifyDate)
|
|||
|
|
{
|
|||
|
|
cal = sc;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (null != cal) { return cal; }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList || 0 == _calibrationList._calibrations.Count)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(sd.SerialNumber) || _calibrationList._calibrations[sd.SerialNumber].Count <= 0) return null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var list = _calibrationList._calibrations[sd.SerialNumber];
|
|||
|
|
list.Sort();
|
|||
|
|
foreach (var sc in list)
|
|||
|
|
{
|
|||
|
|
if (!sc.IsProportional) { return new SensorCalibration(sc); }
|
|||
|
|
if (Array.Exists(sc.Records.Records, record => record.Excitation == exc))
|
|||
|
|
{
|
|||
|
|
return new SensorCalibration(sc);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
public static SensorCalibration GetLatestCalibrationsBySerialNumberAndCalDate(string ser, DateTime calDate)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(ser) || _calibrationList._calibrations[ser].Count <= 0)
|
|||
|
|
return null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var list = new List<SensorCalibration>(_calibrationList._calibrations[ser]);
|
|||
|
|
|
|||
|
|
for (var i = list.Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
if (list[i].CalibrationDate != calDate) { list.RemoveAt(i); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (list.Count <= 0) return null;
|
|||
|
|
list.Sort();
|
|||
|
|
return new SensorCalibration(list[0]);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
public static SensorCalibration GetLatestCalibrationsBySerialNumberCalDateAndModifyDate(string ser, DateTime calDate, DateTime modifyDate)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
if (_calibrationList._calibrations.ContainsKey(ser) && _calibrationList._calibrations[ser].Count > 0)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var list = new List<SensorCalibration>(_calibrationList._calibrations[ser]);
|
|||
|
|
|
|||
|
|
for (var i = list.Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
if (list[i].CalibrationDate != calDate)
|
|||
|
|
{
|
|||
|
|
list.RemoveAt(i);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//12488 Import Test Setup adds new sensor calibration entries every time
|
|||
|
|
//note that modify date as datetime can have more deviation than cal dates, which are just date
|
|||
|
|
//so we have to consider the minimum varation between time, which I set to 1 second here
|
|||
|
|
var delta = list[i].ModifyDate.Subtract(modifyDate);
|
|||
|
|
if (Math.Abs(delta.TotalSeconds) >= 1)
|
|||
|
|
{
|
|||
|
|
list.RemoveAt(i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (list.Count <= 0) return null;
|
|||
|
|
list.Sort();
|
|||
|
|
return new SensorCalibration(list[0]);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log(ex); }
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
public static SensorCalibration[] GetCalibrationsBySerialNumber(SensorData sd)
|
|||
|
|
{
|
|||
|
|
if (null == sd) { return new SensorCalibration[0]; }
|
|||
|
|
if (sd.IsDigitalInput() || sd.IsSquib() || sd.IsDigitalOutput()) { return new[] { SensorCalibration.NewDigitalSC(sd.IsDigitalInput() ? sd.DIUnits : "V") }; }
|
|||
|
|
|
|||
|
|
if (null != _cachedCalibrations)
|
|||
|
|
{
|
|||
|
|
var matches = from sc in _cachedCalibrations where sd.SerialNumber == sc.SerialNumber select sc;
|
|||
|
|
var sensorCalibrations = matches as SensorCalibration[] ?? matches.ToArray();
|
|||
|
|
if (sensorCalibrations.Any())
|
|||
|
|
{
|
|||
|
|
return sensorCalibrations.ToArray();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList || 0 == _calibrationList._calibrations.Count)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(sd.SerialNumber)) return new SensorCalibration[0];
|
|||
|
|
var list = new List<SensorCalibration>(_calibrationList._calibrations[sd.SerialNumber].Count);
|
|||
|
|
list.AddRange(_calibrationList._calibrations[sd.SerialNumber].Select(sc => new SensorCalibration(sc)));
|
|||
|
|
return list.ToArray();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// commits a sensor to the db
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="sc"></param>
|
|||
|
|
/// <param name="bChangeModifyDate"></param>
|
|||
|
|
/// <param name="sd"></param>
|
|||
|
|
/// <param name="bSetLatestCalId">whether to set the calibration id on the sensor to the sensor calibration when the calibration is committed</param>
|
|||
|
|
public static void Commit(SensorCalibration sc, bool bChangeModifyDate, SensorData sd, bool bSetLatestCalId = false)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (sd.IsDigitalInput() || sd.IsDigitalOutput() || sd.IsSquib()
|
|||
|
|
|| sd.IsStreamOutput() || sd.IsStreamInput() || sd.IsUart()) { return; }
|
|||
|
|
if (null == sc) { return; }
|
|||
|
|
|
|||
|
|
SensorCalibration scExisting = null;
|
|||
|
|
if (!bChangeModifyDate) { scExisting = GetLatestCalibrationsBySerialNumberCalDateAndModifyDate(sc.SerialNumber, sc.CalibrationDate, sc.ModifyDate); }
|
|||
|
|
|
|||
|
|
if (null != scExisting && sc.Equals(scExisting)) { return; }//no update needed
|
|||
|
|
|
|||
|
|
if (string.IsNullOrEmpty(sc.SerialNumber)) { return; }//don't commit a calibration without a serialnumber
|
|||
|
|
|
|||
|
|
//correct units capitalization if needed
|
|||
|
|
foreach (var record in sc.Records.Records)
|
|||
|
|
{
|
|||
|
|
var units = MeasurementUnitList.GetMeasurementUnit(record.EngineeringUnits);
|
|||
|
|
if (null != units && units.MainDisplayUnit != record.EngineeringUnits) { record.EngineeringUnits = units.MainDisplayUnit; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sc.Username = string.Empty;
|
|||
|
|
if (null != DbOperations.CurrentUserDbRecord) { sc.Username = DbOperations.CurrentUserDbRecord.UserName; }
|
|||
|
|
sc.Insert(bChangeModifyDate, sd, bSetLatestCalId);
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(sc.SerialNumber)) { _calibrationList._calibrations.Add(sc.SerialNumber, new List<SensorCalibration>()); }
|
|||
|
|
_calibrationList._calibrations[sc.SerialNumber].Add(new SensorCalibration(sc));
|
|||
|
|
}
|
|||
|
|
// ReSharper disable once PossibleNullReferenceException
|
|||
|
|
catch (Exception ex) { APILogger.Log("Failed to write sensor calibration", sc.SerialNumber, ex); }
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// deletes all calibration data
|
|||
|
|
/// originally created so TDM imports could clear all tables except DAS tables
|
|||
|
|
/// </summary>
|
|||
|
|
public static void DeleteAll()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hr = DbOperations.SensorCalibrationsDelete(null, null, null);
|
|||
|
|
if (0 != hr) { return; }
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
_calibrationList._calibrations.Clear();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log("Failed to delete sensor calibrations ", ex); }
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// Deletes Calibration records from the database and Calibration List dictionary that match the serialNumber param
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="serialNumber"></param>
|
|||
|
|
public static void DeleteCalsBySerialNumber(string serialNumber)
|
|||
|
|
{
|
|||
|
|
// 6853 - Sensitivities are lost when importing SLICEWare sensors.
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hr = DbOperations.SensorCalibrationsDelete(serialNumber, null, null);
|
|||
|
|
if (0 != hr)
|
|||
|
|
{
|
|||
|
|
APILogger.Log("Failed to delete sensor calibration ", serialNumber, hr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList) { _calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb()); }
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(serialNumber)) return;
|
|||
|
|
for (var i = _calibrationList._calibrations[serialNumber].Count - 1; i >= 0; i--) { _calibrationList._calibrations[serialNumber].RemoveAt(i); }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log("Failed to delete sensor calibration ", serialNumber, ex); }
|
|||
|
|
}
|
|||
|
|
public static void Delete(SensorCalibration sc)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var hr = DbOperations.SensorCalibrationsDelete(sc.SerialNumber, sc.CalibrationDate.Date, sc.ModifyDate);
|
|||
|
|
if (0 != hr)
|
|||
|
|
{
|
|||
|
|
APILogger.Log("Failed to delete sensor calibration ", sc.SerialNumber, sc.CalibrationDate.ToShortDateString(), sc.ModifyDate.ToString(CultureInfo.InvariantCulture), hr);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lock (LOCK)
|
|||
|
|
{
|
|||
|
|
if (null == _calibrationList)
|
|||
|
|
{
|
|||
|
|
_calibrationList = new SensorCalibrationList(GetSensorCalibrationsFromDb());
|
|||
|
|
}
|
|||
|
|
if (!_calibrationList._calibrations.ContainsKey(sc.SerialNumber)) return;
|
|||
|
|
for (var i = _calibrationList._calibrations[sc.SerialNumber].Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
if (_calibrationList._calibrations[sc.SerialNumber][i].CalibrationDate != sc.CalibrationDate ||
|
|||
|
|
_calibrationList._calibrations[sc.SerialNumber][i].ModifyDate != sc.ModifyDate) continue;
|
|||
|
|
_calibrationList._calibrations[sc.SerialNumber].RemoveAt(i);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex) { APILogger.Log("Failed to delete sensor calibration ", sc.SerialNumber, sc.CalibrationDate.ToShortDateString(), sc.ModifyDate.ToString(CultureInfo.InvariantCulture), ex); }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|