connecting external MQTT publisher with NODE-RED - node.js

In my current project, I am trying to connect my external temperature sensor to NODE-RED.
I have plugged MQTT with the external sensor. This sensor is publishing data with tempMeasurement topic. The configuration of MQTT publisher is as follows:
public class MQTTPublisher {
// public static final String BROKER_URL =
// "tcp://broker.mqttdashboard.com:1883";
public static final String BROKER_URL = "tcp://test.mosquitto.org:1883";
private MqttClient client;
public MQTTPublisher() {
try {
client = new MqttClient(BROKER_URL, MqttClient.generateClientId(),
new MemoryPersistence());
client.connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
public void publish(String topicName, int qos, byte[] payload)
throws MqttException {
final MqttTopic topic = client.getTopic(topicName);
final MqttMessage message = new MqttMessage(payload);
topic.publish(message);
System.out.println("Published data. Topic: " + topic.getName()
+ " Message: " + payload);
}
}
On the other side in Node-RED, I have created MQTT node, that has subscribe "tempMesurement". The configuration of MQTT node in NODE-RED is as follows:
My problem is that MQTT subscriber node is showing disconnected message as show in the above figure. Could you please suggest - what is wrong with the configuration in NODE-RED? How can I resolve this issue?

As mentioned in the comments, you need to remove the tcp:// from the sever name in the config screen

Related

How to solve Unhandle Exception:System.Net Socket.SocketException in azure iot readmessage device?

Hi i have the following code, that reads the message to the device. I have azure portal running. But i get the following exception when running on a command prompt;
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Azure.EventHubs;
using System.Threading.Tasks;
using System.Threading;
using System.Text;
using System.Collections.Generic;
namespace read_d2c_messages
{
class ReadDeviceToCloudMessages
{
// Event Hub-compatible endpoint
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
private readonly static string s_eventHubsCompatibleEndpoint ="sb://iothub-ns-mydeviceco......";
// Event Hub-compatible name
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
private readonly static string s_eventHubsCompatiblePath = "mydeviceconnection";
// az iot hub policy show --name service --query primaryKey --hub-name {your IoT Hub name}
private readonly static string s_iotHubSasKey = "";
private readonly static string s_iotHubSasKeyName = "service";
private static EventHubClient s_eventHubClient;
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct)
{
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
var eventHubReceiver = s_eventHubClient.CreateReceiver("$Default", partition, EventPosition.FromEnqueuedTime(DateTime.Now));
Console.WriteLine("Create receiver on partition: " + partition);
while (true)
{
if (ct.IsCancellationRequested) break;
Console.WriteLine("Listening for messages on: " + partition);
// Check for EventData - this methods times out if there is nothing to retrieve.
var events = await eventHubReceiver.ReceiveAsync(100);
// If there is data in the batch, process it.
if (events == null) continue;
foreach(EventData eventData in events)
{
string data = Encoding.UTF8.GetString(eventData.Body.Array);
Console.WriteLine("Message received on partition {0}:", partition);
Console.WriteLine(" {0}:", data);
Console.WriteLine("Application properties (set by device):");
foreach (var prop in eventData.Properties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
Console.WriteLine("System properties (set by IoT Hub):");
foreach (var prop in eventData.SystemProperties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
}
}
}
private static async Task Main(string[] args)
{
Console.WriteLine("IoT Hub Quickstarts - Read device to cloud messages. Ctrl-C to exit.\n");
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
var connectionString = new EventHubsConnectionStringBuilder(new Uri(s_eventHubsCompatibleEndpoint), s_eventHubsCompatiblePath, s_iotHubSasKeyName, s_iotHubSasKey);
s_eventHubClient = EventHubClient.CreateFromConnectionString(connectionString.ToString());
// Create a PartitionReciever for each partition on the hub.
var runtimeInfo = await s_eventHubClient.GetRuntimeInformationAsync();
var d2cPartitions = runtimeInfo.PartitionIds;
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
Console.WriteLine("Exiting...");
};
var tasks = new List<Task>();
foreach (string partition in d2cPartitions)
{
tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token));
}
// Wait for all the PartitionReceivers to finsih.
Task.WaitAll(tasks.ToArray());
}
}
}
On my command prompt, the exception is System.Net.Sockets.SocketException:A connection attempt failed because the connected party did not properly respond after a period of time, or established failed because host has failed to respond at Microsoft.Azure.EventHub.Amqp.AmqpHubClient.CreateConnectionAsync(TimeSpan, Timeout); What kind of error is this? Is had to do with firewall connectivity issue on my connection string not to receive message? Or hence i am using Free Trail cant be able to create Service-Bus-Messsage on my EndPoint?
I think the way you construct your connection string is not quite correct. When you copy the connection string from your IoT Hub in the full format, this should already work:
s_eventHubClient = EventHubClient.CreateFromConnectionString("Endpoint=sb://iothub-xxxxxx-1180347-e18a7c8824.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=qya62bOiN0********gIyEQ=;EntityPath=myiothubname");

