Skip to content

Commit

Permalink
Merge pull request #977 from WildernessLabs/feature/ahtx0
Browse files Browse the repository at this point in the history
Feature/ahtx0
  • Loading branch information
adrianstevens authored May 15, 2024
2 parents b61fd61 + 6e95fee commit fb357c4
Show file tree
Hide file tree
Showing 15 changed files with 449 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Meadow.Hardware;
using Meadow.Peripherals.Displays;
using System;
using System.Linq;
using System.Threading;

Expand Down Expand Up @@ -182,25 +183,32 @@ private void DrawLoopOnCaller()
{
while (true)
{
if (!_updateInProgress && (IsInvalid || Controls.Any(c => c.IsInvalid)))
{
if (!_updateInProgress && (IsInvalid || Controls.Any(c => c.IsInvalid)))
{
_graphics.Clear(BackgroundColor);
_graphics.Clear(BackgroundColor);

lock (Controls.SyncRoot)
lock (Controls.SyncRoot)
{
foreach (var control in Controls)
{
foreach (var control in Controls)
if (control != null)
{
if (control != null)
{
// TODO: micrographics supports invalidating regions - we need to update to invalidate only regions here, too
RefreshTree(control);
}
// TODO: micrographics supports invalidating regions - we need to update to invalidate only regions here, too
RefreshTree(control);
}
}
}
try
{
_graphics.Show();
IsInvalid = false;
}
catch (Exception ex)
{
// it possible to have a callee error (e.g. an I2C bus problem)
// we'll report it and continue running
Resolver.Log.Warn($"MicroGraphics.Show error while drawing screen: {ex.Message}");
}
IsInvalid = false;
}

Thread.Sleep(50);
Expand All @@ -227,7 +235,16 @@ private void DrawLoopThreaded()
RefreshTree(control);
}
}
_graphics.Show();
try
{
_graphics.Show();
}
catch (Exception ex)
{
// it possible to have a callee error (e.g. an I2C bus problem)
// we'll report it and continue running
Resolver.Log.Warn($"MicroGraphics.Show error while drawing screen: {ex.Message}");
}
IsInvalid = false;
}
}
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Meadow.Foundation.Sensors.Atmospheric;

