Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CTs are ICurrentSensors #1103

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,157 +1,157 @@
using Meadow.Hardware;
using Meadow.Peripherals.Sensors;
using Meadow.Units;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Power
namespace Meadow.Foundation.Sensors.Power;

/// <summary>
/// Represents a general Current Transducer (CT) sensor
/// </summary>
public partial class CurrentTransducer : SamplingSensorBase<Current>, ICurrentSensor
{
/// <summary>
/// Represents a general Current Transducer (CT) sensor
/// The analog input port connected to the transducer
/// </summary>
protected IAnalogInputPort AnalogPort { get; private set; } = default!;

/// <summary>
/// The maximum voltage the CT outputs
/// </summary>
protected Voltage MaxVoltage { get; private set; } = default!;

/// <summary>
/// The sensed current at the maximum output voltage
/// </summary>
protected Current MaxCurrent { get; private set; } = default!;

/// <summary>
/// The minimum voltage the CT outputs
/// </summary>
protected Voltage MinVoltage { get; private set; } = default!;

/// <summary>
/// The sensed current at the minimum output voltage
/// </summary>
public partial class CurrentTransducer : SamplingSensorBase<Current>
protected Current MinCurrent { get; private set; } = default!;

/// <summary>
/// The minimum output voltage
/// </summary>
protected Current MinVoltageDelta { get; private set; } = default!;

/// <summary>
/// The last sensed Current
/// </summary>
public Current? Current { get; protected set; }

/// <summary>
/// Creates a new CurrentTransducer instance
/// </summary>
/// <param name="analogPort">The analog input port connected to the transducer</param>
/// <param name="maxVoltage">The maximum voltage the CT outputs</param>
/// <param name="maxCurrent">The sensed current at the maximum output voltage</param>
/// <param name="minVoltage">The minimum voltage the CT outputs</param>
/// <param name="minCurrent">The sensed current at the minimum output voltage</param>
public CurrentTransducer(IAnalogInputPort analogPort, Voltage maxVoltage, Current maxCurrent, Voltage? minVoltage = null, Current? minCurrent = null)
{
/// <summary>
/// The analog input port connected to the transducer
/// </summary>
protected IAnalogInputPort AnalogPort { get; private set; } = default!;

/// <summary>
/// The maximum voltage the CT outputs
/// </summary>
protected Voltage MaxVoltage { get; private set; } = default!;

/// <summary>
/// The sensed current at the maximum output voltage
/// </summary>
protected Current MaxCurrent { get; private set; } = default!;

/// <summary>
/// The minimum voltage the CT outputs
/// </summary>
protected Voltage MinVoltage { get; private set; } = default!;

/// <summary>
/// The sensed current at the minimum output voltage
/// </summary>
protected Current MinCurrent { get; private set; } = default!;

/// <summary>
/// The minimum output voltage
/// </summary>
protected Current MinVoltageDelta { get; private set; } = default!;

/// <summary>
/// The last sensed Current
/// </summary>
public Current? Current { get; protected set; }

/// <summary>
/// Creates a new CurrentTransducer instance
/// </summary>
/// <param name="analogPort">The analog input port connected to the transducer</param>
/// <param name="maxVoltage">The maximum voltage the CT outputs</param>
/// <param name="maxCurrent">The sensed current at the maximum output voltage</param>
/// <param name="minVoltage">The minimum voltage the CT outputs</param>
/// <param name="minCurrent">The sensed current at the minimum output voltage</param>
public CurrentTransducer(IAnalogInputPort analogPort, Voltage maxVoltage, Current maxCurrent, Voltage? minVoltage = null, Current? minCurrent = null)
{
Initialize(analogPort, maxVoltage, maxCurrent, minVoltage, minCurrent);
}
Initialize(analogPort, maxVoltage, maxCurrent, minVoltage, minCurrent);
}

/// <summary>
/// Creates a new CurrentTransducer instance
/// </summary>
protected CurrentTransducer()
{
}
/// <summary>
/// Creates a new CurrentTransducer instance
/// </summary>
protected CurrentTransducer()
{
}

/// <summary>
/// Initializes the CurrentTransducer instance
/// Use this method when a derived class must do pre-initialization work
/// </summary>
/// <param name="analogPort">The analog input port connected to the transducer</param>
/// <param name="maxVoltage">The maximum voltage the CT outputs</param>
/// <param name="maxCurrent">The sensed current at the maximum output voltage</param>
/// <param name="minVoltage">The minimum voltage the CT outputs</param>
/// <param name="minCurrent">The sensed current at the minimum output voltage</param>
protected virtual void Initialize(IAnalogInputPort analogPort, Voltage maxVoltage, Current maxCurrent, Voltage? minVoltage = null, Current? minCurrent = null)
{
AnalogPort = analogPort;
MaxVoltage = maxVoltage;
MaxCurrent = maxCurrent;
MinVoltage = minVoltage ?? new Voltage(0, Voltage.UnitType.Volts);
MinCurrent = minCurrent ?? new Current(0, Units.Current.UnitType.Amps);

AnalogPort.Subscribe
(
IAnalogInputPort.CreateObserver(
result =>
/// <summary>
/// Initializes the CurrentTransducer instance
/// Use this method when a derived class must do pre-initialization work
/// </summary>
/// <param name="analogPort">The analog input port connected to the transducer</param>
/// <param name="maxVoltage">The maximum voltage the CT outputs</param>
/// <param name="maxCurrent">The sensed current at the maximum output voltage</param>
/// <param name="minVoltage">The minimum voltage the CT outputs</param>
/// <param name="minCurrent">The sensed current at the minimum output voltage</param>
protected virtual void Initialize(IAnalogInputPort analogPort, Voltage maxVoltage, Current maxCurrent, Voltage? minVoltage = null, Current? minCurrent = null)
{
AnalogPort = analogPort;
MaxVoltage = maxVoltage;
MaxCurrent = maxCurrent;
MinVoltage = minVoltage ?? new Voltage(0, Voltage.UnitType.Volts);
MinCurrent = minCurrent ?? new Current(0, Units.Current.UnitType.Amps);

AnalogPort.Subscribe
(
IAnalogInputPort.CreateObserver(
result =>
{
ChangeResult<Current> changeResult = new()
{
ChangeResult<Current> changeResult = new()
{
New = ConvertVoltageToCurrent(result.New),
Old = Current
};
Current = changeResult.New;
RaiseEventsAndNotify(changeResult);
}
)
);
}
New = ConvertVoltageToCurrent(result.New),
Old = Current
};
Current = changeResult.New;
RaiseEventsAndNotify(changeResult);
}
)
);
}

