Skip to content

Instantly share code, notes, and snippets.

@ridomin
Last active May 5, 2022 14:51
Show Gist options
  • Save ridomin/8572122aa346e6bedd2ae0de0b95fcd0 to your computer and use it in GitHub Desktop.
Save ridomin/8572122aa346e6bedd2ae0de0b95fcd0 to your computer and use it in GitHub Desktop.
Demystify IoTHub SDKs
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>demistify_iothub</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MQTTnet" Version="3.1.2" />
</ItemGroup>
</Project>
using MQTTnet.Client.Options;
using System.Text;
namespace demistify_iothub
{
public static class MqttNetExtensions
{
public static MqttClientOptionsBuilder WithAzureIoTHubCredentialsSas(this MqttClientOptionsBuilder builder, string hostName, string deviceId, string sasKey, string modelId = "", int sasMinutes = 60)
{
(string username, string password) = SasAuth.GenerateHubSasCredentials(hostName, deviceId, sasKey, modelId, sasMinutes);
builder
.WithTcpServer(hostName, 8883)
.WithTls()
.WithClientId(deviceId)
.WithCredentials(username, password);
return builder;
}
}
}
using demistify_iothub;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using System.Text;
using System.Text.Json;
using System.Web;
// Connect
IMqttClient mqttClient = new MqttFactory().CreateMqttClient();
var connAck = await mqttClient.ConnectAsync(new MqttClientOptionsBuilder()
.WithAzureIoTHubCredentialsSas(
hostName: "rido-freetier.azure-devices.net",
deviceId: "myDevice",
sasKey: "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA="
)
.Build());
Console.WriteLine($"connAck resaon: {connAck.ResultCode} IsConnected: {mqttClient.IsConnected}");
// Telemetry
var pubAck = await mqttClient.PublishAsync(
$"devices/{mqttClient.Options.ClientId}/messages/events/",
JsonSerializer.Serialize(new { Environment.WorkingSet }) );
Console.WriteLine($"Telemetry sent with pubAck: {pubAck.ReasonCode}" );
await mqttClient.SubscribeAsync("$iothub/methods/POST/#");
await mqttClient.SubscribeAsync("$iothub/twin/res/#");
await mqttClient.SubscribeAsync("$iothub/twin/PATCH/properties/desired/#");
mqttClient.UseApplicationMessageReceivedHandler(async m =>
{
var topic = m.ApplicationMessage.Topic;
var segments = topic.Split('/');
// Command
if (topic.StartsWith("$iothub/methods/POST/"))
{
var qs = HttpUtility.ParseQueryString(segments[^1]);
_ = int.TryParse(qs["$rid"], out int rid);
var cmdName = segments[3];
var cmdPayload = Encoding.UTF8.GetString(m.ApplicationMessage.Payload);
Console.WriteLine($"Executing command {cmdName} with rid {rid} and payload {cmdPayload}");
await mqttClient.PublishAsync($"$iothub/methods/res/200/?$rid={rid}", cmdPayload);
}
//GetTwin reponse
if (topic.StartsWith("$iothub/twin/res/200"))
{
var qs = HttpUtility.ParseQueryString(segments[^1]);
_ = int.TryParse(qs["$rid"], out int rid);
var twin = Encoding.UTF8.GetString(m.ApplicationMessage.Payload);
Console.WriteLine(twin);
}
// UpdateTwin response
if (topic.StartsWith("$iothub/twin/res/204"))
{
var qs = HttpUtility.ParseQueryString(segments[^1]);
var twinVersion = Convert.ToInt32(qs["$version"]);
System.Console.WriteLine(twinVersion);
}
if (topic.StartsWith("$iothub/twin/PATCH/properties/desired"))
{
string msg = Encoding.UTF8.GetString(m.ApplicationMessage.Payload);
System.Console.WriteLine(msg);
}
});
await mqttClient.PublishAsync($"$iothub/twin/GET/?$rid=1");
await mqttClient.PublishAsync(
"$iothub/twin/PATCH/properties/reported/?$rid=2",
JsonSerializer.Serialize(new { myProperty = "myValue" }));
Console.ReadLine();
using System.Text;
namespace demistify_iothub
{
public class SasAuth
{
private const string apiversion_2020_09_30 = "2020-09-30";
public static string GetUserName(string hostName, string deviceId, string modelId = "") =>
$"{hostName}/{deviceId}/?api-version={apiversion_2020_09_30}&model-id={modelId}";
private static string Sign(string requestString, string key)
{
using (var algorithm = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(key)))
{
return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(requestString)));
}
}
public static string CreateSasToken(string resource, string sasKey, int minutes)
{
var expiry = DateTimeOffset.UtcNow.AddMinutes(minutes).ToUnixTimeSeconds().ToString();
var sig = System.Net.WebUtility.UrlEncode(Sign($"{resource}\n{expiry}", sasKey));
return $"SharedAccessSignature sr={resource}&sig={sig}&se={expiry}";
}
public static (string username, string password) GenerateHubSasCredentials(string hostName, string deviceId, string sasKey, string modelId, int minutes = 60) =>
(GetUserName(hostName, deviceId, modelId), CreateSasToken($"{hostName}/devices/{deviceId}", sasKey, minutes));
}
}
@rido-min
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment