Skip to content

Commit

Permalink
Merge pull request #1 from wazzamatazz/feature/linux-listener
Browse files Browse the repository at this point in the history
Add BlueZ-based listener for Linux
  • Loading branch information
wazzamatazz committed May 27, 2021
2 parents 3b4a13c + d8143fc commit de4e0f6
Show file tree
Hide file tree
Showing 15 changed files with 582 additions and 8 deletions.
14 changes: 14 additions & 0 deletions NRuuviTag.sln
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NRuuviTag.Cli", "src\NRuuvi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NRuuviTag.Cli.Windows", "src\NRuuviTag.Cli.Windows\NRuuviTag.Cli.Windows.csproj", "{BDEB99CA-52F1-421D-8CFF-893D6A9F4F97}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRuuviTag.Listener.Linux", "src\NRuuviTag.Listener.Linux\NRuuviTag.Listener.Linux.csproj", "{5450FA92-6453-433C-8DC6-2D775DA188A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRuuviTag.Cli.Linux", "src\NRuuviTag.Cli.Linux\NRuuviTag.Cli.Linux.csproj", "{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -91,6 +95,14 @@ Global
{BDEB99CA-52F1-421D-8CFF-893D6A9F4F97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDEB99CA-52F1-421D-8CFF-893D6A9F4F97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDEB99CA-52F1-421D-8CFF-893D6A9F4F97}.Release|Any CPU.Build.0 = Release|Any CPU
{5450FA92-6453-433C-8DC6-2D775DA188A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5450FA92-6453-433C-8DC6-2D775DA188A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5450FA92-6453-433C-8DC6-2D775DA188A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5450FA92-6453-433C-8DC6-2D775DA188A3}.Release|Any CPU.Build.0 = Release|Any CPU
{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -104,6 +116,8 @@ Global
{1C416DEC-3C02-4692-B337-A44D06478796} = {10A2813D-C970-4F6F-9A59-94F7C972257F}
{E3335A57-337F-44E9-A972-BFD49C0BEE4E} = {10A2813D-C970-4F6F-9A59-94F7C972257F}
{BDEB99CA-52F1-421D-8CFF-893D6A9F4F97} = {10A2813D-C970-4F6F-9A59-94F7C972257F}
{5450FA92-6453-433C-8DC6-2D775DA188A3} = {10A2813D-C970-4F6F-9A59-94F7C972257F}
{DB8F5EA9-C673-48B9-B1E4-1C867CF02D74} = {10A2813D-C970-4F6F-9A59-94F7C972257F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94DF2EE3-033D-46CD-9EC3-7BC808B13372}
Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

A collection of .NET libraries to simplify interacting with RuuviTag IoT sensors from [Ruuvi](https://www.ruuvi.com/).

The repository contains a [core library](/src/NRuuviTag.Core) that defines common types, and a [listener implementation](/src/NRuuviTag.Listener.Windows) that uses the Windows 10 SDK to observe the Bluetooth LE advertisements emitted by RuuviTag devices. Samples received from RuuviTags can be automatically [published to an MQTT broker](#publishing-samples-to-mqtt).
The repository contains a [core library](/src/NRuuviTag.Core) that defines common types, and listener implementations that observe the Bluetooth LE advertisements emitted by RuuviTag devices. Samples received from RuuviTags can be automatically [published to an MQTT broker](#publishing-samples-to-mqtt).

The repository contains the following listener implementations:

- [Windows](/src/NRuuviTag.Listener.Windows) (using the Windows 10 SDK)
- [Linux](/src/NRuuviTag.Listener.Linux) (using [DotNet-BlueZ](https://github.com/hashtagchris/DotNet-BlueZ) to receive advertisements from BlueZ's D-Bus APIs)

The `nruuvitag` [command-line tool](#command-line-application) can be used to as a turnkey solution to start receiving and publishing RuuviTag sensor data to an MQTT broker.


# Example Usage

> See the [samples](/samples) folder for more details examples of usage.
> See the [samples](/samples) folder for more detailed examples of usage.
Usage is very straightforward. For example, to listen via the Windows 10 SDK using the [NRuuviTag.Listener.Windows](https://www.nuget.org/packages/NRuuviTag.Listener.Windows) NuGet package ([source](/src/NRuuviTag.Listener.Windows)):

Expand All @@ -21,11 +26,19 @@ await foreach (var sample in client.ListenAsync(cancellationToken)) {
}
```

To only observe specific RuuviTag devices using the Windows SDK using MAC address filtering:
To listen via BlueZ on Linux using the [NRuuviTag.Listener.Linux](https://www.nuget.org/packages/NRuuviTag.Listener.Linux) NuGet package ([source](/src/NRuuviTag.Listener.Linux)):

```csharp
var client = new WindowsSdkListener();
var client = new BlueZListener("hci0");

await foreach (var sample in client.ListenAsync(cancellationToken)) {
// sample is a RuuviTagSample object.
}
```

To only observe specific RuuviTag devices using MAC address filtering:

```csharp
bool CanProcessMessage(string macAddress) {
return string.Equals(macAddress, "AB:CD:EF:01:23:45");
}
Expand All @@ -43,7 +56,7 @@ The [NRuuviTag.Mqtt.Agent](https://www.nuget.org/packages/NRuuviTag.Mqtt.Agent)

# Command-Line Application

`nruuvitag` is a command-line tool for [Windows](/src/NRuuviTag.Cli.Windows) that can scan for nearby RuuviTags, and publish device readings to the console or to an MQTT broker.
`nruuvitag` is a command-line tool for [Windows](/src/NRuuviTag.Cli.Windows) and [Linux](/src/NRuuviTag.Cli.Linux) that can scan for nearby RuuviTags, and publish device readings to the console or to an MQTT broker.

Examples:

Expand Down
2 changes: 2 additions & 0 deletions build/Dependencies.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<!-- CoreFX Packages -->
<PropertyGroup>
<SystemTextJsonVersion>5.0.2</SystemTextJsonVersion>
<SystemThreadingChannelsVersion>5.0.0</SystemThreadingChannelsVersion>
</PropertyGroup>

<!-- ASP.NET Core/Microsoft Extension Packages -->
Expand All @@ -26,6 +27,7 @@

<!-- Other Packages -->
<PropertyGroup>
<HashtagChrisDotNetBlueZVersion>1.3.1</HashtagChrisDotNetBlueZVersion>
<MqttNetVersion>3.0.15</MqttNetVersion>
<SpectreConsoleVersion>0.39.0</SpectreConsoleVersion>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion build/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"Major": 0,
"Minor": 2,
"Minor": 3,
"Patch": 0,
"PreRelease": "alpha"
}
14 changes: 14 additions & 0 deletions src/NRuuviTag.Cli.Linux/NRuuviTag.Cli.Linux.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64</RuntimeIdentifiers>
<AssemblyName>nruuvitag</AssemblyName>
<Description>Command-line tool that can receive broadcasts from RuuviTag IoT sensors and publish readings to an MQTT broker.</Description>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\NRuuviTag.Cli\NRuuviTag.Cli.csproj" />
<ProjectReference Include="..\NRuuviTag.Listener.Linux\NRuuviTag.Listener.Linux.csproj" />
</ItemGroup>
</Project>
32 changes: 32 additions & 0 deletions src/NRuuviTag.Cli.Linux/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Threading.Tasks;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using NRuuviTag.Listener.Linux;

namespace NRuuviTag.Cli.Windows {

/// <summary>
/// RuuviTag command-line application.
/// </summary>
public class Program {

public static async Task<int> Main(string[] args) {
return await CreateHostBuilder(args)
.BuildAndRunRuuviTagMqttAgent(args)
.ConfigureAwait(false);
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config => {
config.AddRuuviTagMqttDeviceConfiguration();
})
.ConfigureServices((hostContext, services) => {
services.AddRuuviTagMqttAgent(hostContext.Configuration, sp => ActivatorUtilities.CreateInstance<BlueZListener>(sp, BlueZListener.DefaultBluetoothAdapter));
});

}
}
11 changes: 11 additions & 0 deletions src/NRuuviTag.Cli.Linux/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"profiles": {
"NRuuviTag.Cli.Linux": {
"commandName": "Project",
"dotnetRunMessages": "true",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
8 changes: 8 additions & 0 deletions src/NRuuviTag.Cli.Linux/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
}
}
8 changes: 8 additions & 0 deletions src/NRuuviTag.Cli.Linux/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
}
}
58 changes: 58 additions & 0 deletions src/NRuuviTag.Cli/NRuuviTagServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ public static class NRuuviTagServiceCollectionExtensions {
/// <param name="services">
/// The <see cref="IServiceCollection"/>.
/// </param>
/// <param name="configuration">
/// The <see cref="Configuration.IConfiguration"/> for the application.
/// </param>
/// <returns>
/// The <see cref="IServiceCollection"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="configuration"/> is <see langword="null"/>.
/// </exception>
public static IServiceCollection AddRuuviTagMqttAgent<TListener>(this IServiceCollection services, IConfiguration configuration) where TListener : class, IRuuviTagListener {
if (services == null) {
throw new ArgumentNullException(nameof(services));
Expand All @@ -50,6 +56,58 @@ public static class NRuuviTagServiceCollectionExtensions {
return services;
}


/// <summary>
/// Registers services required for a <see cref="CommandApp"/> that will run an <see cref="NRuuviTag.Mqtt.MqttAgent"/>.
/// </summary>
/// <typeparam name="TListener">
/// The <see cref="IRuuviTagListener"/> that the agent will use to listen for RuuviTag
/// advertisements.
/// </typeparam>
/// <param name="services">
/// The <see cref="IServiceCollection"/>.
/// </param>
/// <param name="configuration">
/// The <see cref="Configuration.IConfiguration"/> for the application.
/// </param>
/// <param name="factory">
/// The factory for creating the <typeparamref name="TListener"/>.
/// </param>
/// <returns>
/// The <see cref="IServiceCollection"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="services"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="configuration"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="factory"/> is <see langword="null"/>.
/// </exception>
public static IServiceCollection AddRuuviTagMqttAgent<TListener>(this IServiceCollection services, IConfiguration configuration, Func<IServiceProvider, TListener> factory) where TListener : class, IRuuviTagListener {
if (services == null) {
throw new ArgumentNullException(nameof(services));
}
if (configuration == null) {
throw new ArgumentNullException(nameof(configuration));
}
if (factory == null) {
throw new ArgumentNullException(nameof(factory));
}

services.Configure<DeviceCollection>(configuration.GetSection("Devices"));

var typeResolver = new TypeResolver();

services.AddSingleton(typeResolver);
services.AddTransient<IMqttFactory, MqttFactory>();
services.AddTransient<IRuuviTagListener, TListener>();
services.AddSingleton(CommandUtilities.BuildCommandApp(typeResolver));

return services;
}

}

}
Loading

0 comments on commit de4e0f6

Please sign in to comment.