Working with Yandex IoT Core from an Android device in Java
In this scenario, you'll learn how to connect to Yandex IoT Core from an Android device using the Paho library and Java programming language. It assumes that you know how to develop Android apps in Java using Android Studio.
Note
The source code used in this scenario is available on GitHub.
Once connected, you can exchange messages between your device and registry:
To connect to Yandex IoT Core and start messaging:
- Before you start
- Create the necessary Yandex IoT Core resources
- Connect to Yandex IoT Core
- Log in to Yandex IoT Core
- Establish a connection
- Subscribe to a topic and get data messages
- Send a data message
- Terminate the connection
Before you start
- If you don't have the Yandex Cloud command line interface yet, install and initialize it.
- Download and install Android Studio, a development environment for Android.
Create the necessary Yandex IoT Core resources
Create a registry and add a certificate to it
If you already have a certificate, go directly to the second step.
-
Create a certificate for the registry (skip this step if you already have a registry certificate):
openssl req -x509 \ -newkey rsa:4096 \ -keyout registry-key.pem \ -out registry-cert.pem \ -nodes \ -days 365 \ -subj '/CN=localhost'
-
Create a registry:
yc iot registry create --name my-registry
-
Add a certificate to the registry:
yc iot registry certificate add \ --registry-name my-registry \ # Registry name. --certificate-file registry-cert.pem # Path to the public part of the certificate.
Create a device and add a certificate to it
If you already have a certificate, go directly to the second step.
-
(optional) Create a certificate for the device:
openssl req -x509 \ -newkey rsa:4096 \ -keyout device-key.pem \ -out device-cert.pem \ -nodes \ -days 365 \ -subj '/CN=localhost'
-
Create a device:
yc iot device create --name my-device
-
Add a certificate to the device:
yc iot device certificate add \ --device-name my-device \ # Device name. --certificate-file device-cert.pem # Path to the public part of the certificate.
Connect to Yandex IoT Core
Before connecting, configure the connection parameters using the following code:
String clientId = "YandexIoTCoreAndroidTextClient";
int connectionTimeout = 60;
int keepAliveInterval = 60;
MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(getApplicationContext(),"ssl://mqtt.cloud.yandex.net:8883", clientId);
// Setting up the connection parameters.
MqttConnectOptions options = new MqttConnectOptions();
options.setKeepAliveInterval(keepAliveInterval);
Where:
MqttAndroidClient
is a class that specifies the Yandex IoT Core connection parameters. Client address, port, and ID.MqttConnectOptions
is a class that sets the connection options. You can use the default settings, but we recommend setting thekeepAliveInterval
parameter. Its value determines the frequency of sendingPINGREQ
commands. The lower this parameter value, the faster the client realizes that a connection terminated abnormally. However, this increases the frequency of sending payablePINGREQ
commands.
Log in to Yandex IoT Core
There are two authorization methods:
Authorization using X.509 certificates
For this type of authorization, it's most convenient to use PKCS#12 certificates in PFX format. You can generate a certificate in PKCS#12 format from PEM certificates using the command:
openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12
To load certificates in your project, use the following method:
private SSLSocketFactory getSocketFactory(final InputStream caCrtFile, final InputStream devCert, final String password)
Certificates are loaded in several stages:
-
Load the certificate used for server authentication:
// Loading the CA certificate. CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate caCert = (X509Certificate) cf.generateCertificate(caCrtFile); // Using the CA certificate for server authentication. KeyStore serverCaKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); serverCaKeyStore.load(null, null); serverCaKeyStore.setCertificateEntry("ca", caCert); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(serverCaKeyStore);
-
Load the client certificate used for server authorization:
KeyStore clientKeystore = KeyStore.getInstance("PKCS12"); clientKeystore.load(devCert, password.toCharArray());
As a result, the method returns AdditionalKeyStoresSSLSocketFactory
:
return new AdditionalKeyStoresSSLSocketFactory(clientKeystore, serverCaKeyStore);
The AdditionalKeyStoresSSLSocketFactory
class is inherited from SSLSocketFactory
and used for working with self-signed certificates. At the last stage, pass the obtained sslSocketFactory
instance to the connection parameters:
options.setSocketFactory(sslSocketFactory);
Authorization using a username and password
Since Yandex IoT Core requires the TLS protocol for authorization with a username and password, initialize the AdditionalKeyStoresSSLSocketFactory
class by invoking the method:
private SSLSocketFactory getSocketFactory(final InputStream caCrtFile, final InputStream devCert, final String password)
Pass the null
value as devCert
. This only loads the certificate from the server certification authority:
// Load CA certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate) cf.generateCertificate(caCrtFile);
// CA certificate is used to authenticate server
KeyStore serverCaKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
serverCaKeyStore.load(null, null);
serverCaKeyStore.setCertificateEntry("ca", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(serverCaKeyStore);
return new AdditionalKeyStoresSSLSocketFactory(null, serverCaKeyStore);
In the connection settings, specify the username (registry or device ID) and password:
options.setUserName(mqttUserName);
options.setPassword(mqttPassword.toCharArray());
and the SSLSocketFactory
from the code above:
options.setSocketFactory(sslSocketFactory);
Establish a connection
Establish a connection to Yandex IoT Core using the following code:
mqttAndroidClient.connect(options,null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
}
});
Subscribe to a topic and get data messages
Use a callback function to process the received data:
mqttAndroidClient.setCallback(new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception { }
});
Subscribe to a topic using the following code. In the subscribe
method, specify the topic that you want to subscribe to and the QoS.
IMqttToken subToken = mqttAndroidClient.subscribe(topic, qos);
subToken.setActionCallback(new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
// Publishing a message.
}
@Override
public void onFailure(IMqttToken asyncActionToken,
Throwable exception) {
// The message can't be subscribed to. The user may not have been
// authorized to subscribe to the specified topic.
System.out.println("Failed to subscribe");
}
});
Send a data message
Send messages using the following code. In the publish
method, specify the topic that you want to send a message to and the message text. You can optionally specify the desired level of quality of service for a MqttMessage
class instance.
IMqttDeliveryToken publish = mqttAndroidClient.publish("<topic>", new MqttMessage("Your message text.".getBytes()));
Handle connection loss events and track message delivery using callback functions:
mqttAndroidClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
}
, MqttMessage message) throws Exception { }
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});
Terminate the connection
Disconnect from Yandex IoT Core using the following methods:
mqttAndroidClient.disconnect();
mqttAndroidClient.close();
Where:
- The
disconnect
method terminates the server connection. - The
close
method releasesMqttAndroidClient
class resources.