Skip to main content

ISS Position Sample

Introduction

The ISS Position sample fetches the current position of the International Space Station via an HTTP API and performs reverse geocoding over HTTPS to display the location name. It demonstrates REST client usage with both HTTP and HTTPS endpoints. This sample is compatible with the following boards:

Download

ISS PositionNCS v3.2.1

Project configuration

The application is configured in the prj.conf file:

CONFIG_MAIN_STACK_SIZE=4096
CONFIG_NEWLIB_LIBC=y

CONFIG_NETWORKING=y
CONFIG_NET_NATIVE=n

CONFIG_NET_SOCKETS=y

CONFIG_REST_CLIENT=y

CONFIG_NRF_MODEM_LIB=y
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_NETWORK_TIMEOUT=120
CONFIG_MODEM_KEY_MGMT=y

CONFIG_JSON_LIBRARY=y

CONFIG_MAIN_STACK_SIZE=4096 increases the main thread stack size to accommodate the REST client and JSON parsing buffers.

CONFIG_NETWORKING and CONFIG_NET_NATIVE=n enable networking with the IP stack offloaded to the modem.

CONFIG_NET_SOCKETS enables the sockets API.

CONFIG_REST_CLIENT enables Nordic's REST client library, which handles the HTTP(S) requests.

CONFIG_NRF_MODEM_LIB enables Nordic's modem library. CONFIG_LTE_LINK_CONTROL enables the LTE link control library with a connection timeout of 120 seconds.

CONFIG_MODEM_KEY_MGMT enables the modem key management library, needed for TLS certificate provisioning.

CONFIG_JSON_LIBRARY enables Zephyr's JSON library for parsing API responses.

The sysbuild.conf file enables MCUBoot so the sample can be flashed over USB:

SB_CONFIG_BOOTLOADER_MCUBOOT=y

Code explanation

JSON parsing

Both HTTP responses are JSON objects. Zephyr's JSON library parses JSON strings into pre-defined structs. For example, the ISS position struct and its descriptor:

struct iss_position {
char *latitude;
char *longitude;
};

static const struct json_obj_descr iss_position_descriptor[] = {
JSON_OBJ_DESCR_PRIM(struct iss_position, latitude, JSON_TOK_STRING),
JSON_OBJ_DESCR_PRIM(struct iss_position, longitude, JSON_TOK_STRING),
};

Each struct member matches a field in the JSON response. The descriptor tells the JSON library how to parse each field.

TLS certificate provisioning

The HTTPS request requires a TLS certificate. An ISRG Root X1 certificate (included in the cert/ directory) is provisioned to the modem before connecting to the LTE network:

#define TLS_SEC_TAG 301222

static int cert_provision(void)
{
int err;
bool exists;

err = modem_key_mgmt_exists(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, &exists);
if (err) {
printk("Failed to check for certificates, err %d\n", err);
return err;
}

if (exists) {
int mismatch = modem_key_mgmt_cmp(TLS_SEC_TAG,
MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
cert, strlen(cert));
if (!mismatch) {
return 0;
}

err = modem_key_mgmt_delete(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN);
if (err) {
printk("Failed to delete existing certificate, err %d\n", err);
}
}

err = modem_key_mgmt_write(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
cert, sizeof(cert) - 1);
if (err) {
printk("Failed to provision certificate, err %d\n", err);
return err;
}

return 0;
}

The function checks if the certificate already exists and only re-provisions it if it has changed.

NOTE

Security tag values above 2,147,483,647 are reserved for the modem and should not be used.

ISS position request

The get_iss_position function makes an HTTP GET request to retrieve the ISS latitude and longitude. Since this is a plain HTTP request, TLS is disabled:

struct rest_client_req_context req = {
.http_method = HTTP_GET,
.host = iss_position_api_host,
.url = iss_position_api_endpoint,
.port = 80,
.sec_tag = SEC_TAG_TLS_INVALID,
.tls_peer_verify = TLS_PEER_VERIFY_NONE,
.resp_buff = resp_buf,
.resp_buff_len = sizeof(resp_buf),
.timeout_ms = 30 * MSEC_PER_SEC,
...
};

struct rest_client_resp_context resp;

rest_client_request(&req, &resp);

If the request succeeds, the response body is parsed using the JSON library.

Reverse geolocation request

The get_reverse_geolocation function uses the ISS coordinates to look up the location name via an HTTPS request. The previously provisioned TLS certificate is used:

.sec_tag = TLS_SEC_TAG,
.tls_peer_verify = TLS_PEER_VERIFY_REQUIRED,

Main loop

The sample initializes the modem, provisions the certificate, connects to the LTE network, and then fetches the ISS position and reverse geolocation in a loop every 5 seconds:

err = nrf_modem_lib_init();
err = cert_provision();

printk("Waiting for network... ");
err = lte_lc_connect();
printk("OK\n");

while (true) {
if (get_iss_position(&iss_result)) {
printk("ISS Position: %s, %s (timestamp: %d)\n",
lat, lon, iss_result.timestamp);

if (get_reverse_geolocation(&geo_result, lat, lon)) {
printk("That is over: %s\n", geo_result.display_name);
}
}

k_sleep(K_SECONDS(5));
}
NOTE

The reverse geolocation API can only return locations above land. If the ISS is currently above an ocean, an error will be printed.

Was this page helpful?