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

DF Robot Analog DO sensor #866

Merged
merged 4 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
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
Expand Up @@ -13,7 +13,7 @@ To view all Wilderness Labs open-source projects, including samples, visit [gith
## Usage

```csharp
private IPositionalMotor stepper;
private IStepperMotor stepper;

private bool UseStepDirConfiguration { get; set; } = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public override Task Initialize()
{
Resolver.Log.Info("Initialize...");

a02yyuw = new A02yyuw(Device, Device.PlatformOS.GetSerialPortName("COM1"));
a02yyuw = new A02yyuw(Device, Device.PlatformOS.GetSerialPortName("COM4"));

var consumer = A02yyuw.CreateObserver(
handler: result =>
Expand All @@ -30,7 +30,7 @@ public override Task Initialize()
{
if (result.Old is { } old)
{
return Math.Abs((result.New - old).Centimeters) > 0.5;
return Math.Abs((result.New - old).Centimeters) > 5.0;
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public override Task Initialize()
{
if (result.Old is { } old)
{
return Math.Abs((result.New - old).Centimeters) > 0.5;
return Math.Abs((result.New - old).Centimeters) > 5.0;
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ public override Task Initialize()
sensor.Subscribe(consumer);

// optional classical .NET events can also be used:
sensor.SaturationUpdated += (sender, result) =>
sensor.Updated += (sender, result) =>
{
// string oldValue = (result.Old is { } old) ? $"{old * 100:n0}%" : "n/a";
// Resolver.Log.Info($"Updated - New: {result.New * 100:n0}%, Old: {oldValue}");
string oldValue = (result.Old is { } old) ? $"{old * 100:n0}%" : "n/a";
Resolver.Log.Info($"Updated - New: {result.New * 100:n0}%, Old: {oldValue}");
};

return Task.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using Meadow.Hardware;
using Meadow.Units;
using System;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Environmental;

/// <summary>
/// DFRobot Analog Gravity Dissolved Oxygen Meter
/// </summary>
public partial class DFRobotGravityDOMeter : SamplingSensorBase<ConcentrationInWater> //, IDissolvedOxygenSensor
{
/// <summary>
/// The current water temperature (default 25C)
/// </summary>
public Units.Temperature WaterTemperature { get; set; } = new Units.Temperature(25, Units.Temperature.UnitType.Celsius);

/// <summary>
/// The calibration value for the sensor at 25C (default 1.6V)
/// </summary>
public Voltage CalibrationAt25C { get; set; } = new Voltage(1.6, Voltage.UnitType.Volts);

/// <summary>
/// Returns the analog input port
/// </summary>
protected IAnalogInputPort AnalogInputPort { get; }

/// <summary>
/// Last concentration value read from the sensor
/// </summary>
public ConcentrationInWater? ConcentrationInWater { get; protected set; }

/// <summary>
/// The disolved oxygen lookup table for temperature values from 0 to 40 degrees C
/// </summary>
readonly int[] DO_Table = new int[41] {
14460, 14220, 13820, 13440, 13090, 12740, 12420, 12110, 11810, 11530,
11260, 11010, 10770, 10530, 10300, 10080, 9860, 9660, 9460, 9270,
9080, 8900, 8730, 8570, 8410, 8250, 8110, 7960, 7820, 7690,
7560, 7430, 7300, 7180, 7070, 6950, 6840, 6730, 6630, 6530, 6410};

/// <summary>
/// Creates a new DFRobotGravityDOMeter object
/// </summary>
/// <param name="analogInputPin">Analog pin the temperature sensor is connected to</param>
/// <param name="sampleCount">How many samples to take during a given reading</param>
/// <param name="sampleInterval">The time, to wait in between samples during a reading</param>
public DFRobotGravityDOMeter(IPin analogInputPin, int sampleCount = 5, TimeSpan? sampleInterval = null)
: this(analogInputPin.CreateAnalogInputPort(sampleCount, sampleInterval ?? TimeSpan.FromMilliseconds(40), new Voltage(3.3)))
{ }

/// <summary>
/// Creates a new DFRobotGravityDOMeter object
/// </summary>
/// <param name="analogInputPort">The port for the analog input pin</param>
public DFRobotGravityDOMeter(IAnalogInputPort analogInputPort)
{
AnalogInputPort = analogInputPort;

AnalogInputPort.Subscribe
(
IAnalogInputPort.CreateObserver(
result =>
{
ChangeResult<ConcentrationInWater> changeResult = new()
{
New = VoltageToConcentration(result.New),
Old = ConcentrationInWater
};
ConcentrationInWater = changeResult.New;
RaiseEventsAndNotify(changeResult);
}
)
);
}

/// <summary>
/// Get the current voltage, useful for calibration
/// </summary>
/// <returns></returns>
public Task<Voltage> GetCurrentVoltage()
{
return AnalogInputPort.Read();
}

/// <summary>
/// Reads data from the sensor
/// </summary>
/// <returns>The latest sensor reading</returns>
protected override async Task<ConcentrationInWater> ReadSensor()
{
var voltage = await AnalogInputPort.Read();
var newConcentration = VoltageToConcentration(voltage);
ConcentrationInWater = newConcentration;
return newConcentration;
}

/// <summary>
/// Starts continuously sampling the sensor
/// </summary>
public override void StartUpdating(TimeSpan? updateInterval)
{
lock (samplingLock)
{
if (IsSampling) { return; }
IsSampling = true;
AnalogInputPort.StartUpdating(updateInterval);
}
}

/// <summary>
/// Stops sampling the sensor
/// </summary>
public override void StopUpdating()
{
lock (samplingLock)
{
if (!IsSampling) { return; }
IsSampling = false;
AnalogInputPort.StopUpdating();
}
}

ConcentrationInWater VoltageToConcentration(Voltage voltage)
{
var calibrationValue = DO_Table[(int)WaterTemperature.Celsius];

var voltageSaturationInMilliVolts = CalibrationAt25C.Millivolts + 35 * (WaterTemperature.Celsius - 25);
var concentrationRaw = voltage.Millivolts * calibrationValue / voltageSaturationInMilliVolts;

return new ConcentrationInWater(concentrationRaw, Units.ConcentrationInWater.UnitType.MicrogramsPerLiter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Meadow.Foundation.Sensors.Environmental.DFRobotGravityDOMeter

**DFRobot analog gravity dissolved oxygen sensor**

The **DFRobotGravityDOMeter** library is designed for the [Wilderness Labs](www.wildernesslabs.co) Meadow .NET IoT platform and is part of [Meadow.Foundation](https://developer.wildernesslabs.co/Meadow/Meadow.Foundation/).

The **Meadow.Foundation** peripherals library is an open-source repository of drivers and libraries that streamline and simplify adding hardware to your C# .NET Meadow IoT application.

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/).

## Usage

```csharp
DFRobotGravityDOMeter sensor;

public override Task Initialize()
{
Resolver.Log.Info("Initialize...");

sensor = new DFRobotGravityDOMeter(Device.Pins.A01);

// Example that uses an IObservable subscription to only be notified when the saturation changes
var consumer = DFRobotGravityDOMeter.CreateObserver(
handler: result =>
{
string oldValue = (result.Old is { } old) ? $"{old.MilligramsPerLiter:n0}" : "n/a";
string newValue = $"{result.New.MilligramsPerLiter:n0}";
Resolver.Log.Info($"New: {newValue}mg/l, Old: {oldValue}mg/l");
},
filter: null
);
sensor.Subscribe(consumer);

// optional classical .NET events can also be used:
sensor.Updated += (sender, result) =>
{
string oldValue = (result.Old is { } old) ? $"{old.MilligramsPerLiter}mg/l" : "n/a";
Resolver.Log.Info($"Updated - New: {result.New.MilligramsPerLiter:n0}mg/l, Old: {oldValue}");
};

return Task.CompletedTask;
}

public override async Task Run()
{
Resolver.Log.Info("Run...");

await ReadSensor();

sensor.StartUpdating(TimeSpan.FromSeconds(2));
}

protected async Task ReadSensor()
{
var concentration = await sensor.Read();
Resolver.Log.Info($"Initial concentration: {concentration.MilligramsPerLiter:N0}mg/l");
}

```
## 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/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Meadow.Sdk/1.1.0">
<PropertyGroup>
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageIcon>icon.png</PackageIcon>
<Authors>Wilderness Labs, Inc</Authors>
<TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>DFRobotGravityDOMeter</AssemblyName>
<Company>Wilderness Labs, Inc</Company>
<PackageProjectUrl>http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/</PackageProjectUrl>
<PackageId>Meadow.Foundation.Sensors.Environmental.DFRobotGravityDOMeter</PackageId>
<RepositoryUrl>https://github.com/WildernessLabs/Meadow.Foundation</RepositoryUrl>
<PackageTags>Meadow,Meadow.Foundation,Environmental,DFRobot,Gravity,DO,Dissolved,Oxygen,Meter</PackageTags>
<Version>0.1.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Description>DFRobot analog gravity dissolved oxygen sensor</Description>
</PropertyGroup>
<ItemGroup>
<None Include=".\Readme.md" Pack="true" PackagePath=""/>
<None Include="..\..\..\icon.png" Pack="true" PackagePath="" />
<ProjectReference Include="..\..\..\Meadow.Foundation.Core\Meadow.Foundation.Core.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Meadow.Sdk/1.1.0">
<PropertyGroup>
<RepositoryUrl>https://github.com/WildernessLabs/Meadow.Foundation</RepositoryUrl>
<Company>Wilderness Labs, Inc</Company>
<Authors>Wilderness Labs, Inc</Authors>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>App</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\Meadow.Core\Source\implementations\f7\Meadow.F7\Meadow.F7.csproj" />
<ProjectReference Include="..\..\Driver\Sensors.Environmental.DFRobotGravityDOMeter.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="meadow.config.yaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Meadow;
using Meadow.Devices;
using Meadow.Foundation.Sensors.Environmental;
using System;
using System.Threading.Tasks;

namespace Sensors.Environmental.DFRobotGravityDOMeter_Sample
{
public class MeadowApp : App<F7FeatherV2>
{
//<!=SNIP=>

DFRobotGravityDOMeter sensor;

public override Task Initialize()
{
Resolver.Log.Info("Initialize...");

sensor = new DFRobotGravityDOMeter(Device.Pins.A01);

// Example that uses an IObservable subscription to only be notified when the saturation changes
var consumer = DFRobotGravityDOMeter.CreateObserver(
handler: result =>
{
string oldValue = (result.Old is { } old) ? $"{old.MilligramsPerLiter:n0}" : "n/a";
string newValue = $"{result.New.MilligramsPerLiter:n0}";
Resolver.Log.Info($"New: {newValue}mg/l, Old: {oldValue}mg/l");
},
filter: null
);
sensor.Subscribe(consumer);

// optional classical .NET events can also be used:
sensor.Updated += (sender, result) =>
{
string oldValue = (result.Old is { } old) ? $"{old.MilligramsPerLiter}mg/l" : "n/a";
Resolver.Log.Info($"Updated - New: {result.New.MilligramsPerLiter:n0}mg/l, Old: {oldValue}");
};

return Task.CompletedTask;
}

public override async Task Run()
{
Resolver.Log.Info("Run...");

await ReadSensor();

sensor.StartUpdating(TimeSpan.FromSeconds(2));
}

protected async Task ReadSensor()
{
var concentration = await sensor.Read();
Resolver.Log.Info($"Initial concentration: {concentration.MilligramsPerLiter:N0}mg/l");
}

//<!=SNOP=>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MonoControl:
Options: --jit
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public override Task Initialize()
);
thermistor.Subscribe(consumer);

thermistor.TemperatureUpdated += (object sender, IChangeResult<Meadow.Units.Temperature> e) =>
thermistor.Updated += (object sender, IChangeResult<Meadow.Units.Temperature> e) =>
{
Resolver.Log.Info($"Temperature Updated: {e.New.Fahrenheit:N1}F/{e.New.Celsius:N1}C");
};
Expand Down
Loading
Loading