Sending messages to different topics using spring integration gateway

I am trying to use spring integration for send mqtt messages to a broker and I am trying to use the gateway interface.
#Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
//set the factory details
return factory:
}
#Bean
#ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler =
new MqttPahoMessageHandler("randomString", mqttClientFactory());
//set handler details
messageHandler.setDefaultTopic(topic);
return messageHandler;
}
#Bean
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
#MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
private interface MyGateway {
void sendToMqtt(String data);
}
My question is: If I want to use the gateway handler to send messages to different topics how would I do that without having to create an adapter for each topic ?
Thanks.
Hope I formulated my question clearly and the code is properly formatted.
You need to set the target topic in a message header.
Here is one way to do that...
void sendToMqtt(String data, #Header(MqttHeaders.TOPIC) String topic);
The gateway proxy will assemble the message with the header, which is then used by the outbound adapter.

#Transformer for ObjectToJson Not Working in Spring Integration

A POJO Message.java is to be Converted to JSON(JSON is to be sent to pubsub Topic,using Spring Integration MessageChannels.),using following:
#Bean
#Transformer(inputChannel = "pubsubOutputChannel", outputChannel = "handleOutChannel")
public ObjectToJsonTransformer transformOut() {
return new ObjectToJsonTransformer();
}
#MessagingGateway(defaultRequestChannel = "pubsubOutputChannel")
public interface PubsubOutboundGateway {
void sendToPubsub(Messages msg);
}
#Bean
#ServiceActivator(inputChannel = "handleOutChannel")
public MessageHandler messageSender(PubSubOperations pubsubTemplate) {
return new PubSubMessageHandler(pubsubTemplate, "TestTopic");
}
When i call sendToPubsub() with an instance of Message.java with required properties set,i get an error "Null".
Is serviceActivator not able to receive the required data?
Any suggestions to fix this?.
Yes, it can't do that because you just don't tell it to do that.
Your gateway is configured for this:
#MessagingGateway(defaultRequestChannel = "handleOutChannel")
But that is not an input channel for the ObjectToJsonTransformer. So, whatever you send over that gateway is going directly to the messageSender service activator.
Try to configure your gateway like this:
#MessagingGateway(defaultRequestChannel = "pubsubOutputChannel")

Receiving messages from Azure IOT Hub using MQTT

I am trying to send messages to Azure IOT hub using MQTT and using Azure Device SDK libraries. There are two devices which are configured on IOT Hub. Both devices have different connection string.
Connection string for device 1
connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=sharedKey";
Connection string for device 2
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=sharedKey";
I have wrote two publishers that will send the messages to IOT hub and the subscriber that will recieve message from IOT Hub sent by the publishers.
In first publisher I have passed connection string for device 1 and for second publisher the connection string for device 2. Now when I am running both the publisher classes simultaneously, subscriber is recieving messages from both the publishers. Can anyone let me know how can I modify the code so that the subscriber will only only recieve messages sent by publisher 1 even when both the publisher are running simultaneously.
Here is my code for Publisher 1.
package com.iot.mqtt.connection;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.gson.Gson;
import com.microsoft.azure.sdk.iot.device.DeviceClient;
import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol;
import com.microsoft.azure.sdk.iot.device.IotHubEventCallback;
import com.microsoft.azure.sdk.iot.device.IotHubStatusCode;
import com.microsoft.azure.sdk.iot.device.Message;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.EventCallback;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.MessageSender;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.TelemetryDataPoint;
public class SimulatedDevice {
// The device connection string to authenticate the device with your IoT hub.
// Using the Azure CLI:
// az iot hub device-identity show-connection-string --hub-name {YourIoTHubName} --device-id MyJavaDevice --output table
private static String connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
// Using the MQTT protocol to connect to IoT Hub
private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
private static DeviceClient client;
// Specify the telemetry to send to your IoT hub.
private static class TelemetryDataPoint {
public double temperature;
public double humidity;
public String message;
public String timeStamp;
// Serialize object to JSON format.
public String serialize() {
Gson gson = new Gson();
return gson.toJson(this);
}
}
// Print the acknowledgement received from IoT Hub for the telemetry message sent.
private static class EventCallback implements IotHubEventCallback {
public void execute(IotHubStatusCode status, Object context) {
System.out.println("IoT Hub responded to message with status: " + status.name());
if (context != null) {
synchronized (context) {
context.notify();
}
}
}
}
private static class MessageSender implements Runnable {
public void run() {
try {
// Initialize the simulated telemetry.
double minTemperature = 20;
double minHumidity = 60;
String message;
Random rand = new Random();
InputStream is = null;
Properties prop = null;
prop = new Properties();
is = new FileInputStream("C:\\Users\\H251970\\eclipse-workspace\\IOTMqttTestProject\\resources\\config.properties");
prop.load(is);
message = prop.getProperty("message");
minTemperature = Double.parseDouble(prop.getProperty("temperature"));
minHumidity = Double.parseDouble(prop.getProperty("humidity"));
//System.out.println(message);
while (true) {
// Simulate telemetry.
double currentTemperature = minTemperature + rand.nextDouble() * 15;
double currentHumidity = minHumidity + rand.nextDouble() * 20;
String datatimeStamp= new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());;
TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
telemetryDataPoint.temperature = currentTemperature;
telemetryDataPoint.humidity = currentHumidity;
telemetryDataPoint.message = message;
telemetryDataPoint.timeStamp = datatimeStamp;
// Add the telemetry to the message body as JSON.
String msgStr = telemetryDataPoint.serialize();
Message msg = new Message(msgStr);
// Add a custom application property to the message.
// An IoT hub can filter on these properties without access to the message body.
msg.setProperty("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
System.out.println("Sending message: " + msgStr);
Object lockobj = new Object();
// Send the message.
EventCallback callback = new EventCallback();
client.sendEventAsync(msg, callback, lockobj);
synchronized (lockobj) {
lockobj.wait();
}
Thread.sleep(3000);
}
} catch (Exception e) {
System.out.println("Exception: " + e);
} /*finally {
inputStream.close();
}*/
}
}
public static void main(String[] args) throws IOException, URISyntaxException {
// Connect to the IoT hub.
client = new DeviceClient(connString, protocol);
client.open();
// Create new thread and start sending messages
MessageSender sender = new MessageSender();
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(sender);
// Stop the application.
System.out.println("Press ENTER to exit.");
System.in.read();
executor.shutdownNow();
client.closeNow();
}
}
Code for publisher 2 is also same just the connection-string is different.
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
The subscriber is recieving the message in following form.
Sending message: {"temperature":"27.739594911863872°C","voltage":"15.81301816513805V","motorspeed":"5.0m/s","inverterName":"i550","timeStamp":"22/08/2018 11:18:03"}
IoT Hub responded to message with status: OK_EMPTY
Here is the code for Subscriber class
package com.microsoft.docs.iothub.samples;
import com.microsoft.azure.eventhubs.ConnectionStringBuilder;
import com.microsoft.azure.eventhubs.EventData;
import com.microsoft.azure.eventhubs.EventHubClient;
import com.microsoft.azure.eventhubs.EventHubException;
import com.microsoft.azure.eventhubs.EventPosition;
import com.microsoft.azure.eventhubs.EventHubRuntimeInformation;
import com.microsoft.azure.eventhubs.PartitionReceiver;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.charset.Charset;
import java.net.URI;
import java.net.URISyntaxException;
public class ReadDeviceToCloudMessages {
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
//private static final String eventHubsCompatibleEndpoint = "{your Event Hubs compatible endpoint}";
private static final String eventHubsCompatibleEndpoint = "sb://ihsuprodmares009dednamespace.servicebus.windows.net/";
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
//private static final String eventHubsCompatiblePath = "{your Event Hubs compatible name}";
private static final String eventHubsCompatiblePath = "eventHubsCompatiblePathString";
// az iot hub policy show --name iothubowner --query primaryKey --hub-name {your IoT Hub name}
private static final String iotHubSasKey = "iotHubSasKeyString=";
private static final String iotHubSasKeyName = "iothubowner";
// Track all the PartitionReciever instances created.
private static ArrayList<PartitionReceiver> receivers = new ArrayList<PartitionReceiver>();
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static void receiveMessages(EventHubClient ehClient, String partitionId)
throws EventHubException, ExecutionException, InterruptedException {
final ExecutorService executorService = Executors.newSingleThreadExecutor();
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
ehClient.createReceiver(EventHubClient.DEFAULT_CONSUMER_GROUP_NAME, partitionId,
EventPosition.fromEnqueuedTime(Instant.now())).thenAcceptAsync(receiver -> {
System.out.println(String.format("Starting receive loop on partition: %s", partitionId));
System.out.println(String.format("Reading messages sent since: %s", Instant.now().toString()));
receivers.add(receiver);
while (true) {
try {
// Check for EventData - this methods times out if there is nothing to retrieve.
Iterable<EventData> receivedEvents = receiver.receiveSync(100);
// If there is data in the batch, process it.
if (receivedEvents != null) {
for (EventData receivedEvent : receivedEvents) {
System.out.println(String.format("Telemetry received:\n %s",
new String(receivedEvent.getBytes(), Charset.defaultCharset())));
System.out.println(String.format("Application properties (set by device):\n%s",receivedEvent.getProperties().toString()));
System.out.println(String.format("System properties (set by IoT Hub):\n%s\n",receivedEvent.getSystemProperties().toString()));
}
}
} catch (EventHubException e) {
System.out.println("Error reading EventData");
}
}
}, executorService);
}
public static void main(String[] args)
throws EventHubException, ExecutionException, InterruptedException, IOException, URISyntaxException {
final ConnectionStringBuilder connStr = new ConnectionStringBuilder()
.setEndpoint(new URI(eventHubsCompatibleEndpoint))
.setEventHubName(eventHubsCompatiblePath)
.setSasKeyName(iotHubSasKeyName)
.setSasKey(iotHubSasKey);
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
final ExecutorService executorService = Executors.newSingleThreadExecutor();
final EventHubClient ehClient = EventHubClient.createSync(connStr.toString(), executorService);
// Use the EventHubRunTimeInformation to find out how many partitions
// there are on the hub.
final EventHubRuntimeInformation eventHubInfo = ehClient.getRuntimeInformation().get();
// Create a PartitionReciever for each partition on the hub.
for (String partitionId : eventHubInfo.getPartitionIds()) {
receiveMessages(ehClient, partitionId);
}
// Shut down cleanly.
System.out.println("Press ENTER to exit.");
System.in.read();
System.out.println("Shutting down...");
for (PartitionReceiver receiver : receivers) {
receiver.closeSync();
}
ehClient.closeSync();
executorService.shutdown();
System.exit(0);
}
}
Now I am trying to figure out how to recieve messages from publisher 1 only even when both publishers are running simultaneously. Thanks in Advance.
Azure IoT Hub is not a generic MQTT broker. It only supports the following topics:
devices/{device_id}/messages/devicebound/
devices/{device_id}/messages/devicebound/{property_bag}
And Event Hub can't specify device id too. Like what you have found.
There is a workaround but it is only working when your devices less and equal 10. This because the maximum custom endpoint you can create is 10.
That is you can use Service Bus Topic instead of Event Hub:
Device -> Azure IoT Hub -> Routing -> Endpoint "Service Bus Topic"
Add two service bus topic endpoints.
Add two routes for two endpoints:
Receive from the service bus topic:
subscriptionClient = new SubscriptionClient(ServiceBusConnectionString, TopicName, SubscriptionName);

spring-integration-mqtt With multiple Mqtt Servers for subscription

I am using Spring's spring-integration-mqtt and i can connect to a single Mqtt server and can receive messages on subscribed topics , and now i want to make application which can connect to multiple Mqtt Servers and can receive data from every connection and i want to manage it as dynamic where i can add more Mqtt servers from database or text file.
a simple bean for single Mqtt connection for subscription is as follow
#Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter2 =
new MqttPahoMessageDrivenChannelAdapter("tcp://192.168.100.1:1883","mqtt_virtual_received_sus_2",
"DATA/#", "LD/#","CONF/#","CONFIG/#");
adapter2.setCompletionTimeout(0);
adapter2.setConverter(new DefaultPahoMessageConverter());
adapter2.setQos(2);
adapter2.setOutputChannel(mqttInputChannel());
return adapter2;
}
above code creates a connection for the mqtt server and can receive messages and if i copy paste the same code twice for second server with different Mqtt ip address i can connect to both Mqtt Server as follows
#Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter2 =
new MqttPahoMessageDrivenChannelAdapter("tcp://192.168.100.1:1883","mqtt_virtual_received_sus_2",
"DATA/#", "LD/#","CONF/#","CONFIG/#");
adapter2.setCompletionTimeout(0);
adapter2.setConverter(new DefaultPahoMessageConverter());
adapter2.setQos(2);
adapter2.setOutputChannel(mqttInputChannel());
return adapter2;
}
#Bean
public MessageProducer inbound2() {
MqttPahoMessageDrivenChannelAdapter adapter2 =
new MqttPahoMessageDrivenChannelAdapter("tcp://192.168.100.14:1883","mqtt_virtual_received_sus_1",
"DATA/#", "LD/#","CONF/#","CONFIG/#");
adapter2.setCompletionTimeout(0);
adapter2.setConverter(new DefaultPahoMessageConverter());
adapter2.setQos(2);
adapter2.setOutputChannel(mqttInputChannel());
return adapter2;
}
above code also works fine and i can receive message from both Mqtt Servers, but is there any way i can manage it dynamically like as follows, i change the bean's return type to list, but didn't worked:
#Bean
public List<MqttPahoMessageDrivenChannelAdapter> getAdapter () {
List<MqttPahoMessageDrivenChannelAdapter > logConfList=new ArrayList<MqttPahoMessageDrivenChannelAdapter>();
MqttPahoMessageDrivenChannelAdapter adapter2 =
new MqttPahoMessageDrivenChannelAdapter("tcp://192.168.100.1:1883","mqtt_virtual_received_sus_2",
"DATA/#", "LD/#","CONF/#","CONFIG/#");
adapter2.setCompletionTimeout(0);
adapter2.setConverter(new DefaultPahoMessageConverter());
adapter2.setQos(2);
adapter2.setOutputChannel(mqttInputChannel() );
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter("tcp://192.168.100.14:1883","mqtt_virtual_received_sus_1",
"DATA/#", "LD/#","CONF/#","CONFIG/#");
adapter.setCompletionTimeout(0);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(2);
adapter.setOutputChannel(mqttInputChannel() );
logConfList.add(adapter);
logConfList.add(adapter2);
return logConfList;
}
is there any way i can manage these beans dynamically, where i can fetch mqtt server details from text file and in a for loop or something i can manage multiple connections.
See Dynamic and runtime Integration Flows.
#Autowired
private IntegrationFlowContext flowContext;
private IntegrationFlowRegistration addAnAdapter(String uri, String clientId, MessageChannel channel,
String... topics) {
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(uri, clientId, topics);
// more adapter configuration
IntegrationFlow flow = IntegrationFlows.from(adapter)
.channel(channel)
.get();
return this.flowContext.registration(flow).register();
}
private void removeAdapter(IntegrationFlowRegistration flowReg) {
this.flowContext.remove(flowReg.getId());
}

Resources