diff --git a/Source/Meadow.Foundation.Core/Sensors/Potentiometer/Potentiometer.cs b/Source/Meadow.Foundation.Core/Sensors/Potentiometer/Potentiometer.cs index 351dcd2f9..3a42b78f9 100644 --- a/Source/Meadow.Foundation.Core/Sensors/Potentiometer/Potentiometer.cs +++ b/Source/Meadow.Foundation.Core/Sensors/Potentiometer/Potentiometer.cs @@ -10,9 +10,13 @@ namespace Meadow.Foundation.Sensors; /// public class Potentiometer : IPotentiometer, IDisposable { + /// + public event EventHandler>? Changed; + private IAnalogInputPort inputPort; private Voltage referenceVoltage; private bool portCreated = false; + private Resistance? oldValue; /// /// Gets whether this instance has been disposed. @@ -22,7 +26,7 @@ public class Potentiometer : IPotentiometer, IDisposable /// /// Gets the maximum resistance value of the potentiometer. /// - public Resistance MaxResistance { get; } + public Resistance MaxResistance { get; private set; } /// /// Initializes a new instance of the Potentiometer class with default reference voltage. @@ -31,9 +35,8 @@ public class Potentiometer : IPotentiometer, IDisposable /// The maximum resistance value of the potentiometer. public Potentiometer(IAnalogInputPort inputPort, Resistance maxResistance) { - this.inputPort = inputPort; - MaxResistance = maxResistance; - referenceVoltage = inputPort.ReferenceVoltage; + Initialize(inputPort, maxResistance, inputPort.ReferenceVoltage); + portCreated = false; } /// @@ -63,6 +66,22 @@ public Potentiometer(IPin inputPin, Resistance maxResistance, Voltage referenceV portCreated = true; } + private void Initialize(IAnalogInputPort inputPort, Resistance maxResistance, Voltage refereceVoltage) + { + this.inputPort = inputPort; + MaxResistance = maxResistance; + referenceVoltage = inputPort.ReferenceVoltage; + + inputPort.Updated += OnInputPortUpdated; + } + + private void OnInputPortUpdated(object sender, IChangeResult e) + { + var newValue = new Resistance(MaxResistance.Ohms * e.New.Volts / referenceVoltage.Volts); + Changed?.Invoke(this, new ChangeResult(newValue, oldValue)); + oldValue = newValue; + } + /// /// Gets the current resistance value of the potentiometer by reading the analog input. /// Setting the resistance throws NotSupportedException as potentiometer value can only be changed mechanically. diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedAnalogInputPort.cs b/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedAnalogInputPort.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedAnalogInputPort.cs rename to Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedAnalogInputPort.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs b/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs new file mode 100644 index 000000000..ac4d23a8e --- /dev/null +++ b/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalOutputPort.cs @@ -0,0 +1,34 @@ +using Meadow.Hardware; + +namespace Meadow.Foundation.Sensors; + +public class SimulatedDigitalOutputPort : IDigitalOutputPort +{ + private bool state; + + public bool InitialState { get; } + public string Name { get; } + + public SimulatedDigitalOutputPort(string name, bool initialState) + { + Name = name; + InitialState = state = initialState; + } + + public virtual bool State + { + get => state; + set + { + state = value; + Resolver.Log.Info($"Output {Name} = {State}"); + } + } + + public IDigitalChannelInfo? Channel => null; + public IPin? Pin => null; + + public void Dispose() + { + } +} diff --git a/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalSignalAnalyzer.cs b/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalSignalAnalyzer.cs new file mode 100644 index 000000000..725898d88 --- /dev/null +++ b/Source/Meadow.Foundation.Core/Simulation/Ports/SimulatedDigitalSignalAnalyzer.cs @@ -0,0 +1,51 @@ +using Meadow.Hardware; +using Meadow.Units; + +namespace Meadow.Foundation.Sensors; + +public class SimulatedDigitalSignalAnalyzer : IDigitalSignalAnalyzer +{ + private Frequency frequency; + private double dutyCycle = 0.5; + private ulong count; + + public SimulatedDigitalSignalAnalyzer(Frequency frequency) + { + this.frequency = frequency; + } + + public void SetDutyCycle(double dutyCycle) + { + this.dutyCycle = dutyCycle; + } + + public double GetDutyCycle() + { + return dutyCycle; + } + + public void SetFrequency(Frequency frequency) + { + this.frequency = frequency; + } + + public Frequency GetFrequency() + { + return frequency; + } + + public Frequency GetMeanFrequency() + { + return frequency; + } + + public void SetCount(ulong count) + { + this.count = count; + } + + public ulong GetCount() + { + return count; + } +} diff --git a/Source/Meadow.Foundation.Core/Simulation/BaseSimulatedSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/BaseSimulatedSensor.cs similarity index 89% rename from Source/Meadow.Foundation.Core/Simulation/BaseSimulatedSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/BaseSimulatedSensor.cs index 2821f1e98..7a2e64c85 100644 --- a/Source/Meadow.Foundation.Core/Simulation/BaseSimulatedSensor.cs +++ b/Source/Meadow.Foundation.Core/Simulation/Sensors/BaseSimulatedSensor.cs @@ -6,36 +6,6 @@ namespace Meadow.Foundation.Sensors; -/* -/// -/// Represents a simulated tone generator that implements both IToneGenerator and ISimulatedSensor interfaces. -/// -public class SimulatedToneGenerator : IToneGenerator, ISimulatedSensor -{ -} - -/// -/// Represents a simulated RgbPwmLed that implements both IRgbPwmLed and ISimulatedSensor interfaces. -/// -public class SimulatedRgbPwmLed : IRgbPwmLed, ISimulatedSensor -{ -} - -/// -/// Represents a simulated barometric pressure sensor that implements both IBarometricPressureSensor and ISimulatedSensor interfaces. -/// -public class SimulatedBarometricPressureSensor : IBarometricPressureSensor, ISimulatedSensor -{ -} - -/// -/// Represents a simulated gas resistance sensor that implements both IGasResistanceSensor and ISimulatedSensor interfaces. -/// -public class SimulatedGasResistanceSensor : IGasResistanceSensor, ISimulatedSensor -{ -} -*/ - /// /// A base class for simple simulated single-unit sensors /// diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulateBarometricPressureSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulateBarometricPressureSensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulateBarometricPressureSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulateBarometricPressureSensor.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedAccelerometer.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedAccelerometer.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedAccelerometer.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedAccelerometer.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedCurrentSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedCurrentSensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedCurrentSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedCurrentSensor.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedHallEffectFlowSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedHallEffectFlowSensor.cs new file mode 100644 index 000000000..5494ece88 --- /dev/null +++ b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedHallEffectFlowSensor.cs @@ -0,0 +1,31 @@ +using Meadow.Peripherals.Sensors; +using Meadow.Units; +using System.Threading.Tasks; + +namespace Meadow.Foundation.Sensors; + +public class SimulatedHallEffectFlowSensor : IVolumetricFlowSensor +{ + private SimulatedDigitalSignalAnalyzer _analyzer; + private double _flowCoefficient; + + public SimulatedHallEffectFlowSensor(Frequency simulatedPulseFrequency, double flowCoefficient = 80d) + { + _flowCoefficient = flowCoefficient; + _analyzer = new SimulatedDigitalSignalAnalyzer(simulatedPulseFrequency); + } + + public void SetSignalFrequency(Frequency frequency) + { + _analyzer.SetFrequency(frequency); + } + + public VolumetricFlow Flow => new VolumetricFlow( + _analyzer.GetFrequency().Hertz / _flowCoefficient, + VolumetricFlow.UnitType.LitersPerMinute); + + public Task Read() + { + return Task.FromResult(Flow); + } +} diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedHumiditySensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedHumiditySensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedHumiditySensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedHumiditySensor.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedLightSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedLightSensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedLightSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedLightSensor.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedMoistureSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedMoistureSensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedMoistureSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedMoistureSensor.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedRangeFinder.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedRangeFinder.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedRangeFinder.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedRangeFinder.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedRelay.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedRelay.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedRelay.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedRelay.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedSamplingSensorBase.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedSamplingSensorBase.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedSamplingSensorBase.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedSamplingSensorBase.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedSensorBase.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedSensorBase.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedSensorBase.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedSensorBase.cs diff --git a/Source/Meadow.Foundation.Core/Simulation/SimulatedTemperatureSensor.cs b/Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedTemperatureSensor.cs similarity index 100% rename from Source/Meadow.Foundation.Core/Simulation/SimulatedTemperatureSensor.cs rename to Source/Meadow.Foundation.Core/Simulation/Sensors/SimulatedTemperatureSensor.cs diff --git a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroLayout/Driver/Controls/ListBox.cs b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroLayout/Driver/Controls/ListBox.cs index 853e6bff5..cca0ef8f5 100644 --- a/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroLayout/Driver/Controls/ListBox.cs +++ b/Source/Meadow.Foundation.Libraries_and_Frameworks/Graphics.MicroLayout/Driver/Controls/ListBox.cs @@ -27,6 +27,12 @@ public class ListBox : MicroLayout /// Spacing, in pixels, between items /// public int ItemSpacing { get; } = 1; + + /// + /// Spacing, in pixels, between the control left and the left of each item + /// + public int ItemLeftMargin { get; set; } = 2; + /// /// Items to display in the ListBox /// @@ -53,11 +59,11 @@ public ListBox(int left, int top, int width, int height, IFont font) private void CreateRowLabels(int rowCount) { - var y = 0; + var y = 2; for (var i = 0; i < rowCount; i++) { Controls.Add( - new Label(Left, Top + y, this.Width, _rowHeight) + new Label(ItemLeftMargin, y, this.Width, _rowHeight) { Font = _font, TextColor = TextColor, @@ -182,6 +188,7 @@ private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEven switch (e.Action) { case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Replace: // is the added item visible? if (e.NewStartingIndex < TopIndex + Controls.Count) { diff --git a/Source/Meadow.Foundation.Peripherals/ICs.DigiPots.Mcp4xxx/Driver/Mcp4xxx.ResistorArray.cs b/Source/Meadow.Foundation.Peripherals/ICs.DigiPots.Mcp4xxx/Driver/Mcp4xxx.ResistorArray.cs index 98d0e8f87..a93008ca0 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.DigiPots.Mcp4xxx/Driver/Mcp4xxx.ResistorArray.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.DigiPots.Mcp4xxx/Driver/Mcp4xxx.ResistorArray.cs @@ -1,6 +1,8 @@ using Meadow.Hardware; using Meadow.Units; using System; +using System.Threading; +using System.Threading.Tasks; namespace Meadow.Foundation.ICs.DigiPots; @@ -20,6 +22,9 @@ public class ResistorArray : IPotentiometer, IRheostat private Mcp4xxx _parent; private int _index; private ISpiCommunications _spiComms; + private EventHandler>? _changedEvent; + private Timer? _pollTimer; + private Resistance? _lastValue; /// public Resistance MaxResistance => _parent.MaxResistance; @@ -39,6 +44,35 @@ public Resistance Resistance } } + /// + public event EventHandler>? Changed + { + remove + { + _changedEvent -= value; + + if (_changedEvent?.GetInvocationList().Length == 0) + { + _pollTimer?.Dispose(); + _pollTimer = null; + } + } + add + { + _changedEvent += value; + if (_pollTimer == null) + { + _pollTimer = new Timer(async (_) => + { + var r = Resistance; + _changedEvent?.Invoke(this, new ChangeResult(r, _lastValue)); + _lastValue = r; + await Task.Delay(500); + }); + } + } + } + internal ResistorArray(Mcp4xxx parent, int index, ISpiCommunications spiComms) { if (index is < 0 or > 1) throw new ArgumentException(); diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Mcp23xxx/Driver/Mcp23xxx.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Mcp23xxx/Driver/Mcp23xxx.cs index 4a5f74eca..9386959c6 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Mcp23xxx/Driver/Mcp23xxx.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Mcp23xxx/Driver/Mcp23xxx.cs @@ -643,5 +643,11 @@ private PortBank GetPortBankForPin(IPin pin) } return PortBank.A; } + + /// + public IDigitalSignalAnalyzer CreateDigitalSignalAnalyzer(IPin pin, bool captureDutyCycle) + { + return new SoftDigitalSignalAnalyzer(pin, captureDutyCycle: captureDutyCycle); + } } } \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Pcx857x/Driver/Pcx857x.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Pcx857x/Driver/Pcx857x.cs index 75a4603d2..7099bb077 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Pcx857x/Driver/Pcx857x.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.Pcx857x/Driver/Pcx857x.cs @@ -286,7 +286,7 @@ public void AllOn() /// True to set the pin state high, False to set it low protected abstract void SetPinState(IPin pin, bool state); - void WriteUint16(ushort value) + private void WriteUint16(ushort value) { Span buffer = stackalloc byte[2]; buffer[0] = (byte)value; @@ -313,6 +313,12 @@ private void InterruptPortChanged(object sender, DigitalPortResult e) } } + /// + public IDigitalSignalAnalyzer CreateDigitalSignalAnalyzer(IPin pin, bool captureDutyCycle) + { + return new SoftDigitalSignalAnalyzer(pin, captureDutyCycle: captureDutyCycle); + } + /// /// Dispose of the object /// diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr105.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr105.cs new file mode 100644 index 000000000..9833143ab --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr105.cs @@ -0,0 +1,22 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the GR-105 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 5.5 Hz per L/min +/// +public class Gr105 : HallEffectBase +{ + /// + /// Initializes a new instance of the GR-105 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public Gr105(IPin pin) + : base(pin, 5.5d) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr201.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr201.cs new file mode 100644 index 000000000..01e0af51b --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr201.cs @@ -0,0 +1,22 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the GR-201 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 7.5 Hz per L/min +/// +public class Gr201 : HallEffectBase +{ + /// + /// Initializes a new instance of the GR-201 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public Gr201(IPin pin) + : base(pin, 7.5d) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr216.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr216.cs new file mode 100644 index 000000000..10413a93a --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/Gr216.cs @@ -0,0 +1,22 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the GR-216 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 0.2 Hz per L/min +/// +public class Gr216 : HallEffectBase +{ + /// + /// Initializes a new instance of the GR-216 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public Gr216(IPin pin) + : base(pin, 0.2d) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB1.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB1.cs new file mode 100644 index 000000000..2b3892e8c --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB1.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B1 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 11.0 Hz per L/min +/// - Offset: 0 Hz +/// +public class YfB1 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B9 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB1(IPin pin) + : base(pin, 11.0) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB10.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB10.cs new file mode 100644 index 000000000..fc97fee67 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB10.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B10 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 7.5 Hz per L/min +/// - Offset: 4 Hz +/// +public class YfB10 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B10 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB10(IPin pin) + : base(pin, 7.5, 4) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB2.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB2.cs new file mode 100644 index 000000000..7c8e8c46a --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB2.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B1 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 11.0 Hz per L/min +/// - Offset: 0 Hz +/// +public class YfB2 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B9 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB2(IPin pin) + : base(pin, 11.0) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB3.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB3.cs new file mode 100644 index 000000000..e3b2c84c4 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB3.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B3 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 11.0 Hz per L/min +/// - Offset: 0 Hz +/// +public class YfB3 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B9 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB3(IPin pin) + : base(pin, 11.0) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB6.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB6.cs new file mode 100644 index 000000000..f44d9d22b --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB6.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B10 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 6.6 Hz per L/min +/// - Offset: 0 Hz +/// +public class YfB6 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B6 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB6(IPin pin) + : base(pin, 6.6d) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB9.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB9.cs new file mode 100644 index 000000000..c5437bee3 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Drivers/YfB9.cs @@ -0,0 +1,23 @@ +using Meadow.Hardware; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Driver for the YF-B9 Hall effect water flow sensor. +/// +/// +/// Configures the sensor with its factory calibration values: +/// - Scale factor: 7.5 Hz per L/min +/// - Offset: 4 Hz +/// +public class YfB9 : HallEffectBase +{ + /// + /// Initializes a new instance of the YF-B9 flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + public YfB9(IPin pin) + : base(pin, 7.5, 4) + { + } +} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/HallEffectBase.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/HallEffectBase.cs new file mode 100644 index 000000000..4d615bb98 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/HallEffectBase.cs @@ -0,0 +1,69 @@ +using Meadow.Foundation; +using Meadow.Hardware; +using Meadow.Units; + +using System.Threading.Tasks; + +namespace Meadow.Peripherals.Sensors.Flow; + +/// +/// Base class for Hall effect flow sensors that measure volumetric flow based on pulse frequency. +/// +/// +/// Hall effect flow sensors typically output a frequency proportional to the flow rate. +/// Each sensor model has a specific calibration coefficient (Hz per L/min) used to convert +/// the measured frequency to a flow rate. +/// Sensors will have a flow formula in the form: +/// F = (S * Q - O) +/// e.g. F = (7.5 * Q - 4) +/// where: +/// F = Frequency +/// Q = Flow +/// S = Scale +/// O = Offset +/// +public abstract class HallEffectBase : PollingSensorBase, IVolumetricFlowSensor +{ + private readonly IDigitalSignalAnalyzer analyzer; + private readonly double scale; + private readonly double offset; + + /// + /// Initializes a new instance of a Hall effect flow sensor. + /// + /// The digital input pin connected to the sensor's signal line. + /// The sensor scale factor (S) in Hz per L/min + /// The sensor offset (O) in Hz + protected HallEffectBase(IPin pin, double scale, double offset = 0) + { + this.scale = scale; + this.offset = offset; + analyzer = pin.CreateDigitalSignalAnalyzer(false); + } + + /// + public VolumetricFlow Flow => CalculateFlow(analyzer.GetFrequency(), scale, offset); + + /// + protected override Task ReadSensor() + { + return Task.FromResult(CalculateFlow(analyzer.GetFrequency(), scale, offset)); + } + + /// + /// Calculates volumetric flow rate from frequency using the formula F = (S * Q - O), solving for Q. + /// + /// The measured frequency in Hz + /// The scale factor (S) in Hz per L/min + /// The offset (O) in Hz + /// The flow rate in cubic meters per second + private VolumetricFlow CalculateFlow(Frequency frequency, double scale, double offset) + { + // First solve for Q (L/min): F = (S * Q - O) + // F + O = S * Q + // Q = (F + O) / S + double litersPerMinute = (frequency.Hertz + offset) / scale; + + return new VolumetricFlow(litersPerMinute, VolumetricFlow.UnitType.LitersPerMinute); + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Readme.md b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Readme.md new file mode 100644 index 000000000..86e449b92 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Readme.md @@ -0,0 +1,92 @@ +# Meadow.Foundation.Sensors.Light.Bh1750 + +**Bh1750 I2C luminance and color light sensor** + +The **Bh1750** library is included in the **Meadow.Foundation.Sensors.Light.Bh1750** nuget package and is designed for the [Wilderness Labs](www.wildernesslabs.co) Meadow .NET IoT platform. + +This driver is part of the [Meadow.Foundation](https://developer.wildernesslabs.co/Meadow/Meadow.Foundation/) peripherals library, an open-source repository of drivers and libraries that streamline and simplify adding hardware to your C# .NET Meadow IoT applications. + +For more information on developing for Meadow, visit [developer.wildernesslabs.co](http://developer.wildernesslabs.co/). + +To view all Wilderness Labs open-source projects, including samples, visit [github.com/wildernesslabs](https://github.com/wildernesslabs/). + +## Installation + +You can install the library from within Visual studio using the the NuGet Package Manager or from the command line using the .NET CLI: + +`dotnet add package Meadow.Foundation.Sensors.Light.Bh1750` +## Usage + +```csharp +Bh1750 sensor; + +public override Task Initialize() +{ + Resolver.Log.Info("Initialize..."); + + var i2c = Device.CreateI2cBus(); + sensor = new Bh1750( + i2c, + measuringMode: Mode.ContinuouslyHighResolutionMode, // the various modes take differing amounts of time. + lightTransmittance: 1 // lower this to increase sensitivity, for instance, if it's behind a semi opaque window + ); + + // Example that uses an IObservable subscription to only be notified when the filter is satisfied + var consumer = Bh1750.CreateObserver( + handler: result => Resolver.Log.Info($"Observer: filter satisfied: {result.New.Lux:N2}Lux, old: {result.Old?.Lux:N2}Lux"), + + // only notify if the visible light changes by 100 lux (put your hand over the sensor to trigger) + filter: result => + { + if (result.Old is { } old) + { + // returns true if > 100lux change + return ((result.New - old).Abs().Lux > 100); + } + return false; + }); + sensor.Subscribe(consumer); + + // classical .NET events can also be used: + sensor.Updated += (sender, result) => Resolver.Log.Info($"Light: {result.New.Lux:N2}Lux"); + + return Task.CompletedTask; +} + +public override async Task Run() +{ + var result = await sensor.Read(); + Resolver.Log.Info("Initial Readings:"); + Resolver.Log.Info($" Light: {result.Lux:N2}Lux"); + + sensor.StartUpdating(TimeSpan.FromSeconds(1)); +} + +``` +## How to Contribute + +- **Found a bug?** [Report an issue](https://github.com/WildernessLabs/Meadow_Issues/issues) +- Have a **feature idea or driver request?** [Open a new feature request](https://github.com/WildernessLabs/Meadow_Issues/issues) +- Want to **contribute code?** Fork the [Meadow.Foundation](https://github.com/WildernessLabs/Meadow.Foundation) repository and submit a pull request against the `develop` branch + + +## Need Help? + +If you have questions or need assistance, please join the Wilderness Labs [community on Slack](http://slackinvite.wildernesslabs.co/). +## About Meadow + +Meadow is a complete, IoT platform with defense-grade security that runs full .NET applications on embeddable microcontrollers and Linux single-board computers including Raspberry Pi and NVIDIA Jetson. + +### Build + +Use the full .NET platform and tooling such as Visual Studio and plug-and-play hardware drivers to painlessly build IoT solutions. + +### Connect + +Utilize native support for WiFi, Ethernet, and Cellular connectivity to send sensor data to the Cloud and remotely control your peripherals. + +### Deploy + +Instantly deploy and manage your fleet in the cloud for OtA, health-monitoring, logs, command + control, and enterprise backend integrations. + + diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Sensors.Flow.HallEffect.csproj b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Sensors.Flow.HallEffect.csproj new file mode 100644 index 000000000..48747d866 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Flow.HallEffect/Driver/Sensors.Flow.HallEffect.csproj @@ -0,0 +1,28 @@ + + + 1.11.0 + Readme.md + enable + 10.0 + Apache-2.0 + true + icon.png + Wilderness Labs, Inc + netstandard2.1 + Library + HallEffectFlowSensors + Wilderness Labs, Inc + http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/ + Meadow.Foundation.Sensors.Flow.HallEffect + https://github.com/WildernessLabs/Meadow.Foundation + Meadow.Foundation,flow,YF-B10,GR-105,GR-201,GR-216 + true + Drivers for various hall effect flow sensor + Meadow.Foundation.Sensors.Flow + + + + + + + diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Hid.Keyboard/Driver/Keyboard.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Hid.Keyboard/Driver/Keyboard.cs index 60ee38043..d63f26bcb 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Hid.Keyboard/Driver/Keyboard.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Hid.Keyboard/Driver/Keyboard.cs @@ -166,4 +166,10 @@ public IDigitalOutputPort CreateDigitalOutputPort(IPin pin, bool initialState = return new KeyboardIndicator(pin, ci, initialState ? true : null); } + + /// + public IDigitalSignalAnalyzer CreateDigitalSignalAnalyzer(IPin pin, bool captureDutyCycle) + { + return new SoftDigitalSignalAnalyzer(pin, captureDutyCycle: captureDutyCycle); + } } diff --git a/Source/Meadow.Foundation.sln b/Source/Meadow.Foundation.sln index 20a6a49de..5a12d6827 100644 --- a/Source/Meadow.Foundation.sln +++ b/Source/Meadow.Foundation.sln @@ -1632,8 +1632,13 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Keller XLine", "Keller XLine", "{2240AB38-3CC6-4800-8556-D3BB5C44B720}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Environmental.Keller.XLine", "Meadow.Foundation.Peripherals\Sensors.Environmental.Keller.XLine\Driver\Sensors.Environmental.Keller.XLine.csproj", "{729B86E1-49EE-4668-A599-8D7C28842F9E}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Epd2in15g_Sample", "Meadow.Foundation.Peripherals\Displays.ePaperWaveShare\Samples\Epd2in15g_Sample\Epd2in15g_Sample.csproj", "{EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flow", "Flow", "{C5AA856B-4199-43B1-AECE-8871E91A0EF1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensors.Flow.HallEffect", "Meadow.Foundation.Peripherals\Sensors.Flow.HallEffect\Driver\Sensors.Flow.HallEffect.csproj", "{EE40720A-33B0-4151-80AE-F73F9C1A45D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -3954,6 +3959,12 @@ Global {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.Build.0 = Release|Any CPU {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B}.Release|Any CPU.Deploy.0 = Release|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.Build.0 = Release|Any CPU + {EE40720A-33B0-4151-80AE-F73F9C1A45D8}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4768,6 +4779,8 @@ Global {2240AB38-3CC6-4800-8556-D3BB5C44B720} = {78E463DA-0FA1-4AAE-A281-D3297C9388C9} {729B86E1-49EE-4668-A599-8D7C28842F9E} = {2240AB38-3CC6-4800-8556-D3BB5C44B720} {EA8D8CA1-BB32-49D6-88CF-9EB50ABDC44B} = {7311794D-7D2F-47E8-A5B0-C216CBD64A13} + {C5AA856B-4199-43B1-AECE-8871E91A0EF1} = {9F4EEBFB-F2B6-4B28-ABAD-D219F4AB15F3} + {EE40720A-33B0-4151-80AE-F73F9C1A45D8} = {C5AA856B-4199-43B1-AECE-8871E91A0EF1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF7CA16F-8C38-4546-87A2-5DAAF58A1520}