Working with Yandex IoT Core in Java
In this scenario, you will learn how to connect to Yandex IoT Core using the Paho
Note
The source code used in this scenario is available on GitHub
Once connected, you can:
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 messages.
- Send a 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 Java Development Kit
.
Create the required Yandex IoT Core resources
Create a registry and add a certificate to it
If you already have a certificate, start with the second step.
-
Create a certificate for the registry:
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, start with the second step.
-
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'
-
Review a list of the registries where you can create a device or create a new registry.
-
Create a device:
yc iot device create --registry-name my-registry --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 connOpts
connection parameters using the following code:
String clientId = "YandexIoTCoreTestJavaClient";
int keepAliveInterval = 60;
MqttClient client = new MqttClient("ssl://mqtt.cloud.yandex.net:8883", clientId);
// Installing an asynchronous event handler
client.setCallback(listener);
// Setting up the connection parameters.
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setKeepAliveInterval(keepAliveInterval);
Where:
MqttClient
: Class that specifies the Yandex IoT Core connection parameters:- Address and port
- Client 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 thekeepAliveInterval
value, the faster the client realizes that a connection terminated abnormally. However, this increases the frequency of sending payablePINGREQ
commands.listener
: Class that implements theMqttCallback
interface. It is used for handling such events as server connection loss (connectionLost
), message delivery (deliveryComplete
), and new message arrival (messageArrived
).
Authenticate in Yandex IoT Core
There are two authentication methods:
Authentication using certificates
When authenticating with X.509 certificates, use PKCS#12
openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12
File structure
In the example available on GitHub
/my_registry Registry directory |current directory|. The example should be run from this directory.
`- /device Device directory |device|.
| `- cert.pem Device certificate in PEM format.
| `- key.pem Device key in PEM format.
| `- keystore.p12 Device certificate and key in PKCS#12 format.
`- cert.pem Registry certificate in PEM format.
`- key.pem Registry key in PEM format.
`- keystore.p12 Registry certificate and key in PKCS#12 format.
Loading certificates
A certificate from the certificate authority (CA) is set as a static variable named TRUSTED_ROOT
.
The example uses the following certificate loading method:
private SSLSocketFactory getSocketFactoryWithCerts(String certsDir)
Certificates are loaded in several stages:
-
Load the certificate used for server authentication:
// Loading the CA certificate from the `TRUSTED_ROOT` static variable. InputStream is = new ByteArrayInputStream(TRUSTED_ROOT.getBytes(StandardCharsets.UTF_8)); CertificateFactory cFactory = CertificateFactory.getInstance("X.509"); X509Certificate caCert = (X509Certificate) cFactory.generateCertificate(is); // Using the CA certificate for server authentication. KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType()); tks.load(null); tks.setCertificateEntry("caCert", caCert); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(tks);
-
Load the client certificate used for authentication on the server from the
keystore.p12
file:final char[] emptyPassword = "".toCharArray(); KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream(Paths.get(certsDir, "keystore.p12").toString()), emptyPassword); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, emptyPassword);
-
Get an instance of the
SSLSocketFactory
class:SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); SSLSocketFactory sslSocketFactory = ctx.getSocketFactory();
After that, pass the obtained SSLSocketFactory
instance to the connection parameters:
connOpts.setSocketFactory(sslSocketFactory);
Authenticating by username and password
Since authentication using a username and password in Yandex IoT Core requires the TLS protocol, you need to load the certificate used for server authentication:
// Loading the CA certificate from the `TRUSTED_ROOT` static variable.
private SSLSocketFactory getSocketFactory()
throws Exception {
InputStream is = new ByteArrayInputStream(TRUSTED_ROOT.getBytes(StandardCharsets.UTF_8));
CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate) cFactory.generateCertificate(
is);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore tks = KeyStore.getInstance(KeyStore.getDefaultType());
tks.load(null); // You don't need to load an instance of the `KeyStore` class from the file.
tks.setCertificateEntry("caCert", caCert);
tmf.init(tks);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
return ctx.getSocketFactory();
}
In the connection settings, specify the username (registry or device ID) and password:
connOpts.setUserName(login.trim());
connOpts.setPassword(password.trim().toCharArray());
and the sslSocketFactory
from the code above:
SSLSocketFactory sslSocketFactory = getSocketFactory();
connOpts.setSocketFactory(sslSocketFactory);
Establish a connection
Establish a connection to Yandex IoT Core using the following method:
client.connect(connOpts);
The connect
method is a blocking method. It blocks until the connection is established.
To handle server connection loss events, you can use the connectionLost
method of the MqttCallback
interface:
@Override
public void connectionLost(Throwable cause) {
}
In this case, you should set the event handler (using the setCallback
method) before invoking the connect
method:
client.setCallback(listener);
...
client.connect(connOpts);
...
Where listener
is a class that implements the MqttCallback
interface.
Subscribe to a topic and get messages
Subscribe to a topic using the following code. In the subscribe
method, specify the topic
you want to subscribe to and the level of quality of service (QoS
).
client.subscribe(topic, qos);
To handle new message arrival events, you can use the messageArrived
method of the MqttCallback
interface:
@Override
public void messageArrived(String topic, MqttMessage message){
}
In this case, you should set the event handler (using the setCallback
method) before invoking the connect
method:
client.setCallback(listener);
...
client.connect(connOpts);
...
Where listener
is a class that implements the MqttCallback
interface.
To handle new message arrival events, you can also use the messageArrived
method of the IMqttMessageListener
interface:
client.subscribe(topic, qos, messageListener);
Where messageListener
is a class that implements the IMqttMessageListener
interface.
Send a message
Send a message using the following code. In the publish
method, specify the topic
you want to send a message to and the message text using the MqttMessage
class. You can also specify the desired qos
level for an instance of the MqttMessage
class, if required.
MqttMessage msg = new MqttMessage(message);
msg.setQos(qos);
client.publish(topic, msg);
To handle message delivery events, you can use the deliveryComplete
method of the MqttCallback
interface:
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
In this case, you should set the event handler (using the setCallback
method) before invoking the connect
method:
client.setCallback(listener);
...
client.connect(connOpts);
...
Where listener
is a class that implements the MqttCallback
interface.
Terminate the connection
Disconnect from Yandex IoT Core using the following methods:
client.disconnect();
client.close();
Where:
- The
disconnect
method terminates the server connection. - The
close
method releasesMqttClient
class resources.