I've already worked with mqtt in Java. Now I need to create a C# application to subcribe and publish mqtt messages.
using MqttDotNet library
IMqtt _client = MqttClientFactory.CreateClient(connectionString, clientId);
What is the connectionString?
using M2Mqtt library
The connection succeeded, but I did not receive any published messages.
This is my code:
class Program
{
static void Main(string[] args)
{
var client = new MqttClient(IPAddress.Parse("myTestIP"));
// register to message received
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
var clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
// subscribe to the topic "/home/temperature" with QoS 2
client.Subscribe(
new string[] {"testTopic"},
new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
}
static void client_MqttMsgPublishReceived(
object sender, MqttMsgPublishEventArgs e)
{
// handle message received
Console.WriteLine("message=" + e.Message.ToString());
}
}
This my message publishing code:
mosquitto_pub -d -h testIp -t "testTopic" -m "haai"
I don't think that the MqttDotNet is currently mantained.
I could suggest to use my M2Mqtt client and found documentation on official web site here :
https://m2mqtt.wordpress.com/
The M2Mqtt client is available on Nuget as package too here :
https://www.nuget.org/packages/M2Mqtt/
Paolo.
The connection string is (according to the sample code documentation on Steven Lovegroves website http://www.stevenlovegrove.com/?id=37):
Connection Strings
TCP connection, eg. tcp://brokerhost.com:1883
Bluetooth connection, eg. bt://00:10:dc:af:66:48
Related
I have a project creating a websocket client side (Subscriber) to a MQTT publisher. I am quite new to C# and MQTT protocol. I follow some youtube video to make finish my very first lines connecting to this MQTT publisher to get all the train going in and out Helsinki station.
broker: "rata.digitraffic.fi"
Port: 80
Topic: trains-by-station/HKI (HKI abbr for Helsinki)
I use M2Mqtt library in dotnet to build the subscriber, somehow the client_MqttMsgPublishReceived function is never triggered. the client.IsConnected always returned false value!
You can find info of this mqtt protocol in the url below.
https://www.digitraffic.fi/rautatieliikenne/#websocket-mqtt
It gives me example in JavaScripts and it seems to run fine with the example of each MQTT. But when I tried to do it with my PC, it doesn't give me any thing, but
Hello World!!!
False
and the cmd window on hold.
SOOOO FRUSTRATING right now. it would be much appreciate if anyone can help me out.
BTW, I am using win10, I tried with dotnet 4/5/6 and m2mqtt 4.3.0.
using System.Text;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System;
namespace m2qttSubscriber
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!!!!");
MqttClient client = new MqttClient("rata.digitraffic.fi",
80,
false,
MqttSslProtocols.None,
null,
null);
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
string clientID = "myclientid_" + RandomDigits(4);
client.Connect(clientID);
Console.WriteLine(client.IsConnected);
client.Subscribe(new string[] { "trains-by-station/HKI" },
new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE}) ;
}
static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
Console.WriteLine("SOme thing is received");
string payload = Encoding.Default.GetString(e.Message);
Console.WriteLine("Recevied {0} from", payload);
}
static public string RandomDigits(int length)
{
var random = new Random();
string s = string.Empty;
for (int i = 0; i < length; i++)
s = String.Concat(s, random.Next(10).ToString());
return s;
}
}
}
As per the comments the library used (uPLibrary.Networking.M2Mqtt) does not support MQTT over Websockets (which is what rata.digitraffic.fi:80 offers).
If you are able to use standard MQTT (over TCP/IP) then rata-mqtt.digitraffic.fi:1883 works (OP succeeded with MqttClient client = new MqttClient("rata-mqtt.digitraffic.fi", 1883, false, MqttSslProtocols.None, null, null);) and this is generally preferable to using WebSockets (there are some situations where you have to use WebSockets; e.g. code running in a browser or to bypass some filters/proxies).
Alternatively there are other libraries that do offer support for MQTT over Websockets.
I am trying to send a message to ActiveMQ from a sender written in C# and then trying to receive the message on an android device running ActiveMQ Client.
I was not able to do this. Any help will be appreciated.
I am using the paho eclipse client.
Here is my code:
//Connection with the server
private void connect() {
MqttConnectOptions connectOptions = new MqttConnectOptions();
connectOptions.setAutomaticReconnect(true);
client = new MqttAndroidClient(this, serverURI, clientId);
try {
client.connect(connectOptions, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
publishBtn.setEnabled(true);
subscribe();
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable e) {
e.printStackTrace();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
Yes, you can do this as long as you have configured the broker to add an MQTT Transport endpoint. You will also need to ensure your device can reach the broker which could be behind a firewall or other security measures so configuration here is key. The ActiveMQ 5.x broker configuration for MQTT is documented here.
Azure IoT Hub Supports AMQP, MQTT, HTTP protocols. In order to customize these protocols we have Azure IoT protocol gateway. I can find good samples on MQTT protocol customization. I need some sample codes for TCP based protocol customization using Azure IoT Protocol Gateway.
EDIT (in order to get an answer): what the OP was asking, is an example using the Azure Protocol Gateway to support a proprietary TCP-based protocol. Currently the IoT hub only supports AMQP, MQTT and HTTP. While those protocols actually rely on TCP, the hub doesn't support direct TCP connection without the extra layer of AMQP, MQTT or HTTP.
As explained here, we need a basic example of a custom TCP based protocol.
Imagine a basic device that can only send some proprietary payload through TCP on a given IP address/port: we need an example of a gateway customization that allows this device to send data to the hub.
The current code of the protocol gateway is poorly designed, as it heavily relies on MQTT.
Adding some bounty too.
The default Protocol Gateway sample are indeed somewhat confusing because of all the MQTT code.
The protocol gateway works by 'simulating' a IoTHub connection for each custom protocol device you connect to the gateway.
To do this translation from the TCP device to an IoTHub device you first need to have a connection to the IoTHub on behalf of the device. This is the gateway part.
Below is the core essentials for this IoTHubConnection.
namespace GatewayTest
{
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotNetty.Buffers;
using Microsoft.Azure.Devices.ProtocolGateway.Identity;
using Microsoft.Azure.Devices.ProtocolGateway.IotHubClient;
using Microsoft.Azure.Devices.ProtocolGateway.Messaging;
public class IoTHubConnection : IMessagingChannel<IMessage>
{
private readonly string iotHubHostName;
private readonly Func<IDeviceIdentity, Task<IMessagingServiceClient>> deviceClientFactory;
private readonly Func<string, Task> onMessage;
private IMessagingServiceClient deviceClient;
private IDeviceIdentity deviceIdentity;
public IoTHubConnection(
string iotHubHostName,
Func<IDeviceIdentity, Task<IMessagingServiceClient>> deviceClientFactory,
Func<string, Task> onMessage)
{
this.iotHubHostName = iotHubHostName;
this.deviceClientFactory = deviceClientFactory;
this.onMessage = onMessage;
}
public event EventHandler CapabilitiesChanged;
public async Task OpenAsync(string deviceId, string deviceKey)
{
this.deviceIdentity = this.GetDeviceIdentity(deviceId, deviceKey);
if (this.deviceIdentity != UnauthenticatedDeviceIdentity.Instance)
{
this.deviceClient = await this.deviceClientFactory(this.deviceIdentity);
this.deviceClient.BindMessagingChannel(this);
}
}
public async Task CloseAsync()
{
await this.deviceClient.DisposeAsync(null);
this.deviceClient = null;
}
public void Handle(IMessage message)
{
var messageBody = message.Payload.ToString(Encoding.UTF8);
this.onMessage(messageBody);
this.deviceClient.CompleteAsync(message.Id);
}
public Task SendMessage(string message)
{
var buffer = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(message));
var deviceMessage = this.deviceClient.CreateMessage($"devices/{this.deviceIdentity.Id}/messages/events", buffer);
return this.deviceClient.SendAsync(deviceMessage);
}
protected virtual void OnCapabilitiesChanged(EventArgs e)
{
this.CapabilitiesChanged?.Invoke(this, e);
}
private IDeviceIdentity GetDeviceIdentity(string userName, string deviceKey)
{
IotHubDeviceIdentity ideviceIdentity;
if (!IotHubDeviceIdentity.TryParse($"{this.iotHubHostName}/{userName}", out ideviceIdentity))
{
return UnauthenticatedDeviceIdentity.Instance;
}
ideviceIdentity.WithDeviceKey(deviceKey);
return ideviceIdentity;
}
}
}
The deviceClientFactory callback method should be implemented as shown below and in this line in the ProtocolGateway repo in Github.
deviceClientFactory = IotHubClient.PreparePoolFactory(
"IotHubConnectionString",
400,
TimeSpan.FromMinutes(3),
iotHubClientSettings,
PooledByteBufferAllocator.Default,
new ConfigurableMessageAddressConverter("TopicNameConversion"));
When a Tcp Device connects to the protocol, you should create an instance of this IoTHubConnection and send messages from the Device to the IoTHubConnection and vica versa.
The code below shows a very simple version of how this should be done.
private const int BufferSize = 1024;
private byte[] buffer = new byte[BufferSize];
private IoTHubConnection ioTHubConnection;
private NetworkStream stream;
private async Task Start()
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
var client = await listener.AcceptTcpClientAsync();
ioTHubConnection = new IoTHubConnection("IoTHubName", deviceClientFactory, OnIoTHubMessage);
stream = client.GetStream();
// Read DeviceId and DeviceKey from some sort of StartConnection-message send by the TcpClient.
await ioTHubConnection.OpenAsync("DeviceId", "DeviceKey");
stream.BeginRead(buffer, 0, BufferSize, ReadTcpStreamCallback, null);
}
private void ReadTcpStreamCallback(IAsyncResult ar)
{
var bytesRead = stream.EndRead(ar);
if (bytesRead > 0)
{
var message = System.Text.Encoding.ASCII.GetString(result);
ioTHubConnection.SendMessage(message);
// Read again.
stream.BeginRead(buffer, 0, BufferSize, ReadTcpStreamCallback, null);
}
}
private async Task OnIoTHubMessage(string message)
{
// Potentially do some translation on the IoTHub message
// and send it to the Device
var byteData = Encoding.UTF8.GetBytes(message);
stream.BeginWrite(byteData, 0, byteData.Length, SendTcpCallback, null);
}
private void SendTcpCallback(IAsyncResult ar)
{
stream.EndWrite(ar);
}
I know I am late to this conversation. However I have interesting add on or might be a solution for some.
Azure IoT Gateway is now known as Azure IoT Edge, this is clearly mentioned in the following Azure github repo
https://github.com/Azure/iot-edge-modbus.git
On the other hand, Azure IoT Edge supports TCP for some protocols which can be found in the following links
https://learn.microsoft.com/en-us/azure/iot-edge/deploy-modbus-gateway
https://learn.microsoft.com/en-us/azure/iot-edge/iot-edge-as-gateway
I have created a Notification Hub using this guide and these instructions (for how to add Firebase to Azure).
When I send using Test Send on Azure, the push notification is send successfully. But when I send it using their Console Example in the previous mentioned guide, it simply crashes when using SendGcmNativeNotificationAsync-method.
What can be wrong?
My namespace contains letters and a -, but my name for the hub contains _ too. Can that be the problem (and if it is, why did they not tell me during creation)?
EDIT: Modified code
var connectionStr = ServiceBusConnectionStringBuilder.CreateUsingSharedAccessKey(new Uri({uri}), "DefaultSendSharedAccessSignature", "Ln4em6ZqeukRS3y1Hgq/3m5V2S51IBIkG7tk+MAfO/Y=");
var hub = NotificationHubClient.CreateClientFromConnectionString(connectionStr, {hub-name});
await hub.SendGcmNativeNotificationAsync("{ \"data\" : {\"message\":\"Hello from Azure!\"}}");
Console.ReadLine();
Try something like this:
private static async void SendNotificationAsync()
{
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString("<connection string with full access>", "<hub name>");
var notif = "{ \"data\" : {\"message\":\"" + "Hola" + "\"}}";
await hub.SendGcmNativeNotificationAsync(notif);
}
Obtained from: http://www.c-sharpcorner.com/blogs/sending-notification-from-a-console-application-using-notification-hubs
The connection string can be found in your Notification Hub (Access Policies):
It worked for me for a simple console App Test.
I need to send a message to Azure Iot Hub (https://azure.microsoft.com/it-it/services/iot-hub/) from an Universal App installed in my Raspberry. I've to use HTTP protocol because Raspberry doesn't supports AMQP.
I use the following code:
public sealed partial class MainPage : Page
{
private DispatcherTimer _timer = null;
private DeviceClient _deviceClient = null;
private const string _deviceConnectionString = "<myConnectionString>";
public MainPage()
{
InitializeComponent();
_deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionString, TransportType.Http1);
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(5);
_timer.Tick += _timer_Tick;
_timer.Start();
}
private async void _timer_Tick(object sender, object e)
{
string msg = "{deviceId: 'myFirstDevice', timestamp: " + DateTime.Now.Ticks + " }";
Message eventMessage = new Message(Encoding.UTF8.GetBytes(msg));
await _deviceClient.SendEventAsync(eventMessage);
}
}
SendEventAsync gives me:
Exception thrown: 'Microsoft.Azure.Devices.Client.Exceptions.IotHubCommunicationException' in mscorlib.ni.dll
Message: {"An error occurred while sending the request."}
I've included in my project Microsoft.AspNet.WebApi.Client as documented here: https://github.com/Azure/azure-iot-sdks/issues/65 with no results.
"dependencies": {
"Microsoft.AspNet.WebApi.Client": "5.2.3",
"Microsoft.Azure.Devices.Client": "1.0.0-preview-007",
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
},
"frameworks": {
"uap10.0": {}
}
If I try the SAME code in a Console application it works as expected.
#danvy is right you need to generate a SAS token,here is a signature generator https://github.com/sandrinodimattia/RedDog/releases
There could be multiple ways to send events, you are using http, check out this sample
// Generate a SAS key with the Signature Generator.:
var sas = "SharedAccessSignature sr=https%3a%2f%2freddogeventhub.servicebus.windows.net%2ftemperature%2fpublishers%2flivingroom%2fmessages&sig=I7n%2bqlIExBRs23V4mcYYfYVYhc6adOlMAeTY9VM9kNg%3d&se=1405562228&skn=SenderDevice";
// Namespace info.
var serviceNamespace = "myeventhub";
var hubName = "temperature";
var deviceName = "livingroom";
// Create client.
var httpClient = new HttpClient();
httpClient.BaseAddress =
new Uri(String.Format("https://{0}.servicebus.windows.net/", serviceNamespace));
httpClient.DefaultRequestHeaders
.TryAddWithoutValidation("Authorization", sas);
Console.WriteLine("Starting device: {0}", deviceName);
// Keep sending.
while (true)
{
var eventData = new
{
Temperature = new Random().Next(20, 50)
};
var postResult = httpClient.PostAsJsonAsync(
String.Format("{0}/publishers/{1}/messages", hubName, deviceName), eventData).Result;
Console.WriteLine("Sent temperature using HttpClient: {0}",
eventData.Temperature);
Console.WriteLine(" > Response: {0}",
postResult.StatusCode);
Console.WriteLine(" > Response Content: {0}",
postResult.Content.ReadAsStringAsync().Result);
Thread.Sleep(new Random().Next(1000, 5000));
}
Check out this article for more details http://fabriccontroller.net/iot-with-azure-service-bus-event-hubs-authenticating-and-sending-from-any-type-of-device-net-and-js-samples/
try to set a connection string to your device (_deviceConnectionString) using this tutorial
https://github.com/Azure/azure-iot-sdks/blob/master/tools/DeviceExplorer/doc/how_to_use_device_explorer.md
You can do it by hand using the information you get from the IoT Hub directly or from the dashboard created by the IoT Suite wizard. It will look like this
_deviceConnectionString = "HostName=YourIoTHubName.azure-devices.net;DeviceId=YourDeviceId;SharedAccessKey=YourDeviceSharedAccessKey";
Did you generate the DeviceId and device key correctly using CreateDeviceIdentity tool?
Here is the guide: https://blogs.windows.com/buildingapps/2015/12/09/windows-iot-core-and-azure-iot-hub-putting-the-i-in-iot/
After hours of searching I found an hardware problem. My Raspberry was trying to use the non-configured Wi-Fi dongle to send the request while for all other requests used the network cable. Removing the dongle did the trick.