/* * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2024 Conexio Technologies, Inc * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include #include #include #include #include #include #include #include #include #include /* Header file for the MQTT Library*/ #include #include #include "mqtt_connection.h" /* The mqtt client struct */ static struct mqtt_client client; /* File descriptor */ static struct pollfd fds; /* Define the PVT data frame variable */ static struct nrf_modem_gnss_pvt_data_frame pvt_data; /* Declare helper variables to find the TTFF */ static int64_t gnss_start_time; static bool first_fix = false; const struct device *const bme = DEVICE_DT_GET_ONE(bosch_bme680); struct sensor_value temp, press, humidity, gas_res; static void gnss_event_handler(int event); static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data); static K_SEM_DEFINE(lte_connected, 0, 1); static K_SEM_DEFINE(gnss_fixed, 0, 1); LOG_MODULE_REGISTER(mqtt_app, LOG_LEVEL_INF); static void lte_handler(const struct lte_lc_evt *const evt) { switch (evt->type) { case LTE_LC_EVT_NW_REG_STATUS: if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) && (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) { break; } LOG_INF("Network registration status: %s", evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ? "Connected - home network" : "Connected - roaming"); k_sem_give(<e_connected); break; case LTE_LC_EVT_RRC_UPDATE: LOG_INF("RRC mode: %s", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? "Connected" : "Idle"); break; default: break; } } static int modem_configure(void) { int err; err = nrf_modem_lib_init(); if (err) { LOG_ERR("Failed to initialize the modem library, error: %d", err); return err; } err = lte_lc_system_mode_set(LTE_LC_SYSTEM_MODE_NBIOT, LTE_LC_SYSTEM_MODE_PREFER_NBIOT); if (err) { LOG_ERR("Failed to set system mode LTE-M: %d", err); return err; } LOG_INF("Connecting to LTE network"); err = lte_lc_connect_async(lte_handler); if (err) { LOG_ERR("Error in lte_lc_connect_async, error: %d", err); return err; } k_sem_take(<e_connected, K_FOREVER); LOG_INF("Connected to LTE network"); // Blink LED to indicate we connected to MQTT broker dk_set_led_on(DK_LED1); k_msleep(1000); dk_set_led_off(DK_LED1); return 0; } static void button_handler(uint32_t button_state, uint32_t has_changed) { switch (has_changed) { case DK_BTN1_MSK: /* When button 1/Mode is pressed, call data_publish() to publish a message */ if (button_state & DK_BTN1_MSK){ int err = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, CONFIG_BUTTON_EVENT_PUBLISH_MSG, sizeof(CONFIG_BUTTON_EVENT_PUBLISH_MSG)-1); err |= publish_all(); if (err) { LOG_INF("Failed to send message, %d", err); return; } } } } uint16_t mqtt_cylcle = 0; int publish_all() { int err; err = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, CONFIG_BUTTON_EVENT_PUBLISH_MSG, sizeof(CONFIG_BUTTON_EVENT_PUBLISH_MSG)-1); if (err) { LOG_INF("Failed to send message, %d", err); return 0; } sensor_sample_fetch(bme); sensor_channel_get(bme, SENSOR_CHAN_AMBIENT_TEMP, &temp); sensor_channel_get(bme, SENSOR_CHAN_PRESS, &press); sensor_channel_get(bme, SENSOR_CHAN_HUMIDITY, &humidity); sensor_channel_get(bme, SENSOR_CHAN_GAS_RES, &gas_res); LOG_INF("Temp: %d.%02d degC; Press: %d.%02d kPa; RH: %d.%02d %%; G: %d.%02d Ohm", temp.val1, temp.val2, press.val1, press.val2, humidity.val1, humidity.val2, gas_res.val1, gas_res.val2); //k_msleep(20); err |= publish_sensor(&client, "nrf/dk/temp", temp.val1, temp.val2); //k_msleep(20); err |= publish_sensor(&client, "nrf/dk/pres", press.val1, press.val2); //k_msleep(20); err |= publish_sensor(&client, "nrf/dk/humi", humidity.val1, humidity.val2); //k_msleep(20); err |= publish_sensor(&client, "nrf/dk/gas", gas_res.val1, 0); //k_msleep(1000); struct lte_lc_conn_eval_params params; lte_lc_conn_eval_params_get(¶ms); printf("--- LTE Connection Evaluation Parameters ---\n" "RRC State: %d\n" "Energy Estimate: %d\n" "TAU Triggered: %d\n" "CE Level: %d\n" "EARFCN: %d\n" "DL Pathloss: %d dB\n" "RSRP: %d\n" "RSRQ: %d\n" "TX Repetitions: %d\n" "RX Repetitions: %d\n" "Physical Cell ID: %d\n" "Band: %d\n" "SNR: %d\n" "TX Power: %d dBm\n" "MCC: %d\n" "MNC: %d\n", params.rrc_state, params.energy_estimate, params.tau_trig, params.ce_level, params.earfcn, params.dl_pathloss, params.rsrp, params.rsrq, params.tx_rep, params.rx_rep, params.phy_cid, params.band, params.snr, params.tx_power, params.mcc, params.mnc); err |= publish_int(&client, "nrf/dk/rsrp", params.rsrp); //k_msleep(20); err |= publish_int(&client, "nrf/dk/rsrq", params.rsrq); //k_msleep(20); err |= publish_int(&client, "nrf/dk/snr", params.snr); //k_msleep(20); err |= publish_int(&client, "nrf/dk/enerest", params.energy_estimate); //k_msleep(20); err |= publish_int(&client, "nrf/dk/band", params.band); //k_msleep(20); err |= publish_int(&client, "nrf/dk/txp", params.tx_power); //k_msleep(20); err |= publish_int(&client, "nrf/dk/dlpl", params.dl_pathloss); //k_msleep(20); enum lte_lc_system_mode mode; enum lte_lc_system_mode_preference preference; lte_lc_system_mode_get(&mode, &preference); err |= publish_sensor(&client, "nrf/dk/ltemode", mode, preference); return err; } #if 1 /* Define a function to log fix data in a readable format */ static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data) { LOG_INF("Latitude: %.06f", pvt_data->latitude); LOG_INF("Longitude: %.06f", pvt_data->longitude); LOG_INF("Altitude: %.01f m", pvt_data->altitude); LOG_INF("Time (UTC): %02u:%02u:%02u.%03u", pvt_data->datetime.hour, pvt_data->datetime.minute, pvt_data->datetime.seconds, pvt_data->datetime.ms); } static void gnss_event_handler(int event) { int err; switch (event) { /* On a PVT event, confirm if PVT data is a valid fix */ case NRF_MODEM_GNSS_EVT_PVT: /* Print satellite information */ int num_satellites = 0; for (int i = 0; i < 12 ; i++) { if (pvt_data.sv[i].signal != 0) { num_satellites++; } } LOG_INF("Sat: %d", num_satellites); err = nrf_modem_gnss_read(&pvt_data, sizeof(pvt_data), NRF_MODEM_GNSS_DATA_PVT); if (err) { LOG_ERR("nrf_modem_gnss_read failed, err %d", err); return; } if (pvt_data.flags & NRF_MODEM_GNSS_PVT_FLAG_FIX_VALID) { dk_set_led_on(DK_LED1); print_fix_data(&pvt_data); /* Print the time to first fix */ k_sem_give(&gnss_fixed); if (!first_fix) { LOG_INF("Time to first fix: %2.1lld s", (k_uptime_get() - gnss_start_time)/1000); first_fix = true; } return; } break; /* Log when the GNSS sleeps and wakes up */ case NRF_MODEM_GNSS_EVT_PERIODIC_WAKEUP: LOG_INF("GNSS has woken up"); break; case NRF_MODEM_GNSS_EVT_SLEEP_AFTER_FIX: LOG_INF("GNSS enter sleep after fix"); break; default: break; } } #endif int main(void) { int err; uint32_t connect_attempt = 0; LOG_INF("Starting MQTT sample 2 on %s\n", CONFIG_BOARD); if (!device_is_ready(bme)) { LOG_ERR("sensor: device not ready.\n"); return 0; } LOG_INF("BME680 %p name is %s\n", bme, bme->name); if (dk_leds_init() != 0) { LOG_ERR("Failed to initialize the LED library"); } LOG_INF("Initializing modem library"); err = modem_configure(); if (err) { LOG_ERR("Failed to configure the modem"); return 0; } #ifdef USE_GNSS /* Activate only the GNSS stack */ if (lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS) != 0) { LOG_ERR("Failed to activate GNSS functional mode"); return 0; } /* Register the GNSS event handler */ if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) { LOG_ERR("Failed to set GNSS event handler"); return 0; } /* Set the GNSS fix interval and GNSS fix retry period */ if (nrf_modem_gnss_fix_interval_set(1) != 0) { LOG_ERR("Failed to set GNSS fix interval"); return 0; } if (nrf_modem_gnss_fix_retry_set(900) != 0) { LOG_ERR("Failed to set GNSS fix retry"); return 0; } nrf_modem_gnss_power_mode_set(NRF_MODEM_GNSS_PSM_DISABLED); nrf_modem_gnss_prio_mode_disable(); /* Start the GNSS receiver */ LOG_INF("Starting GNSS"); if (nrf_modem_gnss_start() != 0) { LOG_ERR("Failed to start GNSS"); return 0; } #endif if (dk_buttons_init(button_handler) != 0) { LOG_ERR("Failed to initialize the buttons library"); } err = client_init(&client); if (err) { LOG_ERR("Failed to initialize MQTT client: %d", err); return 0; } /* Log the current system uptime */ //gnss_start_time = k_uptime_get(); dk_set_led_on(DK_LED1); k_sleep(K_SECONDS(2)); dk_set_led_off(DK_LED1); do_connect: if (connect_attempt++ > 0) { LOG_INF("Reconnecting in %d seconds...", 2); dk_set_led_on(DK_LED1); k_sleep(K_SECONDS(2)); // resleep dk_set_led_off(DK_LED1); } LOG_INF("Connection to broker using mqtt_connect"); err = mqtt_connect(&client); if (err) { LOG_ERR("Error in mqtt_connect: %d", err); goto do_connect; } err = fds_init(&client,&fds); if (err) { LOG_ERR("Error in fds_init: %d", err); return 0; } while (1) { #ifdef USE_GNSS err = mqtt_disconnect(&client); if (err != 0){ LOG_INF("No mqtt disconnect"); } err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_LTE); err |= lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS); if (err != 0){ LOG_ERR("Failed to decativate LTE and enable GNSS functional mode"); break; } k_sem_take(&gnss_fixed, K_FOREVER); err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_LTE); err |= lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_GNSS); if (err != 0){ LOG_ERR("Failed to activate LTE"); break; } else { LOG_ERR("Waiting for LTE connect"); } k_sem_take(<e_connected, K_FOREVER); LOG_ERR("LTE connected"); err = mqtt_connect(&client); if (err != 0){ LOG_ERR("Failed to connect to mqtt"); break; } err = fds_init(&client,&fds); if (err) { LOG_ERR("Error in fds_init: %d", err); return 0; } #endif //for (int i = 0; i < 1000; i++) //{ err = poll(&fds, 1, mqtt_keepalive_time_left(&client)); if (err < 0) { LOG_ERR("Error in poll(): %d", errno); break; } err = mqtt_live(&client); if ((err != 0) && (err != -EAGAIN)) { LOG_ERR("Error in mqtt_live: %d", err); break; } if ((fds.revents & POLLIN) == POLLIN) { err = mqtt_input(&client); if (err != 0) { LOG_ERR("Error in mqtt_input: %d", err); break; } } if ((fds.revents & POLLERR) == POLLERR) { LOG_ERR("POLLERR"); break; } if ((fds.revents & POLLNVAL) == POLLNVAL) { LOG_ERR("POLLNVAL"); break; } err = publish_all(); if (err) { LOG_ERR("Publish error"); continue; } //} k_msleep(5000); } LOG_INF("Disconnecting MQTT client"); err = mqtt_disconnect(&client); if (err) { LOG_ERR("Could not disconnect MQTT client: %d", err); } goto do_connect; /* This is never reached */ return 0; }