/*********
  DRI Low-Cost Air Sensor package
  Google Cloud Platform IoT Core communication through LTE/MQTT network
 
  Yeongkwon Son, PhD            |   Celime Garcia, maybe a PhD one day  |   Junyoung Jeon, maybe a BS in a year
  Associate Research Professor  |   Graduate Assistant                  |   Undergraduate Research Assistant
  Desert Research Institute     |   Desert Research Institute           |   Desert Research Institute 
 
  Last update: 2025.10.15.
  Code description:
    - Sensor reports every 20min based on RTC(Real Time Clock)
    - Voltage detection and sleep
    - PSM configuration for low power consumption
    - Watchdog configuration for automatic reset    
 
  PCB specifications;
  - Custom board which is based on nRF9151 DK chip set
  - Soracom global SIM card
  - 3.3V connector
  - Carrier PCB with I2C multiplexor,
    - UART #0: Communication with debuger which is SEGGER J-Link mini
    - GPIO #1: GPIO 1 is disabled because it is used by default in TF-M, reserved for the Secure world (Using silent log API it is solved)
    - I2C #1: Sensirion SEN66 PM, VOC, NOx, Temp, RH sensor
    - I2C #2: Bosch BMP581 Temp, Pressure sensor
    - SPI #3: GigaDevice gd25wb256e flash memory 256Mbit(32Mbyte)
    
*********/
#include <zephyr/debug/thread_analyzer.h>

#include <stdio.h>
#include <ncs_version.h>
#include <zephyr/kernel.h>
#include <zephyr/net/socket.h>

/* MultiThread */
#define STACK_SIZE 4096
#define THREAD_PRIORITY 3


/* SPI */
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/storage/flash_map.h>

/* ADC */
#include <zephyr/drivers/adc.h>

/* Device ID */
#include <zephyr/drivers/hwinfo.h>

/* SIM CARD Communication */
#include <modem/nrf_modem_lib.h>
#include <modem/lte_lc.h>


/* Mqtt connection*/
#include <zephyr/net/mqtt.h>
#include "mqtt_connection.h"


/* I2C Headers */
#include <zephyr/logging/log.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2c.h>


/* Pressure BMP581 */
#include "bmp5.h"
#include "bmp5_defs.h"

/* Gnss */
#include <nrf_modem_gnss.h>

/* Watchdog for reset */
#include <zephyr/drivers/watchdog.h>

/* Date time */
#include <date_time.h>
#include <zephyr/drivers/counter.h>

/* Device ID */
char device_id_str[10] = {0};

uint8_t id[8];
int device_id(void)
{
    
hwinfo_get_device_id(id, sizeof(id));

snprintf(device_id_str,sizeof(device_id_str) , "%02x%02x%02x%02x",
       id[0], id[1], id[2], id[3]);


printk("... \r\n");

printk("[Device ID]  %02x%02x%02x%02x\n",
       id[0], id[1], id[2], id[3]);
       
printk("... \r\n");
k_sleep(K_SECONDS(3));

}


/* SEN66 */
#define SEN66_NODE DT_NODELABEL(sen66)
#define SEN66_1_NODE DT_NODELABEL(sen66_1)

#define EXUCUTION_TIME 25
#define STARTING_TIME 1200
#define DEVICE_ID_WATTING_TIME 100
#define RECONNECTING_TIME 15000

#define GAP 500

/* SEN66 Function */

int read_measurement(const struct i2c_dt_spec *dev, uint8_t *buf, size_t len)
{
    int ret;
    uint8_t cmd_read[] = {0x03, 0x00};

    ret = i2c_write(dev->bus, cmd_read, sizeof(cmd_read), dev->addr);
    if (ret != 0) {
        printk("[SEN] Failed to send read command: %d\r\n", ret);
        return ret;
    }

    k_msleep(30);  

    ret = i2c_read(dev->bus, buf, len, dev->addr);
    if (ret != 0) {
        printk("[SEN] Failed to read measurement: %d\r\n", ret);
        return ret;
    }
      
    return 0;  
}

int read_raw_measurement(const struct i2c_dt_spec *dev, uint16_t *buf, size_t len)
{
    
    int ret;
    uint8_t cmd_read[] = {0x04, 0x05};

    ret = i2c_write(dev->bus, cmd_read, sizeof(cmd_read), dev->addr);
    if (ret != 0) {
        printk("[SEN] Failed to send read command: %d\r\n", ret);
        return ret;
    }

    k_msleep(30); 

    ret = i2c_read(dev->bus, buf, len, dev->addr);
    if (ret != 0) {
        printk("[SEN] Failed to read measurement: %d\r\n", ret);
        return ret;
    }

    return 0;  
}


uint16_t read_u16(uint8_t msb, uint8_t lsb) {
    return ((uint16_t)msb << 8) | lsb;
}

int16_t read_s16(uint8_t msb, uint8_t lsb) {
    return (int16_t)(((uint16_t)msb << 8) | lsb);  // - value possible
}


/* BMP581 */
#define BMP581_NODE DT_NODELABEL(i2c2)
#define BMP581_ADDR 0x46

const struct device *i2c_dev;


/* BMP581 Function */
struct bmp5_dev bmp_dev;
struct bmp5_osr_odr_press_config osr_cfg;
struct bmp5_sensor_data sensor_data;

BMP5_INTF_RET_TYPE user_i2c_read(uint8_t reg_addr, uint8_t *data, uint32_t len, void *intf_ptr) {
    const struct device *i2c = (const struct device *)intf_ptr;
    return i2c_write_read(i2c, BMP581_ADDR, &reg_addr, 1, data, len) == 0 ? BMP5_OK : BMP5_E_COM_FAIL;

}

 
BMP5_INTF_RET_TYPE user_i2c_write(uint8_t reg_addr, const uint8_t *data, uint32_t len, void *intf_ptr) {
    const struct device *i2c = (const struct device *)intf_ptr;
    uint8_t buf[1 + len];
    buf[0] = reg_addr;
    memcpy(&buf[1], data, len);
    return i2c_write(i2c, buf, len + 1, BMP581_ADDR) == 0 ? BMP5_OK : BMP5_E_COM_FAIL;
}

void user_delay_us(uint32_t period, void *intf_ptr) {
    k_usleep(period);
}


/* THE MQTT CONNECTION FOUNCTION */
static struct mqtt_client client;

/* File descriptor */
static struct pollfd fds;

static K_SEM_DEFINE(lte_connected, 0, 1);

K_SEM_DEFINE(mqtt_connected, 0, 1);//

LOG_MODULE_REGISTER(DRI, 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;
        }
		printk("[LTE] Network registration status: %s\r\n",
				evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ?
				"Connected - home network" : "Connected - roaming");
		k_sem_give(&lte_connected);
        break;

        case LTE_LC_EVT_RRC_UPDATE:
            printk("[LTE] RRC: %s\r\n", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ?               
                       "CONNECTED" : "IDLE          ");
            break;

        case LTE_LC_EVT_PSM_UPDATE:
            
            printk("[PSM] PSM TAU=%d s, ActiveTime=%d s \r\n",evt->psm_cfg.tau, evt->psm_cfg.active_time);
            printk("...\r\n");
            k_msleep(GAP);
            break;

     default:
             break;
     }
}

static int modem_configure(void)
{
	int err;

	printk("[MODEM] Initializing modem library\r\n");
	err = nrf_modem_lib_init();
	if (err) {
		LOG_ERR("Failed to initialize the modem library, error: %d \r\n", err);
		return err;
	}else {
        printk("[MODEM] Success to initialize the modem library\r\n");
    }

}

static int lte_connect_function(void)
{
    int err;

    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(&lte_connected, K_FOREVER);
    printk("[LTE] Connected to LTE network\r\n");
    printk("...\r\n");
    k_sleep(K_SECONDS(3));

    return 0;
}




static void maintain_mqtt(void)
{
    
    int rc = poll(&fds, 1, 0);
    if (rc < 0) {
        LOG_ERR("poll 에러: %d", errno);
        return;
    }
   
    if (rc > 0) {
        mqtt_input(&client);
    }
    
    rc = mqtt_live(&client);
    if (rc && rc != -EAGAIN) {
        LOG_ERR("mqtt_live 에러: %d", rc);
    }
}


/* GNSS Macro, struct */
static struct nrf_modem_gnss_pvt_data_frame pvt_data;
static int64_t gnss_start_time;

volatile bool STOP = false;
volatile bool gnss_fix_success = false;

static K_SEM_DEFINE(gnss_fixed, 0, 1);
static K_SEM_DEFINE(GNSS_retry,0,1);
static K_SEM_DEFINE(GNSS_SUCCESS,0,1);

/* GNSS Function */
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", (double)pvt_data->altitude);
    
    k_sem_give(&GNSS_SUCCESS);
    
}

