mqtt between arduino and raspberry pi - raspberry-pi

I'm trying to prepare for my master project in my last year by getting my head around mqtt. I've successfully installed mosquitto on my RPi, ran the test publish and subscribe (hello/world). I also managed to connect to the broker using the android app myMQTT and everything seams to run just fine. The problems start when i try to connect to the broker with an arduino with ethernet shield using the PubSubClient library by knolleary. Everything is connected to one switch (router-Rpi-arduino). I've made sure that the arduino has an unique ip-address an mac-address (I checked it in the router). The server ip-address is also correct as i'm using it to ssh into the Rpi.. The code running on the arduino keeps returning:
Attempting MQTT connection...failed, rc=-4 try again in 5 seconds
The returncode means connection timeout..
I'm running a fresh installed mosquitto on the pi so there's no username or password required to connect to the broker. Does anyone knows what i'm doing wrong here? I've been looking over the internet for a while now and i can't seem to figure it out.
Code running on the arduino:
/*
Basic MQTT example
This sketch demonstrates the basic capabilities of the library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xAA };
IPAddress ip(192, 168, 1, 41);
IPAddress server(192, 168, 1, 26);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i=0;i<length;i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
EthernetClient ethClient;
PubSubClient client(ethClient);
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("arduinoClient")) {
Serial.println("connected");
// Once connected, publish an announcement...
//client.publish("outTopic","hello world");
// ... and resubscribe
client.subscribe("hello/world");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
Serial.begin(57600);
client.setServer(server, 1883);
client.setCallback(callback);
Ethernet.begin(mac, ip);
// Allow the hardware to sort itself out
delay(3000);
}
void loop()
{
if (!client.connected()) {
reconnect();
}
client.loop();
}

From the docs for the PubSubClient, the rc=-4 means the connection attempt has timed out. It has established a TCP connection, but the server has not responded to the MQTT connection attempt.
What version of mosquitto are you using? It is possible you are using an older version that doesn't support MQTT 3.1.1 that the PubSubClient defaults to now. If that is the case, you can change the MQTT_VERSION value in PubSubClient.h to revert back to MQTT 3.1.

Related

ActiveMQ Artemis publish message loss during HA fail-over

I use ActiveMQ Artemis 2.17.0, and I'm looking to avoid message loss in a producer during fail-over.
Message publish loss handled during Artemis active to passive switch by catching ActiveMQUnBlockedException and sending the message again.
The brokers are configured as active/passive HA shared-store. Active node configured in host1 and passive node configured in host2.
Url is:
(tcp://host1:61616,tcp://host2:61616)?ha=true&reconnectAttempts=-1&blockOnDurableSend=false
blockOnDurableSend set to false for high throughput.
During active to passive switch publishing code throws ActiveMQUnBlockedException but not during passive to active switching.
We're using Spring 4.2.5 and CachingConnectionFactory for connection factory.
I'm using the following code to send messages:
private void sendMessageInternal(final ConnectionFactory connectionFactory, final Destination queue, final String message)
throws JMSException {
try (final Connection connection = connectionFactory.createConnection();) {
connection.start();
try (final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final MessageProducer producer = session.createProducer(queue);) {
final TextMessage textMessage = session.createTextMessage(message);
producer.send(textMessage);
}
} catch (JMSException thr) {
if (thr.getCause() instanceof ActiveMQUnBlockedException) {
// consider as fail-over disconnection, send message again.
} else {
throw thr;
}
}
}
In host1 machine, Artemis deployed as master - node1.
In host2 machine, Artemis deployed as slave - node2.
following steps I did to simulate fail-over
node1 and node2 started
node1 started as live server and node2 started as backup server
killed node1, node2 become live server
client publish code threw ActiveMQUnBlockedException and handled to send message again
started node1 again. node1 become live server and node2 become backup again
client publish code did not throw ActiveMQUnBlockedException and loss in message.
Getting following error stack during step #3. ( Killed node1 and node2 become Live server).
javax.jms.JMSException: AMQ219016: Connection failure detected. Unblocking a blocking call that will never get a response
at org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:540)
at org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:434)
at org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext.sessionStop(ActiveMQSessionContext.java:470)
at org.apache.activemq.artemis.core.client.impl.ClientSessionImpl.stop(ClientSessionImpl.java:1121)
at org.apache.activemq.artemis.core.client.impl.ClientSessionImpl.stop(ClientSessionImpl.java:1110)
at org.apache.activemq.artemis.jms.client.ActiveMQSession.stop(ActiveMQSession.java:1244)
at org.apache.activemq.artemis.jms.client.ActiveMQConnection.stop(ActiveMQConnection.java:339)
at org.springframework.jms.connection.SingleConnectionFactory$SharedConnectionInvocationHandler.localStop(SingleConnectionFactory.java:644)
at org.springframework.jms.connection.SingleConnectionFactory$SharedConnectionInvocationHandler.invoke(SingleConnectionFactory.java:577)
at com.sun.proxy.$Proxy5.close(Unknown Source)
at com.eu.amq.failover.test.ProducerNodeTest.sendMessageInternal(ProducerNodeTest.java:133)
at com.eu.amq.failover.test.ProducerNodeTest.sendMessage(ProducerNodeTest.java:110)
at com.eu.amq.failover.test.ProducerNodeTest.main(ProducerNodeTest.java:90)
The ActiveMQUnBlockedException you're getting is coming from Spring's invocation of javax.jms.Connection#stop. It's not related to sending a message. Re-sending a message when you get this specific exception could result in a duplicate message.
Ultimately your problem is directly related to setting blockOnDurableSend=false. This tells the client to "fire and forget." In other words the client won't wait for a response from the broker to ensure the message actually made it successfully. This lack of waiting increases throughput but decreases reliability.
If you really want to mitigate potential message loss you have two main options.
Set blockOnDurableSend=true. This will reduce message throughput, but it's the simplest way to guarantee the message arrived at the broker successfully.
Use a CompletionListener. This will allow you to keep blockOnDurableSend=false, but the application will still be informed if there are problems sending the message although the information will be provided asynchronously. This feature was added in JMS 2 specifically for this kind of scenario. See the JavaDoc for more details.

In QT how can I detect when a USB port switches from serial mode to DFU when connected to an STM32

I have a Qt5.12.4 MinGw64 app where I want to catch a USB event. In Windows 10 the MS driver for STM/USB emits error messages and I can use that as a trigger. Inelegant but it works, until I try to run it in a Win7-8.1 app where the driver is a third party STM driver with a VCP wrapper. I am thinking I need to adopt libusb to try and catch the ports change of state, but I am at a loss as how to proceed. I can see the port info in Device Manager, I just dont know how to get to it. Some of the questions going through my head....
1) Can I just make an OS call to read the port info? (if so, how?)
2) Can libusb and QSerialport co-exist on the same port?
3) What calls to LibUSB1.0 do I make to query the port status?
4) Is there a Windows cli utility like lsusb (wmic??) where I could scrape the data?
5) Which solution is likely to be the best cross platform solution?
I am using this trigger to start dfuse as a process that does a firmware update automatically on my STM board.
I have looked over the libusb1.0 docs but I do not understand just how I can use it. If that is correct solution, an example of how to query the Com port data and state would be most appreciated.
I tried using qDebug() to print out all of the serialportInfo data, while in serial or DFU state, but there is nothing there that is useful that I can use as a trigger.
USB serial mode = Serial port info is: ("COM3", "USB Serial Device", "Microsoft", "00000000001A", "\\.\COM3", "483", "5740", "1", " no data", "1")
USB DFU mode = Serial port info is: ("COM3", "N/A", "N/A", "N/A", "\\.\COM3", "N/A", "N/A", "no data", " no data", "no data")
I need some direction as to how to grab this port info so I dont really have any code that matters, but I am including an excerpt of my working process function.
This code works just fine to actually perform the firmware load. I just need a way to actually trigger it from a USB port change of state
void updateDevice_Dialog::update_firmware(QString fileName)
{
qDebug() << "Updating firmware: " << fileName ;
QDir dir;
ui->progress_label->setText("Preparing to update Firmware .....");
if(dir.setCurrent(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)+"/firmware"))
{
QSettings settings;
QString comPort = settings.value("USBPort").toString();
ui->progress_label->setText("Setting port to: "+comPort+" and starting download .....");
ui->avr_progressBar->setValue(0);
ui->avr_progressBar->setRange(0,100);
ui->avr_progressBar->setHidden(false);
progress_steps = 0; //reset avrProcess line output counter;
qDebug() << "Starting process for stm-dfu on serial port: " << comPort;
connect(avr_Process,SIGNAL(error(QProcess::ProcessError)),this,SLOT(process_error(QProcess::ProcessError)));
connect(avr_Process,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(process_finished(int,QProcess::ExitStatus)));
connect(avr_Process,SIGNAL(readyReadStandardOutput()),this,SLOT(process_readLine()));
connect(avr_Process,SIGNAL(errorOccurred(QProcess::ProcessError)),avr_Process,SLOT(kill()));
connect(avr_Process,SIGNAL(error(QProcess::ProcessError)),ui->avr_progressBar,SLOT(close()));
QString dfu_command = "\""+QCoreApplication::applicationDirPath()+"/Tools/\"dfusecommand -c -d --v --fn "
"\""+QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)+"/firmware/\""+fileName;
qDebug().noquote() << "dfu command string is: "<< dfu_command << " Current dir is: " << dir.currentPath();
avr_Process->start(dfu_command);
avr_Process->waitForFinished(20000);
}
}
From the perspective of the host system, rebooting the microcontroller into DFU will look like the original device was disconnected, and a completely different device was plugged in shortly afterwards.
If you need to watch for this, set up a libusb hotplug callback so that you'll be notified when the DFU device is attached.

Vertx Java Client throwing "SMF AD bind response error" while connecting solace vmr Server

When I am trying to connect solace VMR Server and deliver the messages from a Java client called Vertx AMQP Bridge.
I am able to connect the Solace VMR Server but after connecting, not able to send messages to solace VMR.
I am using below sender code from vertx client.
public class Sender extends AbstractVerticle {
private int count = 1;
// Convenience method so you can run it in your IDE
public static void main(String[] args) {
Runner.runExample(Sender.class);
}
#Override
public void start() throws Exception {
AmqpBridge bridge = AmqpBridge.create(vertx);
// Start the bridge, then use the event loop thread to process things thereafter.
bridge.start("13.229.207.85", 21196,"UserName" ,"Password", res -> {
if(!res.succeeded()) {
System.out.println("Bridge startup failed: " + res.cause());
return;
}
// Set up a producer using the bridge, send a message with it.
MessageProducer<JsonObject> producer =
bridge.createProducer("T/GettingStarted/pubsub");
// Schedule sending of a message every second
System.out.println("Producer created, scheduling sends.");
vertx.setPeriodic(1000, v -> {
JsonObject amqpMsgPayload = new JsonObject();
amqpMsgPayload.put(AmqpConstants.BODY, "myStringContent" + count);
producer.send(amqpMsgPayload);
System.out.println("Sent message: " + count++);
});
});
}
}
I am getting the error below:
Bridge startup failed: io.vertx.core.impl.NoStackTraceThrowable:
Error{condition=amqp:not-found, description='SMF AD bind response
error', info={solace.response_code=503, solace.response_text=Unknown
Queue}} Apr 27, 2018 3:07:29 PM io.vertx.proton.impl.ProtonSessionImpl
WARNING: Receiver closed with error
io.vertx.core.impl.NoStackTraceThrowable:
Error{condition=amqp:not-found, description='SMF AD bind response
error', info={solace.response_code=503, solace.response_text=Unknown
Queue}}
I have created queue and also topic correctly in solace VMR but not able to send/receive messages. Am I missing any configuration from solace VMR Server side? Is there any code-change required in the Vertx Sender Java code above? I am getting the error trace above when delivering message. Can someone help on the same?
Vertx AMQP Bridge Java client :https://vertx.io/docs/vertx-amqp-bridge/java/
There are a few different reason why you may be encountering this error.
It could be that the client is not authorized to publish guaranteed messages. To fix this, you need to enable "guaranteed endpoint create" in the client-profile on the Solace router side.
It may also be that the application is using Reply Handling. This is not currently supported with the Solace router. Support for this will be added in the 8.11 release of the Solace VMR. A workaround for this would be to set ReplyHandlingSupport to false.
AmqpBridgeOptions().setReplyHandlingSupport(false);
There is also a known issue in the Solace VMR which causes this error when unsubscribing from a durable topic endpoint. A fix for this issue will also be in the 8.11 release of the Solace VMR. A workaround for this is to disconnect the client without first unsubscribing.

Remote Logging using Log4j2

So i have this task to log activities to a file, but it has to be done
remotely on the server side, Remote logging.
NOTE : Remote Logging has to be in latest version of Log4j2(2.10)
My task was simple
Send logging info to a port.
Log info from port to a file.
My Discoveries
Socket Appender exist which help send info to a port. This is it, you dont need to create a client side code or anything.
Socket appender configuration in log4j2.properties
appender.socket.type = Socket
appender.socket.name= Socket_Appender
appender.socket.host = "IP address"
appender.socket.port = 8101
appender.socket.layout.type = SerializedLayout
appender.socket.connectTimeoutMillis = 2000
appender.socket.reconnectionDelayMillis = 1000
appender.socket.protocol = TCP
Adapting from here. But this is also log4j 1.x adaptation.
I found out that before log4j 2.6 to listen to a port we used TcpSocketServer which started a server using LogEventBridgeThis helped reach that conclusion. This class was in core.net.server which is no longer available.Assuming it is not used anymore and the only similar/closest class, TcpSocketManager.Other links that helped. How to use SocketAppend?
Then i tried this
public static final Logger LOG=LogManager.getLogger(myapp.class.getName());
main(){
LOG.debug("DEBUG LEVEL");
}
and got the following error
main ERROR TcpSocketManager (TCP:IPAddress:8111) caught exception
and will continue: java.net.SocketTimeoutException: connect timed out
I know this work because i made it read to a socket but there was no one listening, but somehow i messed up big time and there was a code change.
I need help how to go ahead. Thank You in advance
The socket server to remotely receive log events has been moved to a separate repository: https://github.com/apache/logging-log4j-tools
This still needs to be released.

When can connect() on O_NONBLOCK socket fail with something other than EINPROGRESS or EALREADY?

I read the following sample code and I am wondering if anybody can say on which platforms it is possible for connect() to fail with something other than EINPROGRESS or EALREADY.
By fail I mean execute the else branch in the sample to execute. The comment in the source suggests FreeBSD. Are there any other systems? I was not able to get it to fail on Linux.
if (connect(hostp->sockets[i],
(struct sockaddr *)res->ai_addr,
res->ai_addrlen) == -1) {
/* This is what we expect. */
if (errno == EINPROGRESS) {
printf(" connect EINPROGRESS OK "
"(expected)\n");
FD_SET(hostp->sockets[i], &wrfds);
} else {
/*
* This may happen right here, on
* localhost for example (immediate
* connection refused).
* I can see that happen on FreeBSD
* but not on Solaris, for example.
*/
printf(" connect: %s\n",
strerror(errno));
++n;
}
[...]
source: http://mff.devnull.cz/pvu/src/tcp/non-blocking-connect.c
There are many ways why connect might fail. As the comment rightly says even a non-blocking connect might fail immediately on some platforms when connecting to localhost if no listening server is there. Also connect will usually fail immediately if no route can be determined to the target, for example if the interface for the default route is down. And then there are still other ways to fail, like lack of memory, permission denied to connect when running inside a sandbox or similar.