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

refactored Y4000 driver #1084

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
</PropertyGroup>
<ItemGroup>
<None Include=".\Readme.md" Pack="true" PackagePath="" />
<PackageReference Include="Silk.NET" Version="2.21.0" />
<PackageReference Include="SkiaSharp" Version="2.88.8" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="Silk.NET" Version="2.22.0" />
<PackageReference Include="SkiaSharp" Version="2.88.9" />
<PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\icon.png" Link="icon.png" Pack="true" PackagePath="" />
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Meadow.Units;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Environmental;

public interface IKellerTransducer
{
Task<Units.Temperature> ReadTemperature(TemperatureChannel channel);
Task<Pressure> ReadPressure(PressureChannel channel);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Meadow.Modbus;
using Meadow.Units;
using System;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Environmental;

public class KellerTransducer : IKellerTransducer
{
private ModbusRtuClient modbusClient;
private byte modbusAddress = 250;
private ushort activePressureChannels;
private ushort activeTemperatureChannels;

public int? SerialNumber { get; private set; }
public byte ModbusAddress { get; }

public KellerTransducer(ModbusRtuClient modbus, byte modbusAddress = 1)
{
ModbusAddress = modbusAddress;
this.modbusClient = modbus;

if (!modbus.IsConnected)
{
modbus.Connect();
}

_ = ReadConfiguration();

}

private bool isReady = false;

private async Task ReadConfiguration()
{
// the device doesn't appear to like reading > 4 registers at a time
var registers = await modbusClient.ReadHoldingRegisters(ModbusAddress, 0x0200, 4);
SerialNumber = registers.ExtractInt32(2);

registers = await modbusClient.ReadHoldingRegisters(ModbusAddress, 0x0204, 4);
activePressureChannels = registers[0];
activeTemperatureChannels = registers[1];

isReady = true;
}

public async Task<Units.Temperature> ReadTemperature(TemperatureChannel channel)
{
while (!isReady)
{
await Task.Delay(500);
}

if (((ushort)channel & activeTemperatureChannels) == 0)
{
throw new ArgumentException("Selected channel is not supported by the connected device");
}

ushort address = channel switch
{
TemperatureChannel.T => 0x006,
TemperatureChannel.TOB1 => 0x008,
TemperatureChannel.TOB2 => 0x00A,
_ => throw new ArgumentException()
};

var r = await modbusClient.ReadHoldingRegisters(ModbusAddress, address, 2);
var temp = r.ExtractSingle();
return new Units.Temperature(temp, Units.Temperature.UnitType.Celsius);
}

public async Task<Pressure> ReadPressure(PressureChannel channel)
{
while (!isReady)
{
await Task.Delay(500);
}

if (((ushort)channel & activePressureChannels) == 0)
{
throw new ArgumentException("Selected channel is not supported by the connected device");
}

ushort address = channel switch
{
PressureChannel.P1 => 0x0002,
PressureChannel.P2 => 0x004,
_ => throw new ArgumentException()
};

var r = await modbusClient.ReadHoldingRegisters(ModbusAddress, address, 2);
var p = r.ExtractSingle();
return new Pressure(p, Pressure.UnitType.Bar);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Meadow.Foundation.Sensors.Environmental;

public enum PressureChannel
{
P1 = 1 << 1,
P2 = 1 << 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Meadow.Foundation.Sensors.Environmental.Ens160

**ENS160 I2C C02, Ethanol and AQI sensor**

The **Ens160** library is included in the **Meadow.Foundation.Sensors.Environmental.Ens160** 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.Environmental.Ens160`
## Usage

```csharp
Ens160 sensor;

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

var i2cBus = Device.CreateI2cBus(Meadow.Hardware.I2cBusSpeed.Standard);

sensor = new Ens160(i2cBus, (byte)Ens160.Addresses.Address_0x53);

var consumer = Ens160.CreateObserver(
handler: result =>
{
Resolver.Log.Info($"Observer: C02 concentration changed by threshold; new: {result.New.CO2Concentration?.PartsPerMillion:N0}ppm");
},
filter: result =>
{
if (result.Old?.CO2Concentration is { } oldCon &&
result.New.CO2Concentration is { } newCon)
{
return Math.Abs((newCon - oldCon).PartsPerMillion) > 10;
}
return false;
}
);

sensor?.Subscribe(consumer);

if (sensor != null)
{
sensor.Updated += (sender, result) =>
{
Resolver.Log.Info($" CO2 Concentration: {result.New.CO2Concentration?.PartsPerMillion:N0}ppm");
Resolver.Log.Info($" Ethanol Concentration: {result.New.EthanolConcentration?.PartsPerBillion:N0}ppb");
Resolver.Log.Info($" TVOC Concentration: {result.New.TVOCConcentration?.PartsPerBillion:N0}ppb");
Resolver.Log.Info($" AQI: {sensor.GetAirQualityIndex()}");
};
}

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

return base.Initialize();
}

```
## 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.


Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Meadow.Sdk/1.1.0">
<PropertyGroup>
<Version>1.11.0</Version>
<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>Keller.XLine</AssemblyName>
<Company>Wilderness Labs, Inc</Company>
<PackageProjectUrl>http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/</PackageProjectUrl>
<PackageId>Meadow.Foundation.Sensors.Environmental.Keller.XLine</PackageId>
<RepositoryUrl>https://github.com/WildernessLabs/Meadow.Foundation</RepositoryUrl>
<PackageTags>Meadow,Meadow.Foundation,Environmental,Keller,Pressure</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Description>Driver for the line of Keller X-Line Modbus Pressure Transducers</Description>
</PropertyGroup>
<ItemGroup>
<None Include=".\Readme.md" Pack="true" PackagePath="" />
<None Include="..\..\..\icon.png" Pack="true" PackagePath="" />
<PackageReference Include="System.IO.Ports" Version="9.0.0" />
<ProjectReference Include="..\..\..\..\..\Meadow.Modbus\src\Meadow.Modbus\Meadow.Modbus.csproj" />
<ProjectReference Include="..\..\..\Meadow.Foundation.Core\Meadow.Foundation.Core.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Meadow.Units;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Environmental;

public class SimulatedKellerTransducer : IKellerTransducer
{
public Task<Pressure> ReadPressure(PressureChannel channel)
{
return Task.FromResult(new Pressure(123, Pressure.UnitType.Millibar));
}

public Task<Units.Temperature> ReadTemperature(TemperatureChannel channel)
{
return Task.FromResult(new Units.Temperature(42.1, Units.Temperature.UnitType.Fahrenheit));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Meadow.Foundation.Sensors.Environmental;

public enum TemperatureChannel
{
T = 1 << 3,
TOB1 = 1 << 4,
TOB2 = 1 << 5,
Con = 1 << 7
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Meadow.Peripherals.Sensors;
using Meadow.Units;

namespace Meadow.Foundation.Sensors.Environmental;

/// <summary>
/// Represents a sensor for measuring oxidation/reduction potential
/// </summary>
public interface IRedoxPotentialSensor : ISamplingSensor<Voltage>
{
/// <summary>
/// Last value read from the sensor
/// </summary>
Voltage? Potential { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Meadow.Peripherals.Sensors;

namespace Meadow.Foundation.Sensors.Environmental;

/// <summary>
/// Represents a sensor for measuring water quality concentrations
/// </summary>
public interface IWaterQualityConcentrationsSensor : ISamplingSensor<WaterQualityConcentrations>
{
/// <summary>
/// Last value read from the sensor
/// </summary>
WaterQualityConcentrations? Concentrations { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<ItemGroup>
<None Include=".\Readme.md" Pack="true" PackagePath="" />
<None Include="..\..\..\icon.png" Pack="true" PackagePath="" />
<PackageReference Include="System.IO.Ports" Version="9.0.0" />
<ProjectReference Include="..\..\..\Meadow.Foundation.Core\Meadow.Foundation.Core.csproj" />
<ProjectReference Include="..\..\..\..\..\Meadow.Modbus\src\Meadow.Modbus\Meadow.Modbus.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Meadow.Units;

namespace Meadow.Foundation.Sensors.Environmental;

/// <summary>
/// Represents concentrations indicating water quality
/// </summary>
public struct WaterQualityConcentrations
{
/// <summary>
/// Concentration of dissolved Oxygen in water
/// </summary>
public ConcentrationInWater? DissolvedOxygen;
/// <summary>
/// Chlorophyll Concentration (CHL)
/// </summary>
public ConcentrationInWater? Chlorophyl;
/// <summary>
/// Salination (SAL)
/// </summary>
public ConcentrationInWater? BlueGreenAlgae;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public partial class Y4000
{
static class Registers
private static class Registers
{
public static HoldingRegister Version = new HoldingRegister(0x0700, 0x02);
public static HoldingRegister ErrorCode = new HoldingRegister(0x0800, 0x01);
Expand All @@ -15,7 +15,7 @@ static class Registers
public static HoldingRegister ISDN = new HoldingRegister(0x3000, 0x01);
}

struct HoldingRegister
private struct HoldingRegister
{
public ushort Offset { get; private set; }
public int Length { get; private set; }
Expand Down
Loading
Loading