static void gnss_event_handler(int event)
{
	int err;

	switch (event) {
	
	case NRF_MODEM_GNSS_EVT_PVT:
		LOG_INF("Searching...");
       int num_satellites = 0;
        for (int i = 0; i < 12 ; i++) {
        if (pvt_data.sv[i].signal != 0) {
        LOG_INF("sv: %d, cn0: %d", pvt_data.sv[i].sv, pvt_data.sv[i].cn0);
        num_satellites++;
        }  
        }
        LOG_INF("Number of satellites: %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) {

			print_fix_data(&pvt_data);

			k_sem_give(&gnss_fixed);
            
		}

		break;

    case NRF_MODEM_GNSS_EVT_SLEEP_AFTER_TIMEOUT:

        k_sem_give(&GNSS_retry);
        printk("[GNSS] GNSS Timeout\r\n");


        break;

    }

   
    

}


static int gnss_fix_once(void)
{

    printk("[GNSS] Start GNSS one-time fix\r\n");

    if (lte_lc_func_mode_set(LTE_LC_FUNC_MODE_ACTIVATE_GNSS) != 0) {
		LOG_ERR("Failed to activate GNSS functional mode");
		return 0;
	} else {
		printk("[GNSS] SUCCESS TO CONFIGURE THE MODEM\r\n");
	}
    
    if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) {
		LOG_ERR("Failed to set GNSS event handler");
		return 0;
	} else {
		printk("[GNSS] SUCCESS TO set gnss event handler THE MODEM\r\n");
	}

    if(nrf_modem_gnss_fix_interval_set((0)!= 0)){
        LOG_ERR("Failed to set GNSS fix interval");
        return 0;
    }

	if (nrf_modem_gnss_fix_retry_set(CONFIG_GNSS_PERIODIC_TIMEOUT) != 0) { // set time out
		LOG_ERR("Failed to set GNSS fix retry");
        return 0;
	}
    
    printk("[GNSS] Starting GNSS\r\n");

	if (nrf_modem_gnss_start() != 0) {
		LOG_ERR("Failed to start GNSS");
	}

    // while(1)
    // {
    // struct k_poll_event events[2] = {
    //         K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    //                                  K_POLL_MODE_NOTIFY_ONLY, &gnss_fixed),
    //         K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    //                                  K_POLL_MODE_NOTIFY_ONLY, &GNSS_retry),
    //     };

    // k_poll(events, ARRAY_SIZE(events), K_FOREVER);

    // if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) {
            
    //         k_sem_take(&gnss_fixed, K_NO_WAIT);
    //         nrf_modem_gnss_stop();
    //         printk("[GNSS] Fix success, stopping GNSS\n");
    //         break;
    //     }

    // if (events[1].state == K_POLL_STATE_SEM_AVAILABLE) {
            
    //         k_sem_take(&GNSS_retry, K_NO_WAIT);
    //         nrf_modem_gnss_stop();
    //         printk("[GNSS] Timeout → restarting GNSS\n");

    //         if (nrf_modem_gnss_start() != 0) {
    //             LOG_ERR("Failed to restart GNSS");
                
    //         }
    //     }

    // }

  

    if(k_sem_take(&GNSS_SUCCESS, K_SECONDS(1))) //K_FOREVER))
    {
        printk("[GNSS] Postion Fix is success\r\n");
      nrf_modem_gnss_stop();
    }
    
    
    printk("...\r\n");
    k_msleep(GAP);

    return 0;

}



 /* Watch dog */
static const struct device *wdt;
static int wdt_channel = -1;

#define WDT_TIMEOUT_SEC  600000// 10 minutes

static void wdt_init_and_start(void)
{
    wdt = DEVICE_DT_GET(DT_NODELABEL(wdt));
    if (!device_is_ready(wdt)) {
        LOG_ERR("Watchdog device is not ready~~");
        return;
    } else {
        printk("[Watch Dog] Watchdog is ready\r\n");
    }

    struct wdt_timeout_cfg cfg = {
        .window = {
            .min = 0,
            .max = WDT_TIMEOUT_SEC, 
        },
        .callback = NULL,
        .flags = WDT_FLAG_RESET_SOC,  
    };
    
    wdt_channel = wdt_install_timeout(wdt, &cfg); // 0 is fail and 1 is success on the setting as a intizer.
    if (wdt_channel < 0) {
        LOG_ERR("[Watch Dog] install_timeout() failed: %d", wdt_channel);
        return;
    } else {
        printk("[Watch Dog] install_timeout() success: %d\r\n", wdt_channel);
    }

	int err = wdt_setup(wdt, 0);
    if (err) {
        LOG_ERR("wdt_setup() failed: %d", err);
        return;
    }
    
        printk("[Watch Dog] started: timeout=%ds, channel=%d\r\n", WDT_TIMEOUT_SEC, wdt_channel);
}

static inline void wdt_try_feed(void){
    if (wdt_channel >= 0) {
        wdt_feed(wdt, wdt_channel);
        printk("[Watch Dog] Feeding Success \r\n");
        printk("... \r\n");
        k_msleep(GAP);
    }
}

     /* PSM Setting */
    void setup_psm(void)
    {
        
        #define PSM_TAU "00100001"      // 10hours        // 000 = 10 mins, 001 = 1 hour, 010 = 10 hours, 011 = 2 seconds, 100 = 30 seconds, 101 = 1 minute, 110 = 320 hours, 111 = deactivated
        #define ACTIVE_TIME "11100000" // Inactive value for active time on psm

        int err = lte_lc_psm_param_set(PSM_TAU, ACTIVE_TIME); 
        if (err) {
            LOG_ERR("Failed to set PSM parameters: %d", err);
            return;
        }
        printk("...\r\n");
        printk("[PSM] PSM SET TAU %s , ACTIVETIME %s \r\n", PSM_TAU,ACTIVE_TIME);

        err = lte_lc_psm_req(true);
        if (err) {
            LOG_ERR("lte_lc_psm_req failed: %d", err);
            return;
        }

        printk("[PSM] Requested successfully\r\n");

        printk("...\r\n");
        k_msleep(GAP);

    }

    /* The Function of SEN66 MEASUREMENT */

    void SEN66_MEASURE_u16(const struct device *dev, uint8_t *buf, size_t buf_len, float *out_array, int start_index, const char *label, float *avg_out)
    {
        
        float sum = 0.0f;
        printk("...\r\n");
        printk(" -- %s_Array Values -- \r\n",label);
        for ( int i = 0; i <5; i++)
        {
           

            int ret = read_measurement(dev, buf, buf_len);
            if (ret != 0) {
                printk("[SEN] Failed to read measurement: %d\r\n", ret);
                return;
            }
            

            uint16_t raw = read_u16(buf[start_index], buf[start_index + 1]);
            float value = raw / 10.0f; // Assuming the value needs to be divided by 10.0f

            out_array[i] = value;
            sum += value;

            printk("[SEN] %s_array[%d]= %.2f ug/m3 \r\n", label , i , out_array[i]);

            
        }

        *avg_out = sum / 5.0f;
        printk("[SEN] sum %.2f \r\n",sum);
        
        printk("\r\n");
        sum = 0.0f;

    }

    void SEN66_MEASURE_s16(const struct device *dev, uint8_t *buf, size_t buf_len, float *out_array, int start_index, const char *label, float *avg_out, float divide, const char *unit )
{
    
        float sum = 0.0f;
        printk("...\r\n");
        printk(" -- %s_Array Values -- \r\n",label);
        for ( int i = 0; i <5; i++)
        {
            

            int ret = read_measurement(dev, buf, buf_len);
            if (ret != 0) {
                printk("[SEN] Failed to read measurement: %d\r\n", ret);
                return;
            }

            int16_t raw = read_s16(buf[start_index], buf[start_index + 1]);
            float value = raw / divide; 
            
            out_array[i] = value;
            sum += value;

            printk("[SEN] %s_array[%d]= %.2f %s \r\n", label , i , value, unit);

            
        }

        *avg_out = sum / 5.0f;
        printk("[SEN] sum %.2f \r\n",sum);
        
        printk("\r\n");

        
        sum = 0.0f;

    }

    void SEN66_MEASURE_CO2(const struct device *dev, uint8_t *buf, size_t buf_len, uint8_t *out_array, int start_index, const char *label, uint16_t *avg_out)
    {
        
        float sum = 0.0f;
        printk("...\r\n");
        printk(" -- %s_Array Values -- \r\n",label);

        for ( int i = 0; i <5; i++)
        {
            

            int ret = read_measurement(dev, buf, buf_len);
            if (ret != 0) {
                printk("[SEN] Failed to read measurement: %d\r\n", ret);
                return;
            }

            uint16_t raw = read_u16(buf[start_index], buf[start_index + 1]);
            out_array[i] = raw;
            sum += raw;

            printk("[SEN] %s_array[%d]= %u ug/m3 \r\n", label , i , raw);

            
        }

        *avg_out = sum / 5.0f;
        uint16_t avg_co2 = (uint16_t)(*avg_out);
        printk("[SEN] sum %.2f \r\n",sum);
        
        printk("\r\n");
        sum = 0.0f;

    }


    void SEN66_MEASURE_RAW_NOX_VOC(const struct device *dev, uint8_t *buf, size_t buf_len, uint16_t *out_array, int start_index, const char *label, uint16_t *avg_out) //int TIME)
    {
        uint32_t sum = 0;
        printk("...\r\n");
        printk(" -- %s_Array Values -- \r\n",label);
        for ( int i = 0; i <5; i++)
        {
           

            int ret = read_raw_measurement(dev, buf, buf_len);
            if (ret != 0) {
                printk("[SEN] Failed to read measurement: %d\r\n", ret);
                return;
            }
            

            uint16_t raw = read_u16(buf[start_index], buf[start_index + 1]);

            out_array[i] = raw;
            sum += raw;

            printk("[SEN] %s_array[%d]= %u ticks \r\n", label , i , out_array[i]);

           
        }

        *avg_out = sum / 5;
        printk("[SEN] sum %u \r\n",sum);
        
        printk("\r\n");
        sum = 0;

    }

    void MQTT_Reconnect(void)
    {
        int err = client_init(&client);
	if (err) {
		LOG_ERR("Failed to initialize MQTT client: %d", err);

	}

    uint32_t connect_attempt = 0;

    do_connect:
	if (connect_attempt++ > 0) {
	    LOG_INF("Reconnecting in %d ms...", RECONNECTING_TIME);
		k_msleep(RECONNECTING_TIME);
	}

	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);
    }

     err = poll(&fds, 1, mqtt_keepalive_time_left(&client));
        if (err < 0) {
            LOG_ERR("poll error: %d", errno);
            mqtt_disconnect(&client, NULL);
            mqtt_abort(&client);
            client_init(&client);
            
            goto do_connect;
        }

        
        err = mqtt_input(&client);
        if (err != 0 && err != -EAGAIN) {
            LOG_ERR("mqtt_input error: %d", err);
            mqtt_disconnect(&client, NULL);
            mqtt_abort(&client);
            client_init(&client);

            goto do_connect;
        }

        
        if (k_sem_take(&mqtt_connected, K_NO_WAIT) == 0) {
            printk("[MQTT] MQTT takes semaphore.\r\n");
        }

        printk("... \r\n");
    }


    /* RTC */

    #define RTC_FREQ 32768
    #define MAX_SECS 300

    const struct device *rtc;
    struct tm now_tm;
    
    time_t now_sec;

    volatile static uint64_t remaining_secs = 0;
    volatile uint64_t target_ms = 0;
    volatile uint64_t now_ms = 0;
    uint64_t delay_ms = 0;

    volatile bool Alarm_expired = false;

    
