Publish to MQTT topic in AWS IoT from Ionic 5 - amazon-web-services

I am using ionic 5 for a mobile app that runs on iOS and Android. How can I publish a message to an MQTT topic in AWS IoT from Ionic 5? I have generated certificates for the client authentication in AWS IoT already. Are there any libraries available for this?

You can use a variety of MQTT client libraries in the Ionic 5 app to send messages to an MQTT subject in Amazon IoT. Paho MQTT JavaScript Client Library is one such library.
The steps below can be used to incorporate this library into the Ionic 5 app:
With npm, add the Paho MQTT JavaScript client library to your Ionic application.
npm install paho-mqtt
Import the library into your Ionic application, then build a new MQTT
client object.
import { Client } from 'paho-mqtt';
const client = new Client('wss://your-aws-iot-endpoint', 'your-client-id');
Use the client object and your generated certificates to establish a
connection to the Amazon IoT MQTT broker.
Using the send method of the client object, you can send messages to
an MQTT topic after the client has established a connection.
Use certificate-based authentication in place of username and
password by using the following code:
const options = {
useSSL: true,
userName: 'your-aws-iot-username',
password: 'your-aws-iot-password',
ssl: {
key: 'path/to/your/device-private-key.pem',
cert: 'path/to/your/device-certificate.pem',
ca: 'path/to/your/ca-certificate.pem',
},
onSuccess: () => console.log('MQTT client connected'),
onFailure: (error) => console.error('MQTT client connection failed:', error),
};
Using the send method of the client object as before, you can publish
messages to an MQTT topic after the client has established a
connection.
const topic = 'your-mqtt-topic';
const message = new Message('your-message-payload');
message.destinationName = topic;
client.send(message);

Related

Connect react native mobile app to AWS websocket API

I am building a card game on mobile, with React Native and Expo. I would like to allow real-time updates during a game and I thought about using AWS Gateway's websocket API.
I created the API on AWS Gateway and the following code in React Native to connect to it:
connectToWebSocket = (onConnected) => {
const socket = new WebSocket("wss://xxxx.execute-api.us-east-1.amazonaws.com/production");
socket.addEventListener("open", (e) => {
onConnected();
});
socket.addEventListener("close", (e) => console.log("WebSocket is closed"));
socket.addEventListener("error", (e) => console.error(e));
};
Unfortunately, this gives me the error EventĀ {isTrusted: false} and does not connect.
It seems that all the available examples online are about building a web app that connects to AWS Gateway, but not for a mobile app. I've been reading tutorials for hours now and am completely stuck.
Is there any way for me to use AWS Gateway's websocket API for my project?
I figured it out! The very first thing is that my Websocket API was not deployed.
On the Routes panel, I had to go to Actions>Deploy API
The second thing is that my route Integration types were Lambdas, but I had not switched the Use Lambda Proxy integration flag on. Because of that, no event was sent to my lambda and the code was failing.
Once I had fixed both of those, I could connect without a problem :)

Amazon AWS IoT Core: sending an MQTT message via WebSocket from the browser

I'm building a webapp which should send and receive MQTT messages to and from IoT Core.
I read that Amazon AWS IoT Core does support MQTT over WebSocket so I created a test "thing", created an IAM user and attached a policy with full access to the IoT functions (connect, subscribe, send etc..).
The documentation says that the AWS SDK for JavaScript can be used in a browser environment:
So I created my webpp and imported the library
var awsIot = require('aws-iot-device-sdk');
But I get some errors:
Can't resolve 'path
Can't resolve 'fs'
Can't resolve 'tls
After searching online it seems that these libraries are only supported by node.js and not the browser.
It has to do with the fact that webpack has removed polyfills in their new version. You have to add code below to your webpack.config.js fallback location and install them of course.
Or you can switch into webpack v4.
module.exports = {
...
resolve: {
fallback: {
"fs": false,
"path":false,
"tls":false
},
}
}

AWS SES could not send the email, got 550 error

