I'm trying to make Azure IOT Hub behave (more or less) like an MQTT broker.
I want to publish a message on devices/{deviceid}/messages/events/ and then receive it on devices/{deviceid}/messages/devicebound/#.
The library I'm using is M2MQTT and so far, I can connect to the IOT hub and publish a message to the events topic. Using DeviceExplorer I can see the message arriving on the hub.
For some reason the message is not relayed to the devicebound topic and the MqttClient_MqttMsgPublishReceived is never triggered. The event does get triggered when using DeviceExplorer and sending a message from there.
So... I think I'm missing something either in code or in the configuration of the IOT Hub.
Does anybody know what I'm doing wrong?
This is my code:
using Microsoft.Azure.Devices.Common.Security;
using Newtonsoft.Json;
using System;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Windows.Forms;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
namespace DemoM2MqttAzure
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const string IOTHubURI = "TESTIOTHUB.azure-devices.net";
private const string IOTDeviceID = "IOTDevice";
private string IOTDeviceUsername = string.Format("{0}/{1}/?api-version=2018-06-30", IOTHubURI, IOTDeviceID);
private const string IOTDevicePrimaryKey = "xxx";
private string IOTSubscribeDeviceTopic = string.Format("devices/{0}/messages/devicebound/#", IOTDeviceID);
private string IOTPublishDeviceTopic = string.Format("devices/{0}/messages/events/", IOTDeviceID);
//M2MQTT client.
MqttClient mqttClient;
private void buttonStartMQTT_Click(object sender, EventArgs e)
{
mqttClient = new MqttClient(IOTHubURI, 8883, true, MqttSslProtocols.TLSv1_0, UserCertificateSelectionCallback, null);
mqttClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
mqttClient.MqttMsgPublishReceived += MqttClient_MqttMsgPublishReceived;
mqttClient.MqttMsgPublished += MqttClient_MqttMsgPublished;
mqttClient.MqttMsgSubscribed += MqttClient_MqttMsgSubscribed;
string IOTDevicePassword = CreateSharedAccessSignature();
mqttClient.Connect(IOTDeviceID, IOTDeviceUsername, IOTDevicePassword);
if(mqttClient.IsConnected)
{
MessageBox.Show("Connected!");
}
else
{
MessageBox.Show("Connection failed.");
}
}
private void MqttClient_MqttMsgSubscribed(object sender, MqttMsgSubscribedEventArgs e)
{
byte[] qosLevels = e.GrantedQoSLevels;
ushort msgId = e.MessageId;
MessageBox.Show("Event subscribed");
}
private string CreateSharedAccessSignature()
{
string target = string.Format("{0}/devices/{1}", IOTHubURI, IOTDeviceID);
return new SharedAccessSignatureBuilder
{
Key = IOTDevicePrimaryKey,
Target = target,
KeyName = null,
TimeToLive = TimeSpan.FromDays(360)
}.ToSignature();
}
private void buttonSubscribe_Click(object sender, EventArgs e)
{
if(mqttClient.IsConnected)
{
mqttClient.Subscribe(new string[] { IOTSubscribeDeviceTopic }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE });
}
else
{
MessageBox.Show("Not connected.");
}
}
private void buttonPublish_Click(object sender, EventArgs e)
{
if (mqttClient.IsConnected)
{
var telemetryDataPoint = new
{
deviceId = IOTDeviceID,
value = 123.456,
text = "abc"
};
var json = JsonConvert.SerializeObject(telemetryDataPoint);
ushort result = mqttClient.Publish(IOTPublishDeviceTopic, Encoding.UTF8.GetBytes(json), MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, true);
}
else
{
MessageBox.Show("Not connected.");
}
}
private void MqttClient_MqttMsgPublished(object sender, MqttMsgPublishedEventArgs e)
{
if (e.IsPublished)
{
MessageBox.Show("Event message published.");
}
else
{
MessageBox.Show("Message was not published...");
}
}
private void MqttClient_MqttMsgPublishReceived(object sender, uPLibrary.Networking.M2Mqtt.Messages.MqttMsgPublishEventArgs e)
{
MessageBox.Show("Event message publish received.");
}
private bool UserCertificateSelectionCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(mqttClient.IsConnected)
{
mqttClient.Disconnect();
}
}
}
}
I want to publish a message on devices/{deviceid}/messages/events/ and then receive it on devices/{deviceid}/messages/devicebound/#.
Or, you don't quite understand yet how IoT Hub works ;) First clue: IoT Hub is not a full MQTT broker so you should not try to make it behave like one. – silent