diff --git a/AssetTrackerDemo.sln b/AssetTrackerDemo.sln index cd78630..a6a2082 100644 --- a/AssetTrackerDemo.sln +++ b/AssetTrackerDemo.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.1.31911.260 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetTrackerDemo", "AssetTrackerDemo\AssetTrackerDemo.csproj", "{252E24A5-0AC7-4AE7-9CD8-195F7A562D71}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetTrackerDevice", "AssetTrackerDevice\AssetTrackerDevice.csproj", "{AFF7C0F0-3529-45C5-9238-598BD0AACCF1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {252E24A5-0AC7-4AE7-9CD8-195F7A562D71}.Debug|Any CPU.Build.0 = Debug|Any CPU {252E24A5-0AC7-4AE7-9CD8-195F7A562D71}.Release|Any CPU.ActiveCfg = Release|Any CPU {252E24A5-0AC7-4AE7-9CD8-195F7A562D71}.Release|Any CPU.Build.0 = Release|Any CPU + {AFF7C0F0-3529-45C5-9238-598BD0AACCF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFF7C0F0-3529-45C5-9238-598BD0AACCF1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFF7C0F0-3529-45C5-9238-598BD0AACCF1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFF7C0F0-3529-45C5-9238-598BD0AACCF1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AssetTrackerDevice/AssetTrackerDevice.csproj b/AssetTrackerDevice/AssetTrackerDevice.csproj new file mode 100644 index 0000000..640a5ac --- /dev/null +++ b/AssetTrackerDevice/AssetTrackerDevice.csproj @@ -0,0 +1,19 @@ + + + + net6.0-windows10.0.17763.0 + disable + enable + dotnet-AssetTrackerDevice-FE8FBA84-5816-4675-B918-12C1B9B0838C + + + + + + + + + XFAssetTracker.json + + + diff --git a/AssetTrackerDevice/DeviceRunner.cs b/AssetTrackerDevice/DeviceRunner.cs new file mode 100644 index 0000000..23a66bf --- /dev/null +++ b/AssetTrackerDevice/DeviceRunner.cs @@ -0,0 +1,69 @@ +using dtmi_assettrackerdemo; +using Rido.IoTClient; +using Rido.IoTClient.AzIoTHub; + +namespace AssetTrackerDevice +{ + public class DeviceRunner : BackgroundService + { + private readonly ILogger _logger; + private readonly IConfiguration _configuration; + + public DeviceRunner(ILogger logger, IConfiguration configuration) + { + _logger = logger; + _configuration = configuration; + } + + const int default_interval = 5; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + var locator = new Windows.Devices.Geolocation.Geolocator(); + var client = await xfassettrackert0.CreateAsync(_configuration.GetConnectionString("cs"), stoppingToken); + + client.Command_Reboot.OnCmdDelegate = async (cmd) => + { + _logger.LogInformation("Command Reboot received"); + return await Task.FromResult(new Rido.IoTClient.EmptyCommandResponse()); + }; + + client.Property_Interval.OnProperty_Updated = async p => + { + _logger.LogInformation($"Property Desired Prop received: {p.Name}: {p.Value} v {p.Version}"); + var ack = new PropertyAck(p.Name) + { + Value = p.Value, + Status = 200, + Version = p.Version, + Description = "property accepted" + }; + client.Property_Interval.PropertyValue.Value = p.Value; + return await Task.FromResult(ack); + }; + + await client.Property_Interval.InitPropertyAsync(client.InitialState, default_interval, stoppingToken); + + client.Property_FrameworkVersion.PropertyValue = Environment.Version.ToString(); + client.Property_Manufacturer.PropertyValue = "Contoso"; + client.Property_SDKVersion.PropertyValue = (typeof(IoTHubPnPClient).Assembly.GetName().Version.ToString()); + + await client.ReportPropertyAsync(client.AllReadOnlyProperties, stoppingToken); + + _logger.LogInformation("Loop started with interval: " + client.Property_Interval.PropertyValue.Value); + while (!stoppingToken.IsCancellationRequested) + { + var location = await locator.GetGeopositionAsync(); + await client.Telemetry_Location.SendTelemetryAsync(new Location + { + lat = location.Coordinate.Latitude, + lon = location.Coordinate.Longitude, + alt = location.Coordinate.Altitude.Value + + }); + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); + await Task.Delay(client.Property_Interval.PropertyValue.Value * 1000, stoppingToken); + } + } + } +} \ No newline at end of file diff --git a/AssetTrackerDevice/Program.cs b/AssetTrackerDevice/Program.cs new file mode 100644 index 0000000..2b6b584 --- /dev/null +++ b/AssetTrackerDevice/Program.cs @@ -0,0 +1,10 @@ +using AssetTrackerDevice; + +IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddHostedService(); + }) + .Build(); + +await host.RunAsync(); diff --git a/AssetTrackerDevice/Properties/launchSettings.json b/AssetTrackerDevice/Properties/launchSettings.json new file mode 100644 index 0000000..6fc3b2b --- /dev/null +++ b/AssetTrackerDevice/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "AssetTrackerDevice": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development", + "ConnectionStrings__cs": "IdScope=0ne0047D00B;DeviceId=rido-tracker-01;SharedAccessKey=81gPeOIot+L2cwwOwgnaRBuzqpzihpKurt2nGmp28YU=" + } + } + } +} diff --git a/AssetTrackerDevice/XFAssetTracker.json b/AssetTrackerDevice/XFAssetTracker.json new file mode 100644 index 0000000..0e3a71e --- /dev/null +++ b/AssetTrackerDevice/XFAssetTracker.json @@ -0,0 +1,80 @@ +[ + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0;1", + "@type": "Interface", + "contents": [ + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:Location;1", + "@type": [ + "Telemetry", + "Location" + ], + "displayName": { + "en": "Location" + }, + "name": "Location", + "schema": "geopoint" + }, + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:Interval;1", + "@type": [ + "Property", + "TimeSpan" + ], + "displayName": { + "en": "Interval" + }, + "name": "Interval", + "schema": "integer", + "unit": "second", + "writable": true + }, + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:Reboot;1", + "@type": "Command", + "commandType": "synchronous", + "displayName": { + "en": "Reboot" + }, + "name": "Reboot" + }, + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:FrameworkVersion;1", + "@type": "Property", + "displayName": { + "en": "FrameworkVersion" + }, + "name": "FrameworkVersion", + "schema": "string", + "writable": false + }, + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:SDKVersion;1", + "@type": "Property", + "displayName": { + "en": "SDKVersion" + }, + "name": "SDKVersion", + "schema": "string", + "writable": false + }, + { + "@id": "dtmi:assetTrackerDemo:XFAssetTrackert0:Manufacturer;1", + "@type": "Property", + "displayName": { + "en": "Manufacturer" + }, + "name": "Manufacturer", + "schema": "string", + "writable": false + } + ], + "displayName": { + "en": "XFAssetTracker" + }, + "@context": [ + "dtmi:iotcentral:context;2", + "dtmi:dtdl:context;2" + ] + } +] \ No newline at end of file diff --git a/AssetTrackerDevice/appsettings.Development.json b/AssetTrackerDevice/appsettings.Development.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/AssetTrackerDevice/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/AssetTrackerDevice/appsettings.json b/AssetTrackerDevice/appsettings.json new file mode 100644 index 0000000..b2dcdb6 --- /dev/null +++ b/AssetTrackerDevice/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/AssetTrackerDevice/dtmi_assettrackerdemo_xfassettrackert0-1.g.cs b/AssetTrackerDevice/dtmi_assettrackerdemo_xfassettrackert0-1.g.cs new file mode 100644 index 0000000..5513567 --- /dev/null +++ b/AssetTrackerDevice/dtmi_assettrackerdemo_xfassettrackert0-1.g.cs @@ -0,0 +1,56 @@ +// + +using MQTTnet.Client; +using Rido.IoTClient; +using Rido.IoTClient.AzIoTHub; +using Rido.IoTClient.AzIoTHub.TopicBindings; +using System.Reflection.Metadata; + +namespace dtmi_assettrackerdemo +{ + public class xfassettrackert0 : IoTHubPnPClient + { + const string modelId = "dtmi:assetTrackerDemo:XFAssetTrackert0;1"; + + public Telemetry Telemetry_Location; + public WritableProperty Property_Interval; + public Command Command_Reboot; + public ReadOnlyProperty Property_FrameworkVersion; + public ReadOnlyProperty Property_SDKVersion; + public ReadOnlyProperty Property_Manufacturer; + + public xfassettrackert0(IMqttClient c) : base(c) + { + Property_Interval = new WritableProperty(c, "Interval"); + Telemetry_Location = new Telemetry(c, "Location"); + Command_Reboot = new Command(c, "Reboot"); + Property_FrameworkVersion = new ReadOnlyProperty(c, "FrameworkVersion"); + Property_SDKVersion = new ReadOnlyProperty(c, "SDKVersion"); + Property_Manufacturer = new ReadOnlyProperty(c, "Manufacturer"); + } + + public static async Task CreateAsync(string connectionString, CancellationToken cancellationToken) + { + var cs = new ConnectionSettings(connectionString) { ModelId = modelId }; + var client = new xfassettrackert0(await IoTHubConnectionFactory.CreateAsync(cs, cancellationToken)) { ConnectionSettings = cs }; + client.InitialState = await client.GetTwinAsync(cancellationToken); + return client; + } + + public Dictionary AllReadOnlyProperties => new Dictionary() + { + { Property_FrameworkVersion.Name, Property_FrameworkVersion.PropertyValue }, + { Property_SDKVersion.Name, Property_SDKVersion.PropertyValue }, + { Property_Manufacturer.Name, Property_Manufacturer.PropertyValue } + }; + + + } + + public struct Location + { + public double lat { get; set; } + public double lon { get; set; } + public double alt { get; set; } + } +}