I use SES for sending emails to users. Sometimes users reported to me that they did not receive any emails from me. I started to collect bounced emails via sns topic and found a lot of errors with status = 5.5.1 and
diagnosticCode
"smtp; 550 5.1.1 Remote MTA does not support STARTTLS. Message can be delivered only over a TLS connection."
I use the aws-sdk and my code which sends emais:
let params = {
Destination: {
ToAddresses: [emailDestination]
},
Message: {
Body: {
Html: {
Charset: "UTF-8",
Data: template({
...templateData
})
},
},
Subject: {
Charset: 'UTF-8',
Data: templateData.subject
}
},
Source: SOURCE_EMAIL,
ConfigurationSetName: CONFIGURATION_SET_NAME
};
await ses.sendEmail(params).promise()
My ConfigurationSet has TLS Required
What did I do wrong and could it be a remote configuration issue of the user?
I think you are on the right track of it being a remote issue. From the sound of the error, Amazon SES is trying to connect to a remote mail relay but failing to create a TLS connection and canceling instead.
Your configuration set is enforcing a policy of sending only when a TLS connection can be established to receiving server (and message is encrypted) all the way to the end-user. Depending on how sensitive your emails are, this may be the desired behavior.
However, if you want to continue to send the mail, even when unencrypted, you can disable the require TLS setting. Amazon will still use TLS when possible, according to their documentation -
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/security.html
By default, Amazon SES uses opportunistic TLS. This means that Amazon SES always attempts to make a secure connection to the receiving mail server. If Amazon SES can't establish a secure connection, it sends the message unencrypted.

python-socketio websocket emit to particular client in Socket.IO an ionic application

In my project I am using a Django application that acts as a SocketIO server to the Ionic mobile application which uses Socket.io to connect to the server as a client. My django application has another socket connection and it acts as a client to another micro service in python which uses python-socketio to create a websocket server. When I send a request from the Ionic application, it reaches the Django server which sends the request to the client via Django signals and then the request is sent to the micro services and the response from them are to be sent to the same Ionic application via Django. I was able to do it successfully when the Ionic application is only one. When there are multiple Ionic clients and when the data is different for them both, this does not make an effect. Both the clients receive the same data. My requirement forces me to have the communication through the Django server. Can anyone help me with this?
Microservice (python-socketio) <--> Django (python-socketio) <--> Ionic application (socket.io)
The communication is by websockets by eventlet.

Why does grails websockets connection fail but continue to receive messages that have been subscribed to in the browser while using an AWS ELB?

Using Grails 2.5.5 with the spring-websockets plugin 1.3.1 and tomcat 8.0.37.
While using an AWS Elastic Load Balancer, the following error is shown in the Javascript console when loading the application in the browser
WebSocket connection to 'ws://...s.com/Application/stomp/059/uyqk9cdn/websocket' failed: Error during WebSocket handshake: Unexpected response code: 400
From research it has been found that the ELB doesn't support websockets and proxying within the ELB, a third party load balancer or potentially using a new Application Load Balancer (the applications are not in a VPC so this is not an easy solution) might be required.
However, after the error, the following logging is received:
Web Socket Opened...
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
version:1.1
heart-beat:0,0
user-name:admin
connected to server undefined
>>> SUBSCRIBE
id:sub-0
destination:/topic/someTopic
Messages are then received by the client fine when they are broadcast
<<< MESSAGE
destination:/topic/someTopic
content-type:application/json;charset=UTF-8
subscription:sub-0
message-id:xb71g__u-16
content-length:89
The code to initiate the websocket connection is
<r:require module="spring-websocket"/>
<r:script>
var socket = new SockJS("${createLink(uri: '/stomp')}");
var client = Stomp.over(socket);
client.connect({}, function () {
var topic = "/topic/digTicketUpdated";
console.log("Subscribing to -> " + topic);
client.subscribe(topic, function (message) {
console.log("Push Message Received From Server");
updateStatus(message.body);
});
});
</r:script>
This is taken from the grails-spring-websocket github page.
Is it possible to figure out if this is fallback that has kicked in, the websocket actually working or some other scenario. To summarise :
Is the websocket falling back to another protocol?
Is there any way to get rid of the 400 error?
Thanks to the suggestions in the comments, it was found that after the "Unexpected response code: 400" was thrown, SockJS attempted to use a long POST XHR request to emulate the web socket and it worked. This was viewable in the Network tab of Chrome Developer Tools as "xhr_streaming".
To prevent the 400 error showing in the development console, a configurable switch was implemented so web socket connections are not attempted when it is known they are not supported, such as on an AWS ELB. This was achieved by passing by removing "websocket" from the allowed protocols when instantiating SockJS :
var allowedProtocols = ['xdr-streaming', 'xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xdr-polling', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling']
var socket = new SockJS(uri, {}, {protocols_whitelist : allowedProtocols});
var client = Stomp.over(socket);