Core Device Settings
    • PDF

    Core Device Settings

    • PDF

    Article Summary

    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: iotedge-coredevices_01_en.png

    ItemsDescription
    ① Core device settingCore device setup guide
    ② Core Device SearchSearch by core device name
    ③ Delete buttonDelete core device
    ④ ListCore Device list
    ⑤ Deployment tab of DetailsLatest deployment of core devices
    ⑥ Client Devices tab in DetailsList of client devices set on the core device
    ⑦ Endpoints tab in DetailsThe 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.
    Note

    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 namePolicy description
    NCP_CLOUD_IOT_CORE_MANAGERPermission 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.

    1. In the NAVER CLOUD PLATFORM console, click Services > Internet of Things > Cloud IoT Core menu in order.

    2. Click the IoT Edge > Core Devices menu in order.

    3. Click the [Core device settings] button.

    4. 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.
    5. 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 /
        
    6. 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:

        OptionsDescriptionDefault value
        --hEdge core software run option help output-
        --virdual-device-name, --vdnThe 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}
        --startStart the Edge Core software process immediately when entering truetrue
        -- provision, -pProvisioning 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-serviceIf true: Set the Edge Core software as a system service that runs when the device boots up.false
    7. 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.

    1. 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
      
    2. In the NAVER CLOUD PLATFORM console, click Services > Internet of Things > Cloud IoT Core menu in order.

    3. Click the IoT Edge > Core Devices menu in order.

    4. Click and select the core device to be deleted from the list of core devices.

    5. Click the [Delete] button.

    6. 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.

    Note

    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.

    1. In the NAVER Cloud Platform console, click Services > Internet of Things > Cloud IoT Core menu in order.

    2. Click the IoT Edge > Core Devices menu in order.

    3. Click and select a core device from the list of Core Devices.

    4. Click the [Client device settings] button.

    5. Click to select a client device to connect to the corresponding core device.

      Note

      You can search for client devices by name.

    6. Click the [Save] button.

    Isolate the client device

    Here's how to isolate the client device set to the core device.

    1. In the NAVER Cloud Platform console, click Services > Internet of Things > Cloud IoT Core menu in order.
    2. Click the IoT Edge > Core Devices menu in order.
    3. Click and select a core device from the list of Core Devices.
    4. Click the [Client device settings] button.
    5. Click the client device to disconnect and uncheck the check box.
    6. 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.

    Note

    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.

    Note

    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.

    1. Refer to the client device settings and set the client device to the core device you want to connect.
    2. 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.
    3. 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.
    4. 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;
            }
        }
    
    }
    

    Was this article helpful?

    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.