/// <summary>
/// Converts an output voltage from the CT to a sensed current using linear interpolation
/// </summary>
/// <param name="voltage">The ADC voltage read by the AnalogPort</param>
/// <returns>The current being sensed by the CT</returns>
protected virtual Current ConvertVoltageToCurrent(Voltage voltage)
{
// the default implementation just does a simple linear conversion
return new Current(
(MaxCurrent.Amps - MinCurrent.Amps) /
(MaxVoltage.Volts - MinVoltage.Volts)
* voltage.Volts);
}
/// <summary>
/// Converts an output voltage from the CT to a sensed current using linear interpolation
/// </summary>
/// <param name="voltage">The ADC voltage read by the AnalogPort</param>
/// <returns>The current being sensed by the CT</returns>
protected virtual Current ConvertVoltageToCurrent(Voltage voltage)
{
// the default implementation just does a simple linear conversion
return new Current(
(MaxCurrent.Amps - MinCurrent.Amps) /
(MaxVoltage.Volts - MinVoltage.Volts)
* voltage.Volts);
}

///<inheritdoc/>
protected override async Task<Current> ReadSensor()
{
var adc = await AnalogPort.Read();
var newCurrent = ConvertVoltageToCurrent(adc);
Current = newCurrent;
return newCurrent;
}
///<inheritdoc/>
protected override async Task<Current> ReadSensor()
{
var adc = await AnalogPort.Read();
var newCurrent = ConvertVoltageToCurrent(adc);
Current = newCurrent;
return newCurrent;
}

///<inheritdoc/>
public override void StartUpdating(TimeSpan? updateInterval = null)
///<inheritdoc/>
public override void StartUpdating(TimeSpan? updateInterval = null)
{
lock (samplingLock)
{
lock (samplingLock)
{
if (IsSampling) return;
IsSampling = true;
if (IsSampling) return;
IsSampling = true;

base.SamplingTokenSource = new CancellationTokenSource();
CancellationToken ct = SamplingTokenSource.Token;
base.SamplingTokenSource = new CancellationTokenSource();
CancellationToken ct = SamplingTokenSource.Token;

AnalogPort.StartUpdating(updateInterval);
}
AnalogPort.StartUpdating(updateInterval);
}
}

///<inheritdoc/>
public override void StopUpdating()
///<inheritdoc/>
public override void StopUpdating()
{
lock (samplingLock)
{
lock (samplingLock)
{
if (!IsSampling) return;
if (!IsSampling) return;

AnalogPort.StopUpdating();
AnalogPort.StopUpdating();

SamplingTokenSource?.Cancel();
SamplingTokenSource?.Cancel();

// state machine
IsSampling = false;
}
// state machine
IsSampling = false;
}
}
}
Loading