void time_convert(void)
{
    
    date_time_now(&now_ms);

    time_t now_sec = (now_ms / 1000)-25200;
        
        gmtime_r(&now_sec, &now_tm);
    
    printk("[Time]PDT Time: %04d-%02d-%02d %02d:%02d:%02d \r\n",now_tm.tm_year + 1900,now_tm.tm_mon + 1,now_tm.tm_mday,now_tm.tm_hour,now_tm.tm_min,now_tm.tm_sec);
        
}

    /* RTC Function */


static inline uint64_t next_time_set(uint64_t now_ms, const int int_minutes) // 다음 정각을 구함
{
    
    const uint64_t interval_ms = int_minutes * 60 * 1000ULL ; 
    



    uint64_t n = now_ms / interval_ms;

    time_convert();

    return (n + 1ULL) * interval_ms;
}




K_SEM_DEFINE(alarm_sem,0,1);

K_SEM_DEFINE(timing,0,1);

static void every_20mins(const struct device *dev,
                           uint8_t chan_id,
                           uint32_t ticks,
                           void *user_data)
{
    
    printk("[Alarm] Ringed!! remaining_secs=%lld \r\n", remaining_secs);
    
    if (remaining_secs > 0)
    {

        uint32_t next_secs = MIN(remaining_secs, MAX_SECS);
        remaining_secs -= next_secs;

        uint32_t next_ticks = 0;
        next_ticks = next_secs * RTC_FREQ;
        if (next_ticks == 0) next_ticks = 1; // 최소 1
        
    struct counter_alarm_cfg cfg2 = {
            .flags = 0,
            .ticks = next_ticks,
            .callback = every_20mins,
            .user_data = NULL
        };
        
        
        int err2 = counter_set_channel_alarm(dev, 0, &cfg2);
        if (err2) {
                LOG_ERR("Failed2 to set RTC alarm: %d", err2);
            } else {
                printk("[Alarm] Next RTC alarm set after %llu sec \r\n", remaining_secs);
            }

    } else if(remaining_secs == 0){
        
        k_sem_give(&alarm_sem);

        Alarm_expired = true;

        if(Alarm_expired)
        {
            printk("[Alarm] Alarm_expired flag is true \r\n"); 
        }else{
            printk("[Alarm] Alarm_expired flag is false \r\n");
        }
        
        printk("... \r\n");
        printk("... \r\n");

    }



}



static void set_rtc_alarm(uint64_t now_ms, const int int_minutes) {

    if (date_time_now(&now_ms) != 0) {
        printk("[RTC] Failed to get current time\n");
        return;
    }

    
    target_ms =  next_time_set(now_ms, int_minutes); // minutes → ms
    delay_ms = target_ms - now_ms;
    remaining_secs = (delay_ms + 999ULL) / 1000ULL;

    uint32_t first_secs = MIN(remaining_secs, MAX_SECS);
     if (first_secs == 0) first_secs = 1;
     remaining_secs -= first_secs;

    

    uint32_t ticks = first_secs * RTC_FREQ;

    struct counter_alarm_cfg cfg = {
        .flags = 0,
        .ticks = ticks,
        .callback = every_20mins,   // 기존 콜백 그대로 사용
        .user_data = NULL
    };

    int err = counter_set_channel_alarm(rtc, 0, &cfg);
    if (err) {
        LOG_ERR("Failed to set RTC alarm: %d", err);
    } else {
        printk("[RTC] Alarm set for next %llu seconds \n", (unsigned long long)remaining_secs );
    }

    

}



static void reset_rtc_alarm(uint64_t now_ms, volatile int int_minutes) {

   
    date_time_now(&now_ms);

    target_ms = now_ms + (int_minutes * 60 * 1000ULL) ;
    
    uint64_t delay_ms = target_ms - now_ms;

    remaining_secs = (delay_ms + 999ULL) / 1000ULL; //delay_ms / 1000ULL;

    uint64_t first_secs = MIN(remaining_secs, MAX_SECS);
    if (first_secs == 0) first_secs = 1;
    remaining_secs -= first_secs;

    
    uint32_t ticks = 0;
     ticks = first_secs * RTC_FREQ;


    struct counter_alarm_cfg cfg = {
        .flags = 0,
        .ticks = ticks,
        .callback = every_20mins,   // 기존 콜백 그대로 사용
        .user_data = NULL
    };

    
    int err = counter_set_channel_alarm(rtc, 0, &cfg);
    if (err) {
        LOG_ERR("Failed to set RTC alarm: %d", err);
    } else {
        printk("[RTC] Alarm set for next %llu mins \n", (delay_ms + 999ULL)  / 1000ULL );
    }


}





static void dt_evt_handler(const struct date_time_evt *evt)
{
    
    if (evt->type == DATE_TIME_OBTAINED_MODEM ||
        evt->type == DATE_TIME_OBTAINED_NTP ||
        evt->type == DATE_TIME_OBTAINED_EXT ||
        evt->type == DATE_TIME_NOT_OBTAINED) {

    printk("[dt_evt_handler] Date and time event received: %d\r\n", evt->type);


            time_convert();

            /* Measure next time */
            target_ms = next_time_set(now_ms, 20); // Next time set to whatever                        
            delay_ms = target_ms - now_ms;
            remaining_secs = (delay_ms + 999ULL) / 1000ULL;

            uint64_t first_secs = MIN(remaining_secs, MAX_SECS);
            remaining_secs -= first_secs;

            uint32_t ticks = 0;
            ticks = first_secs * RTC_FREQ;

            if (ticks == 0) ticks = 1; // 최소 1
      
            struct counter_alarm_cfg cfg = {
                .flags = 0,
                .ticks = ticks,
                .callback = every_20mins,
                .user_data = NULL
            };

            int err = counter_start(rtc);
            if(err)
            {
                printk("[dt_evt_handler] counter has started %d\r\n", err);
            }

        err = counter_set_channel_alarm(rtc, 0, &cfg); 
        if(err)
            {
                printk("counter fail \r\n");
            }else{
                printk("[RTC] Counter set next %llu Secs\r\n", (delay_ms + 999ULL) / 1000ULL);
            }
        
            printk("... \r\n");
            
        }
}



static void date_time_evt_handler(const struct date_time_evt *evt)
{
    switch (evt->type) {
    case DATE_TIME_OBTAINED_MODEM:
        printk("[TIME] Updated from MODEM\n");
        break;
    case DATE_TIME_OBTAINED_NTP:
        printk("[TIME] Updated from NTP\n");
        break;
    case DATE_TIME_NOT_OBTAINED:
        printk("[TIME] Update failed\n");
        break;
    default:
        break;
    }
}




void RTC_Start(void)
    {
        
        rtc = DEVICE_DT_GET(DT_NODELABEL(rtc0));
        if (!device_is_ready(rtc)) {
            LOG_ERR("RTC device is not ready");
            return;
        }
        
        int err = date_time_update_async(dt_evt_handler);
        if (err) {
            LOG_ERR("Failed to update date and time asynchronously: %d", err);
            return;
        } 
        printk("... \r\n");

    }



    /* Voltage */
    static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user));
    int16_t buf;
    int32_t val_mv;
    int err;
    float voltage = 0.0;

