- Print
- PDF
Core Device Settings
- Print
- PDF
Available in Classic and VPC.
In the core device setup, messages and data can be processed by edge devices running the core software.
Core device screen
The screen layout of Core device is as follows:
Items | Description |
---|---|
① Core device setting | Core device setup guide |
② Core Device Search | Search by core device name |
③ Delete button | Delete core device |
④ List | Core Device list |
⑤ Deployment tab of Details | Latest deployment of core devices |
⑥ Client Devices tab in Details | List of client devices set on the core device |
⑦ Endpoints tab in Details | The endpoint of the core device to which the client connects. |
Prerequisites
Describes what is required when setting up a core device.
Cloud IoT Core resources
The following Cloud IoT Core resources are required to set up the core device:
- Virtual device: Create a core device with the same name as the already created virtual device.
- Certificates: The Edge Core software communicates with Cloud IoT Core using certificates attached to the virtual device you set up as the core device.
The Edge Core software provides a provisioning feature that automatically creates Cloud IoT Core resources for quick installation.
IAM authentication key
The authentication key is used by the core device to provision required resources and interact with cloud services. A description of the required IAM authentication key and policy permissions follows.
Policy name | Policy description |
---|---|
NCP_CLOUD_IOT_CORE_MANAGER | Permission to use of all features in the Cloud IoT Core service |
To provide the IAM authentication key as an environment variable, copy the command below to the device terminal and change the text after the ‘=’ sign to the specified information.
export NCLOUD_ACCESS_KEY_ID=<NCLOUD_ACCESS_KEY_ID>
export NCLOUD_SECRET_KEY=<NCLOUD_SECRET_KEY>
Java
Edge Core software requires a Java runtime version 8 or higher.
- An example command to install Open JDK on Linux is as follows:
sudo apt-get install openjdk-8-jdk
- The command to check the installed Java version is as follows.
java -version
Core device setting
The following describes how to set a core device.
In the NAVER CLOUD PLATFORM console, click Services > Internet of Things > Cloud IoT Core menu in order.
Click the IoT Edge > Core Devices menu in order.
Click the [Core device settings] button.
Select a virtual device to be set as a core device.
- If you select Create New, the virtual device created with the entered name is set as the core device.
Download and install the Edge Core software.
- After downloading, the user can designate the decompression location (-d option), and the software file is decompressed under 'input path/edgecore/'.
curl -sL 'https://github.com/NaverCloudPlatform/iot-edge/releases/latest/download/edgecore.zip' -o edgecore.zip && unzip edgecore.zip -d /
- After downloading, the user can designate the decompression location (-d option), and the software file is decompressed under 'input path/edgecore/'.
Run the Edge Core software using the following command.
sudo -E java -Droot="/edgecore" -jar /edgecore/lib/edgecore.jar --virtual-device-name <CoreDeviceName> --setup-system-service true --provision true
The execution options provided by the Edge Core software are:
Options Description Default value --h Edge core software run option help output - --virdual-device-name, --vdn The name of the virtual device to use as the core device. If the virtual device does not exist, it is created by the Edge Core software. CoreDevice-{random string} --start Start the Edge Core software process immediately when entering true true -- provision, -p Provisioning of the resources needed to set up the core device. - If true: Edge core software creates and connects a virtual device and certificate in the cloud.
- If false and virtual device or certificate does not exist or connection is incorrect: Edge core software terminates
false -- setup-system-service If true: Set the Edge Core software as a system service that runs when the device boots up. false
Click the [List View] button.
- Once installed on your IoT equipment, you can see your core device in the list within a few minutes.
Delete core device
You can delete core devices that are no longer in use. The following describes how to delete a core device.
Please uninstall the Edge Core software.
- If you run the Edge Core software as a system service (systemctl), you need to stop/disable the service before uninstalling it. Execute the command below to uninstall the Edge Core software.
//stop, disable, remove service sudo systemctl stop edgecore.service sudo systemctl disable edgecore.service sudo rm /etc/systemd/system/edgecore.service
In the NAVER CLOUD PLATFORM console, click Services > Internet of Things > Cloud IoT Core menu in order.
Click the IoT Edge > Core Devices menu in order.
Click and select the core device to be deleted from the list of core devices.
Click the [Delete] button.
When the Delete pop-up window appears, click [Delete].
Client devices management
A client device is a virtual device that can access the core device's local message broker. Only pre-configured client devices can access the core device. In the Core Devices menu, you can see at a glance which client devices will connect to the corresponding core device.
You can set one virtual device as a client device for several core devices.
Client device settings
Here's how to set up your client device.
In the NAVER Cloud Platform console, click Services > Internet of Things > Cloud IoT Core menu in order.
Click the IoT Edge > Core Devices menu in order.
Click and select a core device from the list of Core Devices.
Click the [Client device settings] button.
Click to select a client device to connect to the corresponding core device.
NoteYou can search for client devices by name.
Click the [Save] button.
Isolate the client device
Here's how to isolate the client device set to the core device.
- In the NAVER Cloud Platform console, click Services > Internet of Things > Cloud IoT Core menu in order.
- Click the IoT Edge > Core Devices menu in order.
- Click and select a core device from the list of Core Devices.
- Click the [Client device settings] button.
- Click the client device to disconnect and uncheck the check box.
- Click the [Save] button.
Endpoint Management
The client device needs to know the endpoint in order to send messages to the core device's local message broker. The endpoint information of each core device is managed in the cloud.
Endpoint settings
The Edge core software automatically detects changes to the endpoints of the core device and updates them to the cloud.
If the endpoint changes, the Edge Core software restarts after updating to the cloud.
Endpoint lookup
A virtual device can use the Discovery API to query the endpoint of the core device that the virtual device has set as a client device. For more information on the Discover API, see the Discovery API documentation.
You can also check the endpoint of each core device in the console.
Connect client device to core device
Client devices can send and receive messages to and from other client devices through a local message broker within the core device. The Discovery API is used to search for core devices that a client device can connect to and query the necessary information.
- Refer to the client device settings and set the client device to the core device you want to connect.
- Please refer to Endpoint Inquiry to check if the endpoint of the core device exists.
- The client device must be able to access the endpoint of the core device.
- Please refer to Certificate Connection to connect Cloud IoT Core's certificate with the client device, download it, and copy it to the client device.
- Please run the Discovery example code on your client device.
- In this example, one client device publishes the same topic to the core device and subscribes to it.
Java
The library for running the Discovery example code is as follows:
- maven
<dependencies>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${version}</version>
</dependency>
</dependencies>
- Here is Java Discovery example code:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;
public class DiscoveryExample {
/*
*** Modify device name, file path and authentication key ***
*/
static String deviceName = "<DEVICE_NAME>}";
static String clientCaChainFilePath = "/<Your>/<file>/<path>/caChain.pem";
static String clientCertFilePath = "/<Your>/<file>/<path>/thingCert.crt";
static String clientKeyFilePath = "/<Your>/<file>/<path>/privKey.key";
static String accessKey = "<NCLOUD_ACCESS_KEY_ID>";
static String secretKey = "<NCLOUD_SECRET_KEY>}";
static String topic = "/java/action/topic";
static String message = String.format("{ \"name\": \"device\", \"tempC\": \"15\", \"eventTime\": \"%d\"}", Instant.now().toEpochMilli());
public static final String X_NCP_IAM_ACCESS_KEY = "x-ncp-iam-access-key";
public static final String X_NCP_APIGW_TIMESTAMP = "x-ncp-apigw-timestamp";
public static final String X_NCP_APIGW_SIGNATURE_V2 = "x-ncp-apigw-signature-v2";
public static final String X_NCP_IOT_HOST = "cloudiotcore.apigw.ntruss.com";
public static void main(String[] args) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException, MqttException, URISyntaxException {
DiscoveryExample app = new DiscoveryExample();
MqttClient mqttClient = app.getClientFromDiscovery(deviceName);
System.out.println("==== Successfully Connected");
mqttClient.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("==== Connection Lost");
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
System.out.println("<<< Subscribed from Local MQTT Broker Server. topic: " + topic + ", message: " + message.toString());
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println(">>> Published to Local MQTT Broker Server");
}
});
boolean isConnected = mqttClient.isConnected();
if (isConnected) {
mqttClient.subscribe(topic);
}
if (isConnected) {
for (int i = 5; i < 10; i++) {
Random r = new Random();
MqttMessage mqttMessage = new MqttMessage(message.getBytes());
mqttMessage.setQos(0);
mqttMessage.setRetained(false);
try {
MqttTopic mqttTopic = mqttClient.getTopic(topic);
MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
token.waitForCompletion();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
mqttClient.disconnect();
mqttClient.close();
}
private DiscoveryExample() {
init();
}
private MqttClient getClientFromDiscovery(String deviceName) throws MqttException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException, URISyntaxException {
String clientId = deviceName;
//discovery request
URI uri = new URIBuilder()
.setScheme("https")
.setHost(X_NCP_IOT_HOST)
.setPath(String.format("/iotdeviceedge/v1/discover/device/%s", deviceName))
.build();
Header[] headers = makeHeaders("GET", uri.getRawPath(), Instant.now().toEpochMilli(), accessKey, secretKey);
OpenApiResponse<EdgeGroupsDto> response = sendGetObject(uri, headers, new TypeReference<OpenApiResponse<EdgeGroupsDto>>() {
});
List<EdgeGroupDto> edgeGroupList = response.getBody().edgeGroupList;
if (!edgeGroupList.isEmpty()) {
for (EdgeGroupDto edgeGroupDto : edgeGroupList) {
for (ConnectivityInfoDto connectivityInfo : edgeGroupDto.connectivityList) {
//endpoint
String hostAddress = connectivityInfo.hostAddress;
int port = connectivityInfo.portNumber;
String endpoint = String.format("ssl://%s:%d", hostAddress, port);
// set mqtt client
MqttClient mqttClient = new MqttClient(endpoint, clientId, new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setConnectionTimeout(5);
connOpts.setKeepAliveInterval(60);
connOpts.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
// create ssl socket factory
Optional<String> ca = edgeGroupDto.caList.stream().findFirst();
if (ca.isPresent()) {
TrustManagerFactory tmf = getTrustManagerFactory(ca.get());
KeyManagerFactory kmf = getKeyManagerFactory(clientCaChainFilePath, clientCertFilePath, clientKeyFilePath, "");
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
connOpts.setSocketFactory(context.getSocketFactory());
}
//connect
try {
mqttClient.connect(connOpts);
return mqttClient;
} catch (Exception e) {
System.out.println(String.format("client device(%s) failed to connect core device(ssl://%s:%d) with exception %s", deviceName, connectivityInfo.hostAddress, connectivityInfo.getPortNumber(), e.toString()));
}
}
}
} else {
throw new RuntimeException(String.format("client device(%s) could not connect to core device using any of the edge group endpoint", deviceName));
}
throw new RuntimeException("There is no edge group to connect client device " + deviceName);
}
private KeyManagerFactory getKeyManagerFactory(String clientCaChainFilePath, String clientCertFilePath, String clientKeyFilePath, String password) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
KeyPair key = getClientKey(clientKeyFilePath);
Certificate clientCert = getClientCert(clientCertFilePath);
List<Certificate> caChain = getClientCaChain(clientCaChainFilePath, clientCert);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
int caChainSize = caChain.size();
Certificate[] caChainArray = caChain.toArray(new Certificate[caChainSize]);
keyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), caChainArray);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password.toCharArray());
return keyManagerFactory;
}
private TrustManagerFactory getTrustManagerFactory(String coreCaPem) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore rootCaKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
rootCaKeyStore.load(null, null);
X509Certificate coreCaCert = convertStringToX509Cert(coreCaPem);
rootCaKeyStore.setCertificateEntry("core", coreCaCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(rootCaKeyStore);
return tmf;
}
private void init() {
Security.addProvider(new BouncyCastleProvider());
}
private KeyPair getClientKey(String clientKeyFilePath) throws IOException {
PEMParser pemParser = new PEMParser(new FileReader(clientKeyFilePath));
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair key = converter.getKeyPair((PEMKeyPair) object);
pemParser.close();
return key;
}
private List<Certificate> getClientCaChain(String clientCaChainFilePath, Certificate clientCert) throws CertificateException, IOException {
X509Certificate cert = null;
List<Certificate> caChain = new ArrayList<Certificate>();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(clientCaChainFilePath));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(bis);
caChain.add(cert);
}
caChain.add(0, clientCert);
return caChain;
}
private X509Certificate getClientCert(String clientCertFilePath) throws CertificateException, IOException {
return getX509Certificate(clientCertFilePath);
}
private X509Certificate getX509Certificate(String filePath) throws CertificateException, IOException {
X509Certificate caCert = null;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
}
return caCert;
}
private X509Certificate convertStringToX509Cert(String certificate) throws CertificateException {
InputStream targetStream = new ByteArrayInputStream(certificate.getBytes());
return (X509Certificate) CertificateFactory
.getInstance("X509")
.generateCertificate(targetStream);
}
private Header[] makeHeaders(String method, String url, Long epoch, String accessKey, String secretKey) {
Header[] headers = {
new BasicHeader("Content-Type", "application/json"),
new BasicHeader(X_NCP_IAM_ACCESS_KEY, accessKey),
new BasicHeader(X_NCP_APIGW_TIMESTAMP, String.valueOf(epoch)),
new BasicHeader(X_NCP_APIGW_SIGNATURE_V2, makeSignature(method, url, String.valueOf(epoch), accessKey, secretKey))
};
return headers;
}
private String makeSignature(String method, String url, String epoch, String accessKey, String secretKey) {
String signature = null;
String message = method + " " + url + "\n" + epoch + "\n" + accessKey;
try {
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
signature = Base64.encodeBase64String(rawHmac);
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
System.out.println(String.format("Failed to make signature with message : $s", message));
}
return signature;
}
private <T> T sendGetObject(URI uri, Header[] headers, TypeReference<T> responseType) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(uri);
if (headers != null) {
httpGet.setHeaders(headers);
}
return getResponseObject(httpClient.execute(httpGet), responseType);
}
private <T> T getResponseObject(CloseableHttpResponse httpResponse, TypeReference<T> responseType) throws IOException {
try {
HttpEntity responseEntity = httpResponse.getEntity();
String resultString = EntityUtils.toString(responseEntity);
EntityUtils.consume(responseEntity);
if (httpResponse.getStatusLine().getStatusCode() >= 200 && httpResponse.getStatusLine().getStatusCode() <= 299) {
return new ObjectMapper().readValue(resultString, responseType);
}
throw new HttpResponseException(httpResponse.getStatusLine().getStatusCode(), resultString);
} finally {
httpResponse.close();
}
}
static class OpenApiResponse<T> {
private String status;
private T body;
public String getStatus() {
return status;
}
public T getBody() {
return body;
}
}
static class EdgeGroupsDto {
@JsonProperty("EdgeGroups")
private List<EdgeGroupDto> edgeGroupList;
public EdgeGroupsDto(List<EdgeGroupDto> edgeGroupDtos) {
this.edgeGroupList = edgeGroupDtos;
}
public EdgeGroupsDto() {
this.edgeGroupList = new ArrayList<>();
}
public List<EdgeGroupDto> getEdgeGroupList() {
return edgeGroupList;
}
}
static class EdgeGroupDto {
@JsonProperty("EdgeGroupId")
private String edgeGroupId;
@JsonProperty("Connectivity")
private List<ConnectivityInfoDto> connectivityList;
@JsonProperty("CAs")
private List<String> caList;
public String getEdgeGroupId() {
return edgeGroupId;
}
public List<ConnectivityInfoDto> getConnectivityList() {
return connectivityList;
}
public List<String> getCaList() {
return caList;
}
}
static class ConnectivityInfoDto {
private String hostAddress;
private int portNumber;
private String metadata;
public String getHostAddress() {
return hostAddress;
}
public int getPortNumber() {
return portNumber;
}
public String getMetadata() {
return metadata;
}
}
}