public partial class Ahtx0
{
/// <summary>
/// Valid I2C addresses for the sensor
/// </summary>
public enum Addresses : byte
{
/// <summary>
/// Bus address 0x38
/// </summary>
Address_0x38 = 0x38,
/// <summary>
/// Bus address 0x39
/// </summary>
Address_0x39 = 0x39,
/// <summary>
/// Default bus address
/// </summary>
Default = Address_0x38
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Meadow.Foundation.Sensors.Atmospheric;

public partial class Ahtx0
{
/// <summary>
/// Ahtx0 Commands
/// </summary>
internal enum Commands : byte
{
INITIALIZE = 0b111_0001,
TRIGGER_MEAS = 0b1010_1100,
SOFT_RESET = 0b1011_1010
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using Meadow.Hardware;
using Meadow.Peripherals.Sensors;
using Meadow.Peripherals.Sensors.Atmospheric;
using Meadow.Units;
using System;
using System.Threading.Tasks;

namespace Meadow.Foundation.Sensors.Atmospheric;


/// <summary>
/// Ahtx0 Temperature sensor object
/// </summary>
public abstract partial class Ahtx0 :
ByteCommsSensorBase<(RelativeHumidity? Humidity, Units.Temperature? Temperature)>,
ITemperatureSensor, IHumiditySensor, II2cPeripheral
{
private bool isInitialized = false;

private event EventHandler<IChangeResult<Units.Temperature>> temperatureHandlers = default!;
private event EventHandler<IChangeResult<RelativeHumidity>> humidityHandlers = default!;

event EventHandler<IChangeResult<Units.Temperature>> ISamplingSensor<Units.Temperature>.Updated
{
add => temperatureHandlers += value;
remove => temperatureHandlers -= value;
}

event EventHandler<IChangeResult<RelativeHumidity>> ISamplingSensor<RelativeHumidity>.Updated
{
add => humidityHandlers += value;
remove => humidityHandlers -= value;
}

/// <summary>
/// The default I2C address for the peripheral
/// </summary>
public byte DefaultI2cAddress => (byte)Addresses.Default;

/// <inheritdoc/>
public Units.Temperature? Temperature { get; protected set; }

/// <inheritdoc/>
public Units.RelativeHumidity? Humidity { get; protected set; }

/// <summary>
/// Create a new Ahtx0 object using the default configuration for the sensor
/// </summary>
/// <param name="i2cBus">The I2C bus</param>
/// <param name="address">I2C address of the sensor</param>
public Ahtx0(II2cBus i2cBus, byte address = (byte)Addresses.Default)
: base(i2cBus, address, readBufferSize: 7)
{
}

/// <summary>
/// Raise all change events for subscribers
/// </summary>
/// <param name="changeResult">humidity and temperature</param>
protected override void RaiseEventsAndNotify(IChangeResult<(Units.RelativeHumidity? Humidity, Units.Temperature? Temperature)> changeResult)
{
if (changeResult.New.Humidity is { } humidity)
{
humidityHandlers?.Invoke(this, new ChangeResult<Units.RelativeHumidity>(humidity, changeResult.Old?.Humidity));
}
if (changeResult.New.Temperature is { } temperature)
{
temperatureHandlers?.Invoke(this, new ChangeResult<Units.Temperature>(temperature, changeResult.Old?.Temperature));
}
base.RaiseEventsAndNotify(changeResult);
}

private async Task InitializeIfRequired()
{
if (isInitialized) { return; }

BusComms.Write((byte)Commands.SOFT_RESET);
await Task.Delay(20);

while (IsBusy())
{
await Task.Delay(10);
}

BusComms.Write(new byte[] { (byte)Commands.INITIALIZE, 0x08, 0x00 });

while (IsBusy())
{
await Task.Delay(10);
}

BusComms.Read(ReadBuffer.Span[0..1]);

isInitialized = true;
}

private bool IsBusy()
{
BusComms.Read(ReadBuffer.Span[0..1]);
return (ReadBuffer.Span[0] & 0x80) == 0x80;
}

/// <summary>
/// Reads the humidity and temperature.
/// </summary>
protected override async Task<(Units.RelativeHumidity?, Units.Temperature?)> ReadSensor()
{
(Units.RelativeHumidity? Humidity, Units.Temperature? Temperature) conditions;

await InitializeIfRequired();

BusComms.Write(new byte[] { (byte)Commands.TRIGGER_MEAS, 0x33, 0x00 });
await Task.Delay(80);

while (IsBusy())
{
await Task.Delay(10);
}

BusComms.Read(ReadBuffer.Span);

var data = ReadBuffer.ToArray();
Resolver.Log.Info(BitConverter.ToString(data));

var humidity = (data[1] << 12) | (data[2] << 4) | (data[3] >> 4);
conditions.Humidity = new RelativeHumidity((humidity / (double)0x100000) * 100d, RelativeHumidity.UnitType.Percent);

var temp = ((data[3] & 0x0f) << 16) | (data[4] << 8) | data[5];
conditions.Temperature = new Units.Temperature((temp / (double)0x100000) * 200d - 50d, Units.Temperature.UnitType.Celsius);

return conditions;
}

async Task<Units.Temperature> ISensor<Units.Temperature>.Read()
=> (await Read()).Temperature!.Value;

async Task<Units.RelativeHumidity> ISensor<Units.RelativeHumidity>.Read()
=> (await Read()).Humidity!.Value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Meadow.Hardware;

namespace Meadow.Foundation.Sensors.Atmospheric;

/// <summary>
/// Aht10 Temperature sensor object
/// </summary>
public class Aht10 : Ahtx0
{
/// <summary>
/// Create a new Aht10 object using the default configuration for the sensor
/// </summary>
/// <param name="i2cBus">The I2C bus</param>
/// <param name="address">I2C address of the sensor</param>
public Aht10(II2cBus i2cBus, byte address = 56)
: base(i2cBus, address)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Meadow.Hardware;

namespace Meadow.Foundation.Sensors.Atmospheric;

/// <summary>
/// Aht20 Temperature sensor object
/// </summary>
public class Aht20 : Ahtx0
{
/// <summary>
/// Create a new Aht20 object using the default configuration for the sensor
/// </summary>
/// <param name="i2cBus">The I2C bus</param>
/// <param name="address">I2C address of the sensor</param>
public Aht20(II2cBus i2cBus, byte address = 56)
: base(i2cBus, address)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Meadow.Sdk/1.1.0">
<PropertyGroup>
<Version>1.11.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageIcon>icon.png</PackageIcon>
<Authors>Wilderness Labs, Inc</Authors>
<TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>Ahtx0</AssemblyName>
<Company>Wilderness Labs, Inc</Company>
<PackageProjectUrl>http://developer.wildernesslabs.co/Meadow/Meadow.Foundation/</PackageProjectUrl>
<PackageId>Meadow.Foundation.Sensors.Atmospheric.Ahtx0</PackageId>
<RepositoryUrl>https://github.com/WildernessLabs/Meadow.Foundation</RepositoryUrl>
<PackageTags>Meadow.Foundation, Temperature, AHT10, AHT20</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Description>AHTx0 I2C temperature and humidity sensors</Description>
<Nullable>enable</Nullable>
<RootNamespace>Meadow.Foundation.Sensors.Atmospheric</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<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,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\Meadow.Core\source\implementations\windows\Meadow.Windows\Meadow.Windows.csproj" />
<ProjectReference Include="..\..\..\ICs.IOExpanders.Ftxxxx\Driver\ICs.IOExpanders.Ftxxxx.csproj" />
<ProjectReference Include="..\..\Driver\Sensors.Atmospheric.Ahtx0.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Meadow;
using Meadow.Foundation.ICs.IOExpanders;
using Meadow.Foundation.Sensors.Atmospheric;
using Meadow.Peripherals.Sensors;
using System;
using System.Threading.Tasks;

namespace Sensors.Temperature.Aht10_Sample;

public class MeadowApp : App<Windows>
{
public static async Task Main(string[] args)
{
await MeadowOS.Start(args);
}

//<!=SNIP=>

private Ahtx0 sensor;

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

// adjust the index to match your hardware configuration
var ft232 = FtdiExpanderCollection.Devices[0];

sensor = new Aht10(ft232.CreateI2cBus());

var consumer = Aht10.CreateObserver(
handler: (result) =>
{
Resolver.Log.Info($"Observer: Temp changed by threshold; new temp: {result.New.Temperature?.Celsius:N2}C, old: {result.Old?.Temperature?.Celsius:N2}C");
},
filter: null
);
sensor.Subscribe(consumer);

(sensor as ITemperatureSensor).Updated += (sender, e) =>
{
Resolver.Log.Info($"Temperature Updated: {e.New.Celsius:n2}C");
};
return Task.CompletedTask;
}

public override async Task Run()
{
if (sensor == null) { return; }

var result = await sensor.Read();
Resolver.Log.Info("Initial Readings:");
Resolver.Log.Info($" Temperature: {result.Temperature?.Celsius:F1}°C");
Resolver.Log.Info($" Relative Humidity: {result.Humidity:F1}%");

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

//<!=SNOP=>
}
Loading

0 comments on commit fb357c4

Please sign in to comment.