void Voltage_init(void)
{
    

    if (!adc_is_ready_dt(&adc_channel)) {
        LOG_ERR("ADC controller devivce %s not ready", adc_channel.dev->name);
        return 0;
    }

    err = adc_channel_setup_dt(&adc_channel);

        if (err < 0) {
            LOG_ERR("Could not setup channel #%d (%d)", 0, err);
            return 0;
        }

     	
	struct adc_sequence sequence = {
		.buffer = &buf,
		.buffer_size = sizeof(buf),
		
	};

    

    err = adc_sequence_init_dt(&adc_channel, &sequence);
	if (err < 0) {
		LOG_ERR("Could not initalize sequnce");
		return 0;
	}

    err = adc_read(adc_channel.dev, &sequence);
    if (err < 0) {
        LOG_ERR("Could not read (%d)", err);
    }

    val_mv = buf;

    err = adc_raw_to_millivolts_dt(&adc_channel, &val_mv);
    voltage = (float)val_mv / 1000.0;
    if (err < 0) {
                LOG_WRN(" (value in mV not available)\n");
        } 
}


/* FLASH MEMORY SPI */
    const struct device *flash_dev = DEVICE_DT_GET(DT_NODELABEL(gd25wb256));

    #define LOG_OFFSET  0x000000                   // Start address for log storage
    #define SECTOR_SIZE 4096
    #define FLASH_SIZE   (32 * 1024 * 1024)        //256Mbit = 32Mbyte      

    char payload[512] = {0};
    static uint32_t write_offset = LOG_OFFSET;
    
void flash_log_init(void)
{
    if (!device_is_ready(flash_dev)) {
        printk("Flash device not ready!\n");
        return;
    } else {
        printk("[Flash] GD25 device is ready\r\n");
    }

    /* when flash memory has started for the first time */
    printk("Erasing flash log area...\n");
    for (uint32_t addr = LOG_OFFSET; addr < FLASH_SIZE; addr += SECTOR_SIZE) {
        flash_erase(flash_dev, addr, SECTOR_SIZE);
    }

    write_offset = LOG_OFFSET;
    printk("[Flash] log initialized \r\n");
}


void save_log_to_flash(const char *buf , size_t len)
    {

        int err;

        if (!device_is_ready(flash_dev)) {
        LOG_ERR("Flash device not ready");
        return;
        } else {
        printk("[Flash] GD25 device is ready\r\n");
        }


        if (write_offset + len >= FLASH_SIZE) {
        printk("Flash full -> wrap-around to 0\n");
        write_offset = LOG_OFFSET;
        }

        /* Sector erase when write_offset is at the beginning of a sector */ 
        if ((write_offset % SECTOR_SIZE) == 0) {
            flash_erase(flash_dev, write_offset, SECTOR_SIZE);
        }

        time_convert();

        err = flash_write(flash_dev, write_offset , buf , len);
        if (err){
            printk("[FLASH] Flash write success addr: 0x%08x data: %s \r\n", write_offset, buf);
        }else if(err < 0){
            LOG_ERR("[FLASH] Flash write failed %d \r\n", err);
        }
    

        write_offset += len;

        printk("[FLASH] Data saved to flash,Once Measure is done\r\n%s\r\n", buf);
        printk("... \r\n");
        k_msleep(GAP);
    }



    int Publish_sensor_data_Gnss_pressure(const char *device_id_str, float latitude, float longitude, float altitude, struct tm now_tm
                        )
{
    char payload[512] = {0};
    int len = snprintf(payload, sizeof(payload),
        "{"
            "\"ID\":\"%s\","
            "\"latitude\":%.6f,"
            "\"longitude\":%.6f,"
            "\"altitude\":%.2f,"
            "\"Timestamp\":\"%04d-%02d-%02d %02d:%02d:%02d\""
            "}",
            device_id_str, latitude, longitude, altitude,now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour,  now_tm.tm_min, now_tm.tm_sec);



    char buf[512] = {0};
    int len_1 = snprintf(buf, sizeof(buf),
                       "%04d-%02d-%02d %02d:%02d:%02d %.6f,%.6f,%.2f \r\n",
                       now_tm.tm_year + 1900, now_tm.tm_mon + 1,now_tm.tm_mday,now_tm.tm_hour,now_tm.tm_min,now_tm.tm_sec, latitude, longitude, altitude);

        save_log_to_flash(buf, len_1);

 

    return data_publish_satelite(&client,
                        MQTT_QOS_1_AT_LEAST_ONCE,
                        (const uint8_t *)payload,
                        len);


                        
    
}


