Skip to content

Commit

Permalink
Prep 0.4 (#62)
Browse files Browse the repository at this point in the history
* squash big refactor

* clean TwinInitializer

* review tests

* add payload sample

* add avro

* add memmon proto

* sync with ux

* upd links for ux
  • Loading branch information
ridomin authored Sep 29, 2022
1 parent f1f10b2 commit d9fc104
Show file tree
Hide file tree
Showing 189 changed files with 3,427 additions and 2,718 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
6.0.x
3.1.x
dotnet-version: 6.0.x

- name: Restore dependencies
run: dotnet restore
Expand Down
14 changes: 14 additions & 0 deletions MQTTnet.Extensions.MultiCloud.sln
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mqtt-device", "samples\mqtt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mqtt-grpc-device", "samples\mqtt-grpc-device\mqtt-grpc-device.csproj", "{AF019503-8813-4967-B858-0DDAE43C2073}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "payload-size", "samples\payload-size\payload-size.csproj", "{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "memmon-protobuff", "samples\memmon-protobuff\memmon-protobuff.csproj", "{20B75646-CBD2-4E72-8C56-22887A519FA3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -108,6 +112,14 @@ Global
{AF019503-8813-4967-B858-0DDAE43C2073}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF019503-8813-4967-B858-0DDAE43C2073}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF019503-8813-4967-B858-0DDAE43C2073}.Release|Any CPU.Build.0 = Release|Any CPU
{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4}.Release|Any CPU.Build.0 = Release|Any CPU
{20B75646-CBD2-4E72-8C56-22887A519FA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20B75646-CBD2-4E72-8C56-22887A519FA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20B75646-CBD2-4E72-8C56-22887A519FA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20B75646-CBD2-4E72-8C56-22887A519FA3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -120,6 +132,8 @@ Global
{CF342B46-3B96-4270-8881-70FF105DE8E4} = {F5E59EDE-6E77-484C-AB93-C4651F43B9A7}
{F0DE9E2F-0E87-4C2C-875B-79547FD957D6} = {F5E59EDE-6E77-484C-AB93-C4651F43B9A7}
{AF019503-8813-4967-B858-0DDAE43C2073} = {F5E59EDE-6E77-484C-AB93-C4651F43B9A7}
{DF590535-2FDC-4A0A-9EE4-7C9BF818C7B4} = {F5E59EDE-6E77-484C-AB93-C4651F43B9A7}
{20B75646-CBD2-4E72-8C56-22887A519FA3} = {F5E59EDE-6E77-484C-AB93-C4651F43B9A7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {09914DD8-50B2-48E3-B9AB-7764AE36AD6B}
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
### Using `test.mosquitto.org`

- Navigate to the Memory Monitor sample in `samples/memmon` and run it with `dotnet run` (or in Visual Studio hit `F5`). The console app will connect by default to `test.mosquitto.org:8886` (encrypted/no auth) by default.
- Browse to [https://iotmodels.github.io/pnp-mqtt](https://iotmodels.github.io/pnp-mqtt) and connect to `test.mosquitto.org:8081` (websockets, encrypted/no auth)
- Browse to [https://iotmodels.github.io/iotux-mqtt](https://iotmodels.github.io/iotux-mqtt) and connect to `test.mosquitto.org:8081` (websockets, encrypted/no auth)
- You should see a list of devices, select a device matching your machine name. Invoke the command, or change a property. The console application should show those changes.

![test.mosquitto.org](docs/tmo.gif)
Expand All @@ -28,7 +28,7 @@
- The same app can be executed with a local mosquitto server, you can use a pre-configured docker image like: [mosquitto-local](https://github.com/ridomin/mosquitto-local)
- Start mosquitto with `docker run -it --rm -p 8080:8080 -p 1883:1883 -p 8883:8883 -p 8884:8884 -p 8443:8443 ridomin/mosquitto-local:dev`
- Update the connection settings: `dotnet run /ConnectionSettings:cs="HostName=localhost;TcpPort=8883;ClientId=memmon-device;Username=user;Password=password;CaFile=RidoFY23CA.crt"`
- Connect [https://iotmodels.github.io/pnp-mqtt](https://iotmodels.github.io/pnp-mqtt) to `localhost:8443` to interact with your device
- Connect [https://iotmodels.github.io/iotux-mqtt](https://iotmodels.github.io/iotux-mqtt) to `localhost:8443` to interact with your device

### Using `Azure IoT Central`

Expand All @@ -53,7 +53,7 @@ Start from this [device-template](https://github.com/iotmodels/device-template/g
2. Create the base libraries to implement the DTDL interface for each cloud vendor. See the [Memory Monitor sample](samples/memmon/dtmi_rido_pnp_memmon-1.g.cs)
3. Implement the device logic, by using the interface, the device logic can be reused across different cloud vendor implementations. [Device Logic](samples/memmon/Device.cs)
4. Connect the device using different [Connection Settings](docs/ConnectionSettings.md)
5. Interact with the device with a DTDL enabled solution. Like [Azure IoT Central](https://www.azureiotcentral.com), [IoTExplorer](https://docs.microsoft.com/en-us/azure/iot-fundamentals/howto-use-iot-explorer) or [Pnp-Mqtt](https://iotmodels.github.io/pnp-mqtt/)
5. Interact with the device with a DTDL enabled solution. Like [Azure IoT Central](https://www.azureiotcentral.com), [IoTExplorer](https://docs.microsoft.com/en-us/azure/iot-fundamentals/howto-use-iot-explorer) or [Pnp-Mqtt](https://iotmodels.github.io/iotux-mqtt/)


## TL;DR;
Expand All @@ -69,7 +69,7 @@ This repo focuses on the first part: how to implement things/devices that can wo
- Commands. To invoke specific actions in the device from the solution, acka _c2d messages_
- Properties. To manage the device state, reported by the _device_ and optionally being managed from the _solution_. eg How often the telemetry must be sent. _d2c+c2d messages_

3. Enable solutions to reflect those _interaction patterns_ to create UI experiences, IoT Central, IoTExplorer or [Pnp-Mqtt](https://iotmodels.github.io/pnp-mqtt/) are examples of PnP enabled solutions.
3. Enable solutions to reflect those _interaction patterns_ to create UI experiences, IoT Central, IoTExplorer or [Pnp-Mqtt](https://iotmodels.github.io/iotux-mqtt/) are examples of PnP enabled solutions.

Read the [IoT Plug and Play convention](https://docs.microsoft.com/azure/iot-develop/overview-iot-plug-and-play) for more details.

Expand Down
36 changes: 0 additions & 36 deletions Scratch/Scratch.sln

This file was deleted.

35 changes: 35 additions & 0 deletions samples/iot-device/ClientHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using MQTTnet.Client;
using MQTTnet.Extensions.MultiCloud;
using MQTTnet.Extensions.MultiCloud.AzureIoTClient.TopicBindings;
using MQTTnet.Extensions.MultiCloud.AzureIoTClient.Untyped;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Telemetry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace iot_device
{
internal class ClientHub
{
TwinRequestResponseBinder rr;

public ITelemetry<double> Temperature;
public IReadOnlyProperty<string> SdkInfo;
public ICommand<string, string> Echo;
public IWritableProperty<int> Interval;

public ClientHub(IMqttClient c)
{
rr = new TwinRequestResponseBinder(c);
Temperature = new HubTelemetryUTF8Json<double>(c, "temp");
SdkInfo = new HubReadOnlyPropertyUTFJson<string>(c, "sdkInfo");
Echo = new HubCommandUTF8Json<string, string>(c, "echo");
Interval = new HubWritablePropertyUTFJson<int>(c, "interval");
}

internal async Task<string> GetTwinAsync(CancellationToken cancellationToken = default)
=> await rr.GetTwinAsync(cancellationToken);
}
}
21 changes: 21 additions & 0 deletions samples/iot-device/ClientMsgPack.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using MQTTnet.Client;
using MQTTnet.Extensions.MultiCloud;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Command;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.ReadOnlyProperty;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Telemetry;

namespace iot_device;

internal class ClientMsgPack
{
public ITelemetry<double> Temperature;
public IReadOnlyProperty<string> SdkInfo;
public ICommand<int, string> EchoRepeater;

public ClientMsgPack(IMqttClient c)
{
Temperature = new TelemetryMsgPack<double>(c, "temperature");
SdkInfo = new ReadOnlyPropertyMessagePack<string>(c, "sdkInfo");
EchoRepeater = new CommandMsgPack<int, string>(c, "echoRepeater");
}
}
25 changes: 25 additions & 0 deletions samples/iot-device/ClientProtobuff.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using device_template_protos;
using MQTTnet.Client;
using MQTTnet.Extensions.MultiCloud;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Command;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.ReadOnlyProperty;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Telemetry;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.WritableProperty;

namespace iot_device;

internal class ClientProtobuff
{
public ITelemetry<Telemetries> Temperature;
public IReadOnlyProperty<Properties> SdkInfo;
public ICommand<echoRequest, echoResponse> Echo;
public IWritableProperty<Properties, ack> Interval;

public ClientProtobuff(IMqttClient c)
{
Temperature = new TelemetryProtobuff<Telemetries>(c, "temp");
SdkInfo = new ReadOnlyPropertyProtobuff<Properties>(c, "sdkInfo");
Echo = new CommandProtobuff<echoRequest, echoResponse>(c, "echo", echoRequest.Parser);
Interval = new WritablePropertyProtobuff<Properties, ack>(c, "interval", Properties.Parser);
}
}
24 changes: 24 additions & 0 deletions samples/iot-device/ClientUTF8Json.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using MQTTnet.Client;
using MQTTnet.Extensions.MultiCloud;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Command;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.ReadOnlyProperty;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.Telemetry;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient.WritableProperty;

namespace iot_device;

internal class ClientUTF8Json
{
public ITelemetry<double> Temperature;
public IReadOnlyProperty<string> SdkInfo;
public ICommand<string, string> Echo;
public IWritableProperty<int> Interval;

public ClientUTF8Json(IMqttClient c)
{
Temperature = new TelemetryUTF8Json<double>(c, "temp");
SdkInfo = new ReadOnlyPropertyUTFJson<string>(c, "sdkInfo");
Echo = new CommandUTF8Json<string, string>(c, "echo");
Interval = new WritablePropertyUTFJson<int>(c, "interval");
}
}
76 changes: 76 additions & 0 deletions samples/iot-device/DeviceUtf8.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using MQTTnet.Client;
using MQTTnet.Extensions.MultiCloud.AzureIoTClient;
using MQTTnet.Extensions.MultiCloud.Connections;

using device_template_protos;
using MQTTnet.Extensions.MultiCloud;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient;

namespace iot_device;

public class DeviceUtf8 : BackgroundService
{
private readonly ILogger<DeviceUtf8> _logger;
private readonly IConfiguration _configuration;

private IMqttClient? mqtt;

public DeviceUtf8(ILogger<DeviceUtf8> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}


protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
ConnectionSettings cs = new(_configuration.GetConnectionString("cs") + ";ModelId=dtmi:com:example:DeviceTemplate;1");
mqtt = await BrokerClientFactory.CreateFromConnectionSettingsAsync(cs, true, stoppingToken);
//mqtt = await HubDpsFactory.CreateFromConnectionSettingsAsync(cs, stoppingToken);
_logger.LogInformation($"Connected {cs}");
var client = new ClientUTF8Json(mqtt!);

client.Interval.Value = 5;
await client!.SdkInfo.SendMessageAsync("my SDK testing hub");

client.Interval.OnMessage = async m =>
{
Ack<int> ack = new Ack<int>();
if (m > 0)
{
client.Interval.Value = m;
ack.Status = 200;
ack.Description = "property accepted";
ack.Value = m;
ack.Version = client.Interval.Version;
}
else
{
ack.Status = 403;
ack.Description = $"negative value ({m}) not accepted";
ack.Value = client.Interval.Value;
ack.Version = client.Interval.Version;
}
return await Task.FromResult(ack);
};

client.Echo.OnMessage = async m =>
{
string result = string.Empty;
for (int i = 0; i < 3; i++)
{
result += m;
}
return await Task.FromResult(result);
};

while (!stoppingToken.IsCancellationRequested)
{
await client.Temperature.SendMessageAsync(32.1);
_logger.LogInformation("Worker running at: {time}, enabled {enabled}", DateTimeOffset.Now, true);
await Task.Delay(client.Interval.Value * 1000, stoppingToken);
}
}


}
73 changes: 73 additions & 0 deletions samples/iot-device/DeviceprotoBuff.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using MQTTnet.Client;

using MQTTnet.Extensions.MultiCloud.Connections;

using device_template_protos;
using MQTTnet.Extensions.MultiCloud.BrokerIoTClient;

namespace iot_device;

public class DeviceprotoBuff : BackgroundService
{
private readonly ILogger<DeviceprotoBuff> _logger;
private readonly IConfiguration _configuration;

private IMqttClient? mqtt;

public DeviceprotoBuff(ILogger<DeviceprotoBuff> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}


protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
ConnectionSettings cs = new(_configuration.GetConnectionString("cs") + ";ModelId=device-template.proto");
mqtt = await BrokerClientFactory.CreateFromConnectionSettingsAsync(cs, true, stoppingToken);
_logger.LogInformation($"Connected {cs}");

var client = new ClientProtobuff(mqtt!);

client.Interval.Value = new Properties() { Interval = 5};
await client!.SdkInfo.SendMessageAsync(new Properties { SdkInfo = "my SDK"});

client.Interval.OnMessage = async m =>
{
ack ack = new ack(); //<int>(mqtt!, "interval");
if (m.Interval > 0)
{
client.Interval.Value = m;
ack.Status = 200;
ack.Description = "property accepted";
ack.Value = Google.Protobuf.WellKnownTypes.Any.Pack(m);
}
else
{
ack.Status = 403;
ack.Description = $"negative value ({m}) not accepted";
ack.Value = Google.Protobuf.WellKnownTypes.Any.Pack(client.Interval.Value);
}
return await Task.FromResult(ack);
};

client.Echo.OnMessage = async m =>
{
string result = "echo ";
for (int i = 0; i < 3; i++)
{
result += m.InEcho;
}
return await Task.FromResult(new echoResponse { OutEcho = result});
};

while (!stoppingToken.IsCancellationRequested)
{

await client.Temperature.SendMessageAsync(new Telemetries { Temp = 32.1});

_logger.LogInformation("Worker running at: {time}, enabled {enabled}", DateTimeOffset.Now, true);
await Task.Delay(client.Interval.Value.Interval * 1000, stoppingToken);
}
}
}
2 changes: 1 addition & 1 deletion samples/iot-device/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Device>();
services.AddHostedService<DeviceUtf8>();
})
.Build();

Expand Down
Loading

0 comments on commit d9fc104

Please sign in to comment.