dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.49k stars 1.07k forks source link

Add some Powershell example (please!) #1330

Closed ilgrank closed 2 years ago

ilgrank commented 2 years ago

Hi undestand it can be trivial for someone, but not for everyone. I've searched long and not even a single hit returns on Google for using MQTTnet in Powershell Could you please add some basic example? Many thanks!

chkr1011 commented 2 years ago

This library is no PowerShell Module. So working with this library in PowerShell works the same way as working with other .NET Code in PowerShell (https://stackoverflow.com/questions/3079346/how-to-reference-net-assemblies-using-powershell).

Apart from that I cannot help much because I do not use PowerShell that often.

ilgrank commented 2 years ago

Thanks for the quick reply @chkr1011 , I know how to use .NET code in PS, and using the v4.0.0-preview1, I've come this far:

Add-Type -Path "C:\temp\MQTTnet.dll"
$Factory=[MQTTnet.MqttFactory]::new()
$MqttClient=$Factory.CreateMqttClient()
$Options=[MQTTnet.Client.MqttClientOptionsBuilder]::new().WithClientId("Client1").WithTcpServer("test.mosquitto.org").WithCleanSession().Build()
$MqttClient.ConnectAsync($options, [System.Threading.CancellationToken]::None)

but then I try to subscribe to a topic, i.e.: $MqttClient.SubscribeAsync([MQTTnet.Client.MqttClientSubscribeOptionsBuilder]::new().WithTopic('Sample').Build()) I cannot proceed since [MQTTnet.Client.MqttClientSubscribeOptionsBuilder]::new()

has only these methods:

   TypeName: MQTTnet.Client.MqttClientSubscribeOptionsBuilder

Name                       MemberType Definition
----                       ---------- ----------
Build                      Method     MQTTnet.Client.MqttClientSubscribeOptions Build()

WithSubscriptionIdentifier Method     MQTTnet.Client.MqttClientSubscribeOptionsBuilder WithSubscriptionIdentifier(uint32 subscriptionIdentifier)
WithTopicFilter            Method     MQTTnet.Client.MqttClientSubscribeOptionsBuilder WithTopicFilter(string topic, MQTTnet.Protocol.MqttQuality...
WithUserProperty           Method     MQTTnet.Client.MqttClientSubscribeOptionsBuilder WithUserProperty(string name, string value)

(ie: is lacking the ".WithTopic()").

I'm following the guide here: [https://github.com/dotnet/MQTTnet/wiki/Client] (https://github.com/dotnet/MQTTnet/wiki/Client) and this guide seems to be up to date, since 3.11 is lacking MQTTnet.Client.MqttClientOptionsBuilder ...

diputssi commented 2 years ago

I was able to get a bit further, so I'm adding additional steps here. Looks like you can use the with topic filter method instead of WithTopic.

$topic = [MQTTnet.MqttTopicFilterBuilder]::new().WithTopic('testnode/#').build()

Then create a subscribe options object with the topic filter.

$SubscribeOptions = [MQTTnet.Client.MqttClientSubscribeOptionsBuilder]::new().WithTopicFilter( $topic ).Build()

Then I attempt to get at the awaiter object, but it finishes before I can get await on the results.

Sometimes you can see the awaiter not finish.

$awaiter = $MqttClient.SubscribeAsync($SubscribeOptions).getawaiter(); $Awaiter; $Awaiter

Basically, I don't know how to do await tasks in PowerShell without having the SubscribeAsync trigger and finish before I set up the callback. Maybe someone else can help us in setting up the callback first.

I currently get around all of this .Net nonsense by using a PowerShell wrapper around a python object based on paho. But of course less than ideal.

ilgrank commented 1 year ago

To @diputssi and anyone else ending here, seeking to use the only (as today) actively maintained .NET MQTT library: Is kind of possible to use MQTTNet in powershell, but (afaik) there's no way to register the message events, hence you will be able to publish messages into topics, but not be able to receive them since: Register-ObjectEvent -inputObject $MqttClient -EventName ApplicationMessageReceivedAsync -Action {write-host "-" } will error out: Register-ObjectEvent : Cannot register for the specified event. Events that require a return value are not supported. and adding the event 'the old fashioned way', ie: $MqttClient.Add_ApplicationMessageReceivedAsync({write-host "-"; return $null }) will simply not trigger at all.

That said, if sending messages is all you need, the following code is working: (tested with MQTTnet 4.1.x, Powershell 5.1, Win 10 21H2. You can find pre-compiled DLLs on Nuget)

Add-Type -Path .\MQTTnet.dll
$MQTTClient=[MQTTnet.MqttFactory]::new().CreateMqttClient()
$ClientOptions=[MQTTnet.Client.MqttClientOptionsBuilder]::new().WithClientId("Client1").WithTcpServer("test.mosquitto.org").WithCleanSession().Build()
$MQTTClient.ConnectAsync($ClientOptions, [System.Threading.CancellationToken]::None)
$SubscribeOptions=[MQTTnet.Client.MqttClientSubscribeOptionsBuilder]::new().WithTopicFilter('#').Build()
$MQTTClient.SubscribeAsync($SubscribeOptions,[System.Threading.CancellationToken]::None)
$Message=[MQTTnet.MqttApplicationMessageBuilder]::new().WithTopic("test").WithPayload("hello world!").Build()
$MQTTClient.PublishAsync($Message)

The only fully working library remains M2Mqtt.Net but isn't updated basically since 2015 and in my experience, it does suffer from hangs/crashes alas.

chkr1011 commented 1 year ago

We may create a proper PowerShell module. It may be way easier to use then importing importing this library manually.

ilgrank commented 1 year ago

We may create a proper PowerShell module. It may be way easier to use then importing importing this library manually.

That would be awesome, as currently there's no viable alternative for Powershell users. I'm keeping my fingers crossed :)

(btw, I updated the previous post with details on the inability of Powershell to handle the events generated by MQTTNet.)

ilgrank commented 10 months ago

We may create a proper PowerShell module. It may be way easier to use then importing importing this library manually.

Sorry to necro this issue, has there been any update on this matter?

Also, for anyone coming here looking for help: I tested the code above in Powershell 5.1 and recently in Powershell 7.4 Preview 1, with the same results (ie: Register-ObjectEvent: Cannot register for the specified event. Events that require a return value are not supported. (Parameter 'eventName')