int publish_sensor_data(const char *device_id_str, float pm1, float pm25, float pm4, float pm10,
                        float rh, float temp, float co2, float voltage,float hPa, uint32_t result_raw_NOx, uint32_t result_Raw_VOC, struct tm now_tm)
{

    int64_t now_ms;
    time_t now_sec;

    
    date_time_now(&now_ms);
    now_sec = (now_ms / 1000) - 25200;  // PDT 기준
    gmtime_r(&now_sec, &now_tm);
    
    char payload[512] = {0};
    int len = snprintf(payload, sizeof(payload),
        "{"
            "\"ID\":\"%s_A\","
            "\"pm1\":%.2f,"
            "\"pm25\":%.2f,"
            "\"pm4\":%.2f,"
            "\"pm10\":%.2f,"
            "\"rh\":%.2f,"
            "\"temp\":%.2f,"
            "\"co2\":%.2f,"
            "\"voltage\":%.2f,"
            "\"Pressure\":%.2f,"
            "\"Raw_nox\":%u,"
            "\"Raw_voc\":%u,"
            "\"Timestamp\":\"%04d-%02d-%02d %02d:%02d:%02d\""
            "}",
            device_id_str, pm1, pm25, pm4, pm10,
            rh, temp, co2,voltage , hPa,result_raw_NOx ,result_Raw_VOC, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour,  now_tm.tm_min, now_tm.tm_sec);


    char topic[64] = {0};

    uint8_t id[8];    
    hwinfo_get_device_id(id, sizeof(id));

    snprintf(topic,sizeof(topic) ,"sensor/%02x%02x%02x%02x%02x%02x%02x%02x",
       id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
   
   

    return data_publish(&client,
                        MQTT_QOS_1_AT_LEAST_ONCE,
                        (const uint8_t *)payload,
                        len, topic);

}



int publish_sensor_data_B(const char *device_id_str, float pm1, float pm25, float pm4, float pm10,
                        float rh, float temp, float co2, float voltage,float hPa, uint32_t result_raw_NOx, uint32_t result_Raw_VOC, struct tm now_tm)
{
    int64_t now_ms;
  
    time_t now_sec;

    
    date_time_now(&now_ms);
    now_sec = (now_ms / 1000) - 25200;  // PDT 기준
    gmtime_r(&now_sec, &now_tm);

    char payload[512] = {0};
    int len = snprintf(payload, sizeof(payload),
        "{"
            "\"ID\":\"%s_B\","
            "\"pm1\":%.2f,"
            "\"pm25\":%.2f,"
            "\"pm4\":%.2f,"
            "\"pm10\":%.2f,"
            "\"rh\":%.2f,"
            "\"temp\":%.2f,"
            "\"co2\":%.2f,"
            "\"voltage\":%.2f,"
            "\"Pressure\":%.2f,"
            "\"Raw_nox\":%u,"
            "\"Raw_voc\":%u,"
            "\"Timestamp\":\"%04d-%02d-%02d %02d:%02d:%02d\""
            "}",
            device_id_str, pm1, pm25, pm4, pm10,
            rh, temp, co2,voltage , hPa,result_raw_NOx ,result_Raw_VOC, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour,  now_tm.tm_min, now_tm.tm_sec);


    char topic[64] = {0};

    uint8_t id[8];    
    hwinfo_get_device_id(id, sizeof(id));

    snprintf(topic,sizeof(topic) ,"sensor/%02x%02x%02x%02x%02x%02x%02x%02x_B",
       id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
   
   

    return data_publish(&client,
                        MQTT_QOS_1_AT_LEAST_ONCE,
                        (const uint8_t *)payload,
                        len, topic);

}

/* sum_avg_value */

volatile static float result_pm1, result_pm25, result_pm4, result_pm10, result_rh, result_Temp,  result_voltage, result_hPa;
volatile static uint32_t result_raw_NOx=0, result_Raw_VOC=0;
volatile static uint16_t result_co2;

volatile static float result_pm1_B, result_pm25_B, result_pm4_B, result_pm10_B, result_rh_B, result_Temp_B,  result_voltage_B, result_hPa_B;
volatile static int32_t result_raw_NOx_B=0, result_Raw_VOC_B=0;
volatile static uint16_t result_co2_B;


float prev_result_pm1 = 0.0f, prev_result_pm25 = 0.0f, prev_result_pm4 = 0.0f, prev_result_pm10 = 0.0f;
float prev_result_rh = 0.0f, prev_result_Temp = 0.0f;
float prev_result_voltage = 0.0f, prev_result_hPa = 0.0f,prev_result_co2=0.0f;
uint32_t prev_result_raw_NOx = 0, prev_result_Raw_VOC = 0;

float prev_result_pm1_B = 0.0f, prev_result_pm25_B = 0.0f, prev_result_pm4_B = 0.0f, prev_result_pm10_B = 0.0f;
float prev_result_rh_B = 0.0f, prev_result_Temp_B = 0.0f;
float prev_result_voltage_B = 0.0f, prev_result_hPa_B = 0.0f,prev_result_co2_B=0.0f;
uint32_t prev_result_raw_NOx_B = 0, prev_result_Raw_VOC_B = 0;

volatile float current_pm1,current_pm25,current_pm4, current_pm10,current_rh,current_Temp,  current_voc,current_nox,current_voltage,current_hPa;
volatile uint32_t current_raw_NOx , current_Raw_VOC ;
volatile uint16_t current_co2 = 0;

volatile float current_pm1_B,current_pm25_B,current_pm4_B, current_pm10_B,current_rh_B,current_Temp_B,  current_voc_B,current_nox_B,current_voltage_B,current_hPa_B;
volatile uint32_t current_raw_NOx_B , current_Raw_VOC_B ;
volatile uint16_t current_co2_B = 0;

volatile uint16_t sample_count = 0;
volatile uint16_t sample_count_B = 0;


static float sum_pm1 = 0, sum_pm25 = 0, sum_pm4 = 0, sum_pm10 = 0;
static float sum_rh = 0, sum_temp = 0;
static uint32_t sum_co2 = 0;
static float sum_voltage = 0, sum_hPa = 0;
static uint32_t sum_Raw_NOx = 0, sum_Raw_VOC = 0;

static float sum_pm1_B = 0, sum_pm25_B = 0, sum_pm4_B = 0, sum_pm10_B = 0;
static float sum_rh_B = 0, sum_temp_B = 0;
static uint32_t sum_co2_B = 0;
static float sum_voltage_B = 0, sum_hPa_B = 0;
static uint32_t sum_Raw_NOx_B = 0, sum_Raw_VOC_B = 0;


uint64_t previous_time_set = 0;
volatile uint64_t divide = 0;
volatile uint64_t prev_sample_count = 0;
volatile uint64_t prev_sample_count_B = 0;
uint64_t divide_count=0;

void sum_avg_value(float pm1, float pm25, float pm4, float pm10,
                        float Humidity, float Temp, float VOC_Index, float NOx_Index, uint16_t co2, float voltage, float hPa,uint16_t Raw_NOx, uint16_t Raw_VOC)
{
    
    uint64_t current_time_set = target_ms;
    
    
    sum_pm1     += pm1;
    sum_pm25    += pm25;
    sum_pm4     += pm4;
    sum_pm10    += pm10;
    sum_rh      += Humidity;
    sum_temp    += Temp;
    sum_co2     += co2;
    sum_voltage += voltage;
    sum_hPa     += hPa;
    sum_Raw_NOx += Raw_NOx;
    sum_Raw_VOC += Raw_VOC;

    sample_count++;

    current_pm1 = sum_pm1 / sample_count;
    current_pm25 = sum_pm25 / sample_count;
    current_pm4 = sum_pm4 / sample_count;
    current_pm10 = sum_pm10 / sample_count;
    current_rh = sum_rh / sample_count;
    current_Temp = sum_temp / sample_count;
    current_co2 = sum_co2 / sample_count;
    current_voltage = sum_voltage / sample_count;
    current_hPa = sum_hPa / sample_count;
    current_raw_NOx = sum_Raw_NOx / sample_count;
    current_Raw_VOC = sum_Raw_VOC / sample_count;
    
        printk("[MongoDB] Store divided value to send datas to MongoDB\r\nPM1: %.2f, PM2.5: %.2f, PM4: %.2f, PM10: %.2f, RH: %.2f, Temp: %.2f, CO2: %d, Voltage: %.2f, Pressure: %.2f, Raw NOx %u , Raw VOC %u\r\n",
               current_pm1, current_pm25, current_pm4, current_pm10,
               current_rh, current_Temp, 
               current_co2, current_voltage, current_hPa , current_raw_NOx, current_Raw_VOC);
    

}

void sum_avg_value_B(float pm1, float pm25, float pm4, float pm10,
                        float Humidity, float Temp, float VOC_Index, float NOx_Index, uint16_t co2, float voltage, float hPa,uint16_t Raw_NOx, uint16_t Raw_VOC)
{
    
    uint64_t current_time_set = target_ms;
    
    
    sum_pm1_B     += pm1;
    sum_pm25_B    += pm25;
    sum_pm4_B     += pm4;
    sum_pm10_B    += pm10;
    sum_rh_B      += Humidity;
    sum_temp_B    += Temp;
    sum_co2_B     += co2;
    sum_voltage_B += voltage;
    sum_hPa_B     += hPa;
    sum_Raw_NOx_B += Raw_NOx;
    sum_Raw_VOC_B += Raw_VOC;

    sample_count_B++;

    current_pm1_B = sum_pm1_B / sample_count_B;
    current_pm25_B = sum_pm25_B / sample_count_B;
    current_pm4_B = sum_pm4_B / sample_count_B;
    current_pm10_B = sum_pm10_B / sample_count_B;
    current_rh_B = sum_rh_B / sample_count_B;
    current_Temp_B = sum_temp_B / sample_count_B;
    current_co2_B = sum_co2_B / sample_count_B;
    current_voltage_B = sum_voltage_B / sample_count_B;
    current_hPa_B = sum_hPa_B / sample_count_B;
    current_raw_NOx_B = sum_Raw_NOx_B / sample_count_B;
    current_Raw_VOC_B = sum_Raw_VOC_B / sample_count_B;
    
        printk("[MongoDB] Store divided value to send datas to MongoDB\r\nPM1: %.2f, PM2.5: %.2f, PM4: %.2f, PM10: %.2f, RH: %.2f, Temp: %.2f, CO2: %d, Voltage: %.2f, Pressure: %.2f, Raw NOx %u , Raw VOC %u\r\n",
               current_pm1_B, current_pm25_B, current_pm4_B, current_pm10_B,
               current_rh_B, current_Temp_B, 
               current_co2_B, current_voltage_B, current_hPa_B , current_raw_NOx_B, current_Raw_VOC_B);
    

}

void update_prev_value_A(void)
{
    prev_result_pm1 = current_pm1;
    prev_result_pm25 = current_pm25;
    prev_result_pm4 = current_pm4;
    prev_result_pm10 = current_pm10;
    prev_result_rh = current_rh;
    prev_result_Temp = current_Temp;
    prev_result_co2 = current_co2;
    prev_result_voltage = current_voltage;
    prev_result_hPa = current_hPa;
    prev_result_raw_NOx = current_raw_NOx;
    prev_result_Raw_VOC = current_Raw_VOC;
  
}

void update_prev_value_B(void)
{
    prev_result_pm1_B = current_pm1_B;
    prev_result_pm25_B = current_pm25_B;
    prev_result_pm4_B = current_pm4_B;
    prev_result_pm10_B = current_pm10_B;
    prev_result_rh_B = current_rh_B;
    prev_result_Temp_B = current_Temp_B;
    prev_result_co2_B = current_co2_B;
    prev_result_voltage_B = current_voltage_B;
    prev_result_hPa_B = current_hPa_B;
    prev_result_raw_NOx_B = current_raw_NOx_B;
    prev_result_Raw_VOC_B = current_Raw_VOC_B;
  
}

void sum_prev_current_value_A(void)
{
    result_pm1 = (prev_result_pm1 + current_pm1) / 2.0f;
    result_pm25 = (prev_result_pm25 + current_pm25) / 2.0f;
    result_pm4 = (prev_result_pm4 + current_pm4) / 2.0f;
    result_pm10 = (prev_result_pm10 + current_pm10) / 2.0f;
    result_rh = (prev_result_rh + current_rh) / 2.0f;
    result_Temp = (prev_result_Temp + current_Temp) / 2.0f;
    result_co2 = (prev_result_co2 + current_co2) / 2.0f;
    result_voltage = (prev_result_voltage + current_voltage) / 2.0f;
    result_hPa = (prev_result_hPa + current_hPa) / 2.0f;
    result_raw_NOx = (prev_result_raw_NOx + current_raw_NOx) / 2;
    result_Raw_VOC = (prev_result_Raw_VOC + current_Raw_VOC) / 2;
}

void sum_prev_current_value_B(void)
{
    result_pm1_B = (prev_result_pm1_B + current_pm1_B) / 2.0f;
    result_pm25_B = (prev_result_pm25_B + current_pm25_B) / 2.0f;
    result_pm4_B = (prev_result_pm4_B + current_pm4_B) / 2.0f;
    result_pm10_B = (prev_result_pm10_B + current_pm10_B) / 2.0f;
    result_rh_B = (prev_result_rh_B + current_rh_B) / 2.0f;
    result_Temp_B = (prev_result_Temp_B + current_Temp_B) / 2.0f;
    result_co2_B = (prev_result_co2_B + current_co2_B) / 2.0f;
    result_voltage_B = (prev_result_voltage_B + current_voltage_B) / 2.0f;
    result_hPa_B = (prev_result_hPa_B + current_hPa_B) / 2.0f;
    result_raw_NOx_B = (prev_result_raw_NOx_B + current_raw_NOx_B) / 2;
    result_Raw_VOC_B = (prev_result_Raw_VOC_B + current_Raw_VOC_B) / 2;
}




void First_loop_value_A(void)
{
    result_pm1 = current_pm1;
    result_pm25 = current_pm25;
    result_pm4 = current_pm4;
    result_pm10 = current_pm10;
    result_rh = current_rh;
    result_Temp = current_Temp;
    result_co2 = current_co2;
    result_voltage = current_voltage;
    result_hPa = current_hPa;
    result_raw_NOx = current_raw_NOx;
    result_Raw_VOC = current_Raw_VOC;
}

void First_loop_value_B(void)
{
    result_pm1_B = current_pm1_B;
    result_pm25_B = current_pm25_B;
    result_pm4_B = current_pm4_B;
    result_pm10_B = current_pm10_B;
    result_rh_B = current_rh_B;
    result_Temp_B = current_Temp_B;
    result_co2_B = current_co2_B;
    result_voltage_B = current_voltage_B;
    result_hPa_B = current_hPa_B;
    result_raw_NOx_B = current_raw_NOx_B;
    result_Raw_VOC_B = current_Raw_VOC_B;
}


void sum_value_reset(void)
{
    if(Alarm_expired)
        {   
            
                
                sum_pm1 = 0;
                sum_pm25 = 0;
                sum_pm4 = 0;
                sum_pm10 = 0;
                sum_rh = 0;
                sum_temp = 0;
                sum_co2 = 0;
                sum_voltage = 0;
                sum_hPa = 0;
                sum_Raw_NOx = 0;
                sum_Raw_VOC = 0;

                sum_pm1_B = 0;
                sum_pm25_B = 0;
                sum_pm4_B = 0;
                sum_pm10_B = 0;
                sum_rh_B = 0;
                sum_temp_B = 0;
                sum_co2_B = 0;
                sum_voltage_B = 0;
                sum_hPa_B = 0;
                sum_Raw_NOx_B = 0;
                sum_Raw_VOC_B = 0;

                prev_sample_count = sample_count;
                sample_count = 0;

                prev_sample_count_B = sample_count_B;
                sample_count_B = 0;
                

                printk("sample_count %u,  prev_sample_count %llu\r\n", sample_count,prev_sample_count );
            

    }
}


volatile float avg_pm25 = 0.0;
volatile float avg_pm25_B = 0.0;
volatile float previous_pm25 = 0.0f;
volatile float current1_pm25 = 0.0f; 
volatile int next_interval = 20;
bool static next_interval_locked = false;

#define EVERY_20_MINS 20
#define EVERY_5_MINS 5
#define EVERY_10_MINS 10

/* -------------------- MAIN CODE START POINT --------------------- */
void main(void)
{
    k_msleep(10000); // Wait for 10 seconds before starting

    /* DUMP Station */
	int err;
	int ret;
    int i;

	float pm1_array[5];
    float pm25_array[5];
    float pm4_array[5];
    float pm10_array[5];
    float Humidity_array[5];
    float Temp_array[5];
    float VOC__array_Index[5];
    float NOx__array_Index[5];
    float NOx_raw_array[5];
    float VOc_raw_array[5];
    float sum = 0.0; 
    float Pa_array[5];
    float hPa = 0.0;

    uint8_t co2_array[5];
    uint16_t data_buf[30];
    uint8_t buf[14] = {0};
  

    uint16_t avg_co2 = 0.0;
	uint32_t connect_attempt = 0;

    uint16_t VOc_raw_data = 0;
    uint16_t NOx_raw_data = 0;


    float avg_pm1 = 0.0;
    float avg_pm4 = 0.0;
    float avg_pm10 = 0.0;
    float avg_Humidity = 0.0;
    float avg_Temp = 0.0;
    float avg_VOC_Index = 0.0;
    float avg_NOx_Index = 0.0;
    float avg_NOx_raw = 0.0;
    float avg_VOc_raw = 0.0;


    uint16_t VOc_raw_data_B= 0;
    uint16_t NOx_raw_data_B = 0;


    float avg_pm1_B = 0.0;
    float avg_pm4_B = 0.0;
    float avg_pm10_B = 0.0;
    float avg_Humidity_B = 0.0;
    float avg_Temp_B = 0.0;
    float avg_VOC_Index_B = 0.0;
    float avg_NOx_Index_B = 0.0;
    float avg_NOx_raw_B = 0.0;
    float avg_VOc_raw_B = 0.0;
    uint16_t avg_co2_B = 0;

    float pm1_array_B[5];
    float pm25_array_B[5];
    float pm4_array_B[5];
    float pm10_array_B[5];
    float Humidity_array_B[5];
    float Temp_array_B[5];
    float VOC__array_Index_B[5];
    float NOx__array_Index_B[5];
    float NOx_raw_array_B[5];
    float VOc_raw_array_B[5];
    float sum_B = 0.0; 
    float Pa_array_B[5];
    float hPa_B = 0.0;
    uint16_t co2_array_B[5];
    int count = 0;
    int pm25_flag = 0;
    int measure_interval_ms =0;

    uint16_t data_buf_B[30];
    uint8_t buf_B[14] = {0};
   
    static int over_count = 0;
    static int between_count = 0;
    static int under_count = 0;
    
    
    /* Device Id */
    device_id();

	printk("[SEN] Get information from SEN66 \r\n");

	k_sleep(K_MSEC(DEVICE_ID_WATTING_TIME));

	const struct i2c_dt_spec sen66 = I2C_DT_SPEC_GET(SEN66_NODE);

    const struct i2c_dt_spec sen66_1 = I2C_DT_SPEC_GET(SEN66_1_NODE);

	if (!device_is_ready(sen66.bus)) {
	LOG_ERR("[SEN] I2C bus %s \r\n",sen66.bus->name);
	
    } else {
        printk("[SEN] SEN66 Addr: %s  \r\n", sen66.bus->name);
    }



    /* SEN66 Measurement Start */

	uint8_t cmd_start[] = {0x00, 0x21}; 

    k_msleep(STARTING_TIME);

    ret = i2c_write_dt(&sen66, cmd_start, sizeof(cmd_start));
    if (ret == 0) {
        printk("[SEN] SEN66 Measurement is starting \r\n");
    } else {
        printk("[SEN] SEN66 MEASUREMENT IS FAILED : %d \r\n", ret);
        
    }
    k_msleep(50);

    ret = i2c_write_dt(&sen66_1, cmd_start, sizeof(cmd_start));
    if (ret == 0) {
        printk("[SEN] SEN66_1 Measurement is starting \r\n");
    } else {
        printk("[SEN] SEN66_1 MEASUREMENT IS FAILED : %d \r\n", ret);
        
    }

    printk("... \r\n");
    


    /* BMP581 */

    int8_t rslt;
    int8_t chip_id;
    uint8_t i2c_addr = 0x46;
    uint8_t dummy = 0;

    i2c_dev = DEVICE_DT_GET(BMP581_NODE);
    if (!device_is_ready(i2c_dev)) {
        printk(" [BMP] BMP581 won't be started \r\n");
        return;
    }    printk("[BMP] BMP581 will be started \r\n");
 
    bmp_dev.intf = BMP5_I2C_INTF;
    bmp_dev.intf_ptr = (void *)i2c_dev;
    bmp_dev.read = user_i2c_read;
    bmp_dev.write = user_i2c_write;
    bmp_dev.delay_us = user_delay_us;

    k_msleep(2);

    if(i2c_dev == NULL) {
        printk("[BMP] i2c_dev is NULL\r\n");
    }


    /* To make the sensor stable */

    bmp5_get_regs(BMP5_REG_CHIP_ID, &dummy, 1, &bmp_dev);

     bmp5_get_regs(0x01, &chip_id,  1, &bmp_dev);
       printk("[BMP] BMP581 CHIP_ID: 0x%02X\n", chip_id);

    rslt = bmp5_init(&bmp_dev);
     if (rslt != BMP5_OK) {
         printk("[BMP] BMP5 init failed: %d\n", rslt);
     } 
   

    osr_cfg.press_en = BMP5_ENABLE;
    osr_cfg.osr_p = BMP5_OVERSAMPLING_4X; 
    osr_cfg.osr_t = BMP5_OVERSAMPLING_8X; // Temperature
    osr_cfg.odr = BMP5_ODR_50_HZ; // Output Data Rate


    rslt = bmp5_set_osr_odr_press_config(&osr_cfg, &bmp_dev);
    if (rslt != BMP5_OK) {
        printk(" Failed to get OSR/ODR config: %d\n", rslt);
        return;
    }

    struct bmp5_iir_config iir_cfg = {

    .set_iir_t = BMP5_IIR_FILTER_COEFF_3, // Temperature IIR
    .set_iir_p = BMP5_IIR_FILTER_COEFF_3, // Pressure IIR
    .shdw_set_iir_t = BMP5_ENABLE,
    .shdw_set_iir_p = BMP5_ENABLE,
    .iir_flush_forced_en = BMP5_ENABLE

    };

    rslt = bmp5_set_iir_config(&iir_cfg, &bmp_dev);
    if (rslt != BMP5_OK) {
        printk(" Failed to set IIR config: %d\n", rslt);
        return;
    }else {
        printk("[BMP] IIR config is set \r\n");
    }
    

    rslt = bmp5_set_power_mode(BMP5_POWERMODE_NORMAL, &bmp_dev);
    if (rslt != BMP5_OK) {
        printk(" Failed to set power mode: %d\n", rslt);
        return;
    }else {
        printk("[BMP] Power mode is Nomal \r\n");
    }

    printk("... \r\n");
    k_msleep(GAP);

    k_msleep(50);


    /* Watch dog start */
    wdt_init_and_start();
    
    printk("... \r\n");
    k_msleep(GAP);
   

	/* Modem confiure and MQTT */
	err = modem_configure();
	if (err) {
		LOG_ERR("[MODEM] Failed to configure the modem \r\n");
	}else {
        printk("[MODEM] Success to configure the modem \r\n");
    }

    printk("... \r\n");
    k_msleep(GAP);


    /* Gnss and LTE connection */
    err = gnss_fix_once();
    if(err=0)
    {
        printk("[GNSS] GNSS fix is success %d",err);
    }



    /* Setup PSM */
    setup_psm();


    /* LTE Connection */
    lte_connect_function();

    /* RTC Start*/
    RTC_Start();

    /* MQTT Connect */
    MQTT_Reconnect();

    


        printk("...\r\n");
        err = lte_lc_psm_req(false);
        if (err) {
            printk("Failed to wake modem: %d\r\n", err);
        }
        printk("[PSM] PSM request wake mode up\r\n");

        time_convert();

        err = Publish_sensor_data_Gnss_pressure(device_id_str, pvt_data.latitude, pvt_data.longitude, pvt_data.altitude
                            ,now_tm);
                            if (err){ 
                                printk("[MQTT] sending is failed: %d \r\n", err);
                            }
                            else { 
                                printk("[MQTT] Sending is success\r\n");
                                printk("...\r\n");
                            } 


        lte_lc_psm_req(true);
        printk("[PSM] Publish done, back to PSM\r\n");                    

        
        printk("[MQTT] Disconnecting MQTT client\r\n");
        printk("... \r\n");

    (void)mqtt_disconnect(&client, NULL);

    k_msleep(1000);
    printk("[BMP] Waitting for 1000ms. \r\n");

    

                  

while (1) {

    printk("...\r\n");
    printk(" -- Every 5minutes measurement start -- \r\n");
    

    /* Watchdog Feed */
    wdt_try_feed();

    
    /* Sensor will be mesuring the datas */
    printk("[SEN] Start to read the measurement \r\n");
    printk("... \r\n");
    k_msleep(GAP);

    time_convert();
    /* SEN66 MEASUREMENT */
    SEN66_MEASURE_RAW_NOX_VOC(&sen66, buf, sizeof(buf),VOc_raw_array, 6, "VOC_RAW", &VOc_raw_data);
    SEN66_MEASURE_RAW_NOX_VOC(&sen66, buf, sizeof(buf),NOx_raw_array, 9, "NOX_RAW", &NOx_raw_data);
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), pm1_array, 0, "pm1", &avg_pm1);
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), pm25_array, 3, "pm25", &avg_pm25);
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), pm4_array, 6, "pm4", &avg_pm4);
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), pm10_array, 9, "pm10", &avg_pm10);
    SEN66_MEASURE_s16(&sen66, data_buf, sizeof(data_buf), Humidity_array, 12, "Humidity", &avg_Humidity, 100.0f, "%" ) ;
    SEN66_MEASURE_s16(&sen66, data_buf, sizeof(data_buf), Temp_array, 15, "Temp", &avg_Temp, 200.0f, "T[C]" );
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), VOC__array_Index, 18, "VOC", &avg_VOC_Index);
    SEN66_MEASURE_u16(&sen66, data_buf, sizeof(data_buf), NOx__array_Index, 21, "NOx", &avg_NOx_Index);
    SEN66_MEASURE_CO2(&sen66, data_buf, sizeof(data_buf), co2_array, 24, "CO2", &avg_co2);

     printk("[SEN_B] Start to read the measurement \r\n");
    printk("... \r\n");
    k_msleep(GAP);



    SEN66_MEASURE_RAW_NOX_VOC(&sen66_1, buf_B, sizeof(buf_B),VOc_raw_array_B, 6, "VOC_RAW", &VOc_raw_data_B);
    SEN66_MEASURE_RAW_NOX_VOC(&sen66_1, buf_B, sizeof(buf_B),NOx_raw_array_B, 9, "NOX_RAW", &NOx_raw_data_B);
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), pm1_array_B, 0, "pm1", &avg_pm1_B);
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), pm25_array_B, 3, "pm25", &avg_pm25_B);
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), pm4_array_B, 6, "pm4", &avg_pm4_B);
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), pm10_array_B, 9, "pm10", &avg_pm10_B);
    SEN66_MEASURE_s16(&sen66_1, data_buf_B, sizeof(data_buf_B), Humidity_array_B, 12, "Humidity", &avg_Humidity_B, 100.0f, "%" ) ;
    SEN66_MEASURE_s16(&sen66_1, data_buf_B, sizeof(data_buf_B), Temp_array_B, 15, "Temp", &avg_Temp_B, 200.0f, "T[C]" );
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), VOC__array_Index_B, 18, "VOC", &avg_VOC_Index_B);
    SEN66_MEASURE_u16(&sen66_1, data_buf_B, sizeof(data_buf_B), NOx__array_Index_B, 21, "NOx", &avg_NOx_Index_B);
    SEN66_MEASURE_CO2(&sen66_1, data_buf_B, sizeof(data_buf_B), co2_array_B, 24, "CO2", &avg_co2_B);
    time_convert();

    

    /* BMP581 Pressure(*4) and Temp(*8) */
    bmp5_get_sensor_data(&sensor_data, &osr_cfg, &bmp_dev);
    hPa = sensor_data.pressure/100;
    hPa_B = sensor_data.pressure/100;
    float temp = sensor_data.temperature;


    wdt_try_feed();


    printk("\r\n");
    printk(" -- Average values -- \r\n");

    k_sleep(K_SECONDS(1));

	/* Print values */ 
    printk("[SEN_A] PM1.0     : %.2f ug/m3\r\n",avg_pm1);
    printk("[SEN_A] PM2.5     : %.2f ug/m3\r\n",avg_pm25);
    printk("[SEN_A] PM4.0     : %.2f ug/m3\r\n",avg_pm4);
    printk("[SEN_A] PM10.0    : %.2f ug/m3\r\n",avg_pm10);
    printk("[SEN_A] RH [%%]    : %.2f %%\r\n",avg_Humidity);
    printk("[SEN_A] T[C]      : %.2f T[C]\r\n" ,avg_Temp);
    printk("[SEN_A] VOC Index : %.2f ppb\r\n",avg_VOC_Index);
    printk("[SEN_A] NOx Index : %.2f ppb\r\n",avg_NOx_Index );
    printk("[SEN_A] CO2       : %u   ppm\r\n",avg_co2); 
    printk("[BMP_A] hPa       : %.2f hPa\r\n", hPa);
    printk("[SEN_A] NOx Index : %.2f ppb\r\n",avg_NOx_Index );
    printk("[SEN_A] VOC RAW Data : %u ticks\r\n", VOc_raw_data);
    printk("[SEN_A] NOx RAW Data : %u ticks\r\n", NOx_raw_data);
    printk("\r\n");
    printk("\r\n");
    printk("[SEN_B] PM1.0     : %.2f ug/m3\r\n",avg_pm1_B);
    printk("[SEN_B] PM2.5     : %.2f ug/m3\r\n",avg_pm25_B);
    printk("[SEN_B] PM4.0     : %.2f ug/m3\r\n",avg_pm4_B);
    printk("[SEN_B] PM10.0    : %.2f ug/m3\r\n",avg_pm10_B);
    printk("[SEN_B] RH [%%]    : %.2f %%\r\n",avg_Humidity_B);
    printk("[SEN_B] T[C]      : %.2f T[C]\r\n" ,avg_Temp_B);
    printk("[SEN_B] VOC Index : %.2f ppb\r\n",avg_VOC_Index_B);
    printk("[SEN_B] NOx Index : %.2f ppb\r\n",avg_NOx_Index_B );
    printk("[SEN_B] CO2       : %u   ppm\r\n",avg_co2_B); 
    printk("[BMP_B] hPa       : %.2f hPa\r\n", hPa_B);
    printk("[SEN_B] NOx Index : %.2f ppb\r\n",avg_NOx_Index_B );
    printk("[SEN_B] VOC RAW Data : %u ticks\r\n", VOc_raw_data_B);
    printk("[SEN_B] NOx RAW Data : %u ticks\r\n", NOx_raw_data_B);

    /* Voltage Measurement */
    Voltage_init();
    printk("[ADC] VDD       : %.2f V \r\n", voltage);

    printk("\r\n");
    printk(" -- Measurements are done -- \r\n");
    printk("\r\n");
	

    
    /* Store data into Flash Memory */
    char buf[512] = {0};
    int len_1 = snprintf(buf, sizeof(buf),
                       "%04d-%02d-%02d %02d:%02d:%02d %.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f \r\n",
                        now_tm.tm_year + 1900, now_tm.tm_mon + 1,now_tm.tm_mday,now_tm.tm_hour,now_tm.tm_min,now_tm.tm_sec, avg_pm1, avg_pm25, avg_pm4, avg_pm10,
            avg_Humidity, avg_Temp, avg_VOC_Index, avg_NOx_Index, avg_co2, voltage, hPa, NOx_raw_data, VOc_raw_data);
    char buf_2[512] = {0};
    int len_2 = snprintf(buf, sizeof(buf),
                       "%04d-%02d-%02d %02d:%02d:%02d %.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f \r\n",
                        now_tm.tm_year + 1900, now_tm.tm_mon + 1,now_tm.tm_mday,now_tm.tm_hour,now_tm.tm_min,now_tm.tm_sec, avg_pm1_B, avg_pm25_B, avg_pm4_B, avg_pm10_B,
            avg_Humidity_B, avg_Temp_B, avg_VOC_Index_B, avg_NOx_Index_B, avg_co2_B, voltage, hPa, NOx_raw_data_B, VOc_raw_data_B);

    save_log_to_flash(buf, len_1);
    save_log_to_flash(buf_2, len_2);


    sum_avg_value(avg_pm1, avg_pm25, avg_pm4, avg_pm10, avg_Humidity, avg_Temp, avg_VOC_Index, avg_NOx_Index, avg_co2, voltage, hPa,NOx_raw_data, VOc_raw_data); // current 
    
    sum_avg_value_B(avg_pm1_B, avg_pm25_B, avg_pm4_B, avg_pm10_B, avg_Humidity_B, avg_Temp_B, avg_VOC_Index_B, avg_NOx_Index_B, avg_co2_B, voltage, hPa,NOx_raw_data_B, VOc_raw_data_B);
    

    if(!next_interval_locked)
    {
        if(avg_pm25 >= 35.5f) // >35.5f
            {   
                if(next_interval >= EVERY_5_MINS)
                {
                    printk("[Current pm25] currnet_pm25 over 0.5 %.2f \r\n", avg_pm25);
                    next_interval = EVERY_5_MINS;
                    next_interval_locked = true;
                    printk("[Currnet pm25] next_interval is set 5\r\n");
                }            
                
            }else if ( avg_pm25 < 35.5f && avg_pm25 >= 12.1f ) //35.5f > > 12.1f
            {
                if(next_interval >= EVERY_10_MINS)
                {
                    printk("[Current pm25] currnet_pm25: %.2f previous_pm25: %.2f \r\n", avg_pm25, previous_pm25);
                    next_interval = EVERY_10_MINS;
                    printk("[Currnet pm25] next_interval is set 10\r\n");
                }
                
            }else if ( avg_pm25_B >= 35.5f ) //35.5f > > 12.1f
            {
                if(next_interval >= EVERY_5_MINS)
                {
                    printk("[Current pm25] currnet_pm25: %.2f previous_pm25: %.2f \r\n", avg_pm25, previous_pm25);
                    next_interval = EVERY_5_MINS;
                    printk("[Currnet pm25] next_interval is set 10\r\n");
                }
                
            }else if ( avg_pm25_B < 35.5f && avg_pm25 >= 12.1f ) //35.5f > > 12.1f
            {
                if(next_interval >= EVERY_5_MINS)
                {
                    printk("[Current pm25] currnet_pm25: %.2f previous_pm25: %.2f \r\n", avg_pm25, previous_pm25);
                    next_interval = EVERY_5_MINS;
                    printk("[Currnet pm25] next_interval is set 10\r\n");
                }
                
            }

    }


    printk("[Next interval] Time has been changed: %d\r\n", next_interval);


    k_msleep(1000); 

    /* Watchdog Feed */
    wdt_try_feed();


    }

}

