Working with Yandex IoT Core from an Android device in Java
In this scenario, you will learn how to connect to Yandex IoT Core from an Android device using the Paho
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:
- Create the required Yandex IoT Core resources:
- Connect to Yandex IoT Core.
- Authenticate in Yandex IoT Core:
- Establish a connection.
- Subscribe to a topic and receive data messages.
- Send a data message.
- Terminate the connection.
Getting started
- If you do not have the Yandex Cloud command line interface yet, install and initialize it.
- Download and install Android Studio
, a development environment for Android.
Create the required 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
: Class that specifies the Yandex IoT Core connection parameters, i.e., the client address, port, and ID.MqttConnectOptions
: 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.
Authenticate in Yandex IoT Core
There are two authentication methods:
Authentication using X.509 certificates
For this type of authentication, it is most convenient to use PKCS#12
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 authentication on the server:
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);
Authenticating by username and password
Since Yandex IoT Core requires the TLS protocol for authentication with a username and password, initialize the AdditionalKeyStoresSSLSocketFactory
class with this 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:
// 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);
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 you want to subscribe to and the QoS level.
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) {
}
@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 releases theMqttAndroidClient
class resources.