/* Multi Thread */
int Measurement = 20;
int count = 0;

void publishing_mqtt_data_thread(void)
{
    
    while(1)
    {     
        k_sem_take(&alarm_sem, K_FOREVER);
                 
        if(Alarm_expired)
        {

            Measurement = next_interval;
            printk("next interval was set Before Alarm expired next_interval:%d\r\n",next_interval);
            count++;

            if(count >= 5)
            {
                date_time_update_async(date_time_evt_handler);
                count = 0;
            }

            time_convert();  
            reset_rtc_alarm(now_ms, next_interval);

            switch(Measurement)
            {
                case EVERY_20_MINS:
                    printk("[Every 20 Mins] publish datas \r\n");
                    Alarm_expired = false;
                    lte_lc_psm_req(false);
                    
                    /* MQTT Reconnect */
                    MQTT_Reconnect();

                    if(prev_sample_count > 0)
                    {
                        sum_prev_current_value_A();
                        sum_prev_current_value_B();

                    }else{
                        First_loop_value_A();
                        First_loop_value_B();

                    }  

                    time_convert();

                    publish_sensor_data(device_id_str, result_pm1,result_pm25,result_pm4,result_pm10,result_rh,result_Temp,result_co2,result_voltage,result_hPa,result_raw_NOx, result_Raw_VOC,now_tm);
    
                    k_sleep(K_SECONDS(1)); 

                    publish_sensor_data_B(device_id_str, result_pm1_B,result_pm25_B,result_pm4_B,result_pm10_B,result_rh_B,result_Temp_B,result_co2_B,result_voltage_B,result_hPa_B,result_raw_NOx_B, result_Raw_VOC_B,now_tm);

                    update_prev_value_A();
                    update_prev_value_B();
                    

                    prev_sample_count = sample_count;
                    
                    sum_value_reset();

                    lte_lc_psm_req(true);

                    (void)mqtt_disconnect(&client, NULL);

                    // time_convert();  
                    // reset_rtc_alarm(now_ms, next_interval);
                    
                    next_interval_locked = false;
                    next_interval = EVERY_20_MINS;

                    
                    
                    break;

                case EVERY_5_MINS:
                printk("[Every 5 Mins] publish datas\r\n");
                    Alarm_expired = false;
                    lte_lc_psm_req(false);
                    
                    /* MQTT Reconnect */
                    MQTT_Reconnect();

                    if(prev_sample_count > 0)
                    {
                        sum_prev_current_value_A();
                        sum_prev_current_value_B();

                    }else{
                        First_loop_value_A();
                        First_loop_value_B();

                    }  

                    time_convert();

                    publish_sensor_data(device_id_str, result_pm1,result_pm25,result_pm4,result_pm10,result_rh,result_Temp,result_co2,result_voltage,result_hPa,result_raw_NOx, result_Raw_VOC,now_tm);

                    k_sleep(K_SECONDS(1)); 

                    publish_sensor_data_B(device_id_str, result_pm1_B,result_pm25_B,result_pm4_B,result_pm10_B,result_rh_B,result_Temp_B,result_co2_B,result_voltage_B,result_hPa_B,result_raw_NOx_B, result_Raw_VOC_B,now_tm);


                    update_prev_value_A();
                    update_prev_value_B();
                   

                    prev_sample_count = sample_count;
                
                    sum_value_reset();
                
                    lte_lc_psm_req(true);
    
                    (void)mqtt_disconnect(&client, NULL);

                    // time_convert();  
                    // reset_rtc_alarm(now_ms, next_interval);

                    
                    next_interval_locked = false;
                    next_interval = EVERY_20_MINS;

                    break;

                case EVERY_10_MINS:

                    printk("[Every 10 Mins] publish datas \r\n");
                    
                    Alarm_expired = false;
                    lte_lc_psm_req(false);
                    
                    /* MQTT Reconnect */
                    MQTT_Reconnect();

                    if(prev_sample_count > 0)
                    {
                        sum_prev_current_value_A();
                        sum_prev_current_value_B();

                    }else{
                        First_loop_value_A();
                        First_loop_value_B();

                    }  

                    time_convert();

                    publish_sensor_data(device_id_str, result_pm1,result_pm25,result_pm4,result_pm10,result_rh,result_Temp,result_co2,result_voltage,result_hPa,result_raw_NOx, result_Raw_VOC,now_tm);
    
                    k_sleep(K_SECONDS(1)); 

                    publish_sensor_data_B(device_id_str, result_pm1_B,result_pm25_B,result_pm4_B,result_pm10_B,result_rh_B,result_Temp_B,result_co2_B,result_voltage_B,result_hPa_B,result_raw_NOx_B, result_Raw_VOC_B,now_tm);

                    update_prev_value_A();
                    update_prev_value_B();
                    

                    prev_sample_count = sample_count;
                    
                    sum_value_reset();
                    
                    lte_lc_psm_req(true);

                    (void)mqtt_disconnect(&client, NULL);

                    // time_convert();  
                    // reset_rtc_alarm(now_ms, next_interval);

                    next_interval_locked = false;
                    next_interval = EVERY_20_MINS;

                    
                    break;
            }
        
        }

        previous_pm25 = current_pm25;

    }

    }

K_THREAD_DEFINE(thread0_id, STACK_SIZE, publishing_mqtt_data_thread, NULL, NULL, NULL, THREAD_PRIORITY, 0, 0);
