aws iot sample: add support to report CPU load

The application also monitors the CPU load along with the temperature.
It also uploads the Thing Shadow when the load variation is bigger than 10% (per
param in the config file).

This commit adds the following configuration parameter:
  * 'cpu_load_variation': Minimum absolute value of the difference between last
    reported CPU load and the current value to report again.

https://jira.digi.com/browse/DEL-4149

Signed-off-by: Tatiana Leon <tatiana.leon@digi.com>
This commit is contained in:
Tatiana Leon 2017-05-11 15:24:47 +02:00
parent 1fff418887
commit 4837f8edc5
9 changed files with 125 additions and 8 deletions

View File

@ -2,11 +2,11 @@ AWS IoT device SDK Demo Application
=================================== ===================================
Demo application to connect devices to AWS IoT. Demo application to connect devices to AWS IoT.
This application monitors the CPU temperature. This application monitors the CPU temperature and load.
The demo uploads the device Thing Shadow every minute or when the difference The demo uploads the device Thing Shadow every minute or when the difference
between the temperature current value and the last reported is bigger than a between the current value of temperature or load and the last reported is bigger
configured value. than a configured value (1C for temperature and 10% for CPU load).
The repository has the following directories: The repository has the following directories:
@ -50,7 +50,8 @@ You can specify the configuration file with `-c`:
{ {
"state" : { "state" : {
"reported" : { "reported" : {
"temperature" : 45.971 "temperature" : 45.971,
"cpuLoad" : 4.504505
} }
}, },
"clientToken" : "<thing_name>-3" "clientToken" : "<thing_name>-3"

View File

@ -59,3 +59,9 @@ shadow_report_rate = 60
# By default, 1C. # By default, 1C.
temperature_variation = 1 temperature_variation = 1
# CPU load variation: Minimum absolute value of the difference between last
# reported CPU load and the current value to report to the cloud again (in %).
# Its value must be between 0.1% and 50.0%.
# By default, 10%.
cpu_load_variation = 10

View File

@ -44,6 +44,9 @@
#define SETTING_TEMP_VARIATION "temperature_variation" #define SETTING_TEMP_VARIATION "temperature_variation"
#define SETTING_TEMP_VARIATION_MIN 0.1 /* C */ #define SETTING_TEMP_VARIATION_MIN 0.1 /* C */
#define SETTING_TEMP_VARIATION_MAX 10.0 /* C */ #define SETTING_TEMP_VARIATION_MAX 10.0 /* C */
#define SETTING_CPULOAD_VARIATION "cpu_load_variation"
#define SETTING_CPULOAD_VARIATION_MIN 1 /* % */
#define SETTING_CPULOAD_VARIATION_MAX 50.0 /* % */
#define SETTING_UNKNOWN "__unknown" #define SETTING_UNKNOWN "__unknown"
@ -58,6 +61,7 @@ static int cfg_check_certificates_path(cfg_t *cfg, cfg_opt_t *opt);
static int cfg_check_cert_file(cfg_t *cfg, cfg_opt_t *opt); static int cfg_check_cert_file(cfg_t *cfg, cfg_opt_t *opt);
static int cfg_check_shadow_report_rate(cfg_t *cfg, cfg_opt_t *opt); static int cfg_check_shadow_report_rate(cfg_t *cfg, cfg_opt_t *opt);
static int cfg_check_temp_variation(cfg_t *cfg, cfg_opt_t *opt); static int cfg_check_temp_variation(cfg_t *cfg, cfg_opt_t *opt);
static int cfg_check_cpuload_variation(cfg_t *cfg, cfg_opt_t *opt);
static int cfg_check_int_range(cfg_t *cfg, cfg_opt_t *opt, uint32_t min, uint32_t max); static int cfg_check_int_range(cfg_t *cfg, cfg_opt_t *opt, uint32_t min, uint32_t max);
static int cfg_check_float_range(cfg_t *cfg, cfg_opt_t *opt, float min, float max); static int cfg_check_float_range(cfg_t *cfg, cfg_opt_t *opt, float min, float max);
static int cfg_check_empty_string(cfg_t *cfg, cfg_opt_t *opt); static int cfg_check_empty_string(cfg_t *cfg, cfg_opt_t *opt);
@ -106,6 +110,7 @@ int parse_configuration(const char *const filename, aws_iot_cfg_t *aws_cfg)
CFG_INT (SETTING_SHADOW_REPORT_RATE, 60, CFGF_NONE), CFG_INT (SETTING_SHADOW_REPORT_RATE, 60, CFGF_NONE),
CFG_FLOAT (SETTING_TEMP_VARIATION, 1, CFGF_NONE), CFG_FLOAT (SETTING_TEMP_VARIATION, 1, CFGF_NONE),
CFG_FLOAT (SETTING_CPULOAD_VARIATION, 10, CFGF_NONE),
/* Needed for unknown settings. */ /* Needed for unknown settings. */
CFG_STR (SETTING_UNKNOWN, NULL, CFGF_NONE), CFG_STR (SETTING_UNKNOWN, NULL, CFGF_NONE),
@ -133,6 +138,7 @@ int parse_configuration(const char *const filename, aws_iot_cfg_t *aws_cfg)
cfg_set_validate_func(cfg, SETTING_PRIVKEY_NAME, cfg_check_cert_file); cfg_set_validate_func(cfg, SETTING_PRIVKEY_NAME, cfg_check_cert_file);
cfg_set_validate_func(cfg, SETTING_SHADOW_REPORT_RATE, cfg_check_shadow_report_rate); cfg_set_validate_func(cfg, SETTING_SHADOW_REPORT_RATE, cfg_check_shadow_report_rate);
cfg_set_validate_func(cfg, SETTING_TEMP_VARIATION, cfg_check_temp_variation); cfg_set_validate_func(cfg, SETTING_TEMP_VARIATION, cfg_check_temp_variation);
cfg_set_validate_func(cfg, SETTING_CPULOAD_VARIATION, cfg_check_cpuload_variation);
/* Parse the configuration file. */ /* Parse the configuration file. */
switch (cfg_parse(cfg, filename)) { switch (cfg_parse(cfg, filename)) {
@ -192,6 +198,7 @@ static int fill_aws_iot_config(aws_iot_cfg_t *aws_cfg)
return -1; return -1;
aws_cfg->shadow_report_rate = cfg_getint(cfg, SETTING_SHADOW_REPORT_RATE); aws_cfg->shadow_report_rate = cfg_getint(cfg, SETTING_SHADOW_REPORT_RATE);
aws_cfg->temp_variation = cfg_getfloat(cfg, SETTING_TEMP_VARIATION); aws_cfg->temp_variation = cfg_getfloat(cfg, SETTING_TEMP_VARIATION);
aws_cfg->cpuload_variation = cfg_getfloat(cfg, SETTING_CPULOAD_VARIATION);
return 0; return 0;
} }
@ -336,6 +343,22 @@ static int cfg_check_temp_variation(cfg_t *cfg, cfg_opt_t *opt)
SETTING_TEMP_VARIATION_MAX); SETTING_TEMP_VARIATION_MAX);
} }
/*
* cfg_check_cpuload_variation() - Validate CPU load variation value is between
* 0.1 and 50.0
*
* @cfg: The section where the option is defined.
* @opt: The option to check.
*
* @Return: 0 on success, any other value otherwise.
*/
static int cfg_check_cpuload_variation(cfg_t *cfg, cfg_opt_t *opt)
{
return cfg_check_float_range(cfg, opt,
SETTING_CPULOAD_VARIATION_MIN,
SETTING_CPULOAD_VARIATION_MAX);
}
/* /*
* cfg_check_int_range() - Validate a parameter int value is between the given range * cfg_check_int_range() - Validate a parameter int value is between the given range
* *

View File

@ -47,6 +47,8 @@
* @shadow_report_rate: Frequency at which report system information (seconds) * @shadow_report_rate: Frequency at which report system information (seconds)
* @temp_variation: Temperature variation between last reported and current * @temp_variation: Temperature variation between last reported and current
* (C) to report again * (C) to report again
* @cpuload_variation: CPU load variation between last reported and current (%)
* to report again
*/ */
typedef struct { typedef struct {
char *thing_name; char *thing_name;
@ -59,6 +61,7 @@ typedef struct {
char *priv_key_fname; char *priv_key_fname;
uint32_t shadow_report_rate; uint32_t shadow_report_rate;
uint16_t temp_variation; uint16_t temp_variation;
uint16_t cpuload_variation;
} aws_iot_cfg_t; } aws_iot_cfg_t;
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------

View File

@ -185,6 +185,14 @@ IoT_Error_t initialize_shadow(AWS_IoT_Client *mqtt_client,
device_shadow->temp = 0; device_shadow->temp = 0;
device_shadow->temp_update = 0; device_shadow->temp_update = 0;
device_shadow->cpu_load_handler.cb = NULL;
device_shadow->cpu_load_handler.pKey = ATTR_CPU_LOAD;
device_shadow->cpu_load_handler.pData = &(device_shadow->cpu_load);
device_shadow->cpu_load_handler.type = SHADOW_JSON_DOUBLE;
device_shadow->cpu_load = 0;
device_shadow->cpu_load_update = 0;
device_shadow->aws_config = &aws_cfg; device_shadow->aws_config = &aws_cfg;
return SUCCESS; return SUCCESS;
@ -208,8 +216,9 @@ IoT_Error_t update_shadow(AWS_IoT_Client *mqtt_client)
return rc; return rc;
rc = aws_iot_shadow_add_reported(json_doc_buf, size_json_doc_buf, rc = aws_iot_shadow_add_reported(json_doc_buf, size_json_doc_buf,
1, 2,
&(device_shadow->temp_handler)); &(device_shadow->temp_handler),
&(device_shadow->cpu_load_handler));
if (rc != SUCCESS) if (rc != SUCCESS)
return rc; return rc;
@ -260,6 +269,7 @@ static void shadow_update_status_callback(const char *pThingName,
case SHADOW_ACK_ACCEPTED: case SHADOW_ACK_ACCEPTED:
IOT_INFO("Shadow update accepted"); IOT_INFO("Shadow update accepted");
dev_shadow->temp_update = 0; dev_shadow->temp_update = 0;
dev_shadow->cpu_load_update = 0;
break; break;
} }
} }

View File

@ -29,6 +29,7 @@
D E F I N I T I O N S D E F I N I T I O N S
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
#define ATTR_TEMPERATURE "temperature" #define ATTR_TEMPERATURE "temperature"
#define ATTR_CPU_LOAD "cpuLoad"
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
D A T A T Y P E S D E F I N I T I O N S D A T A T Y P E S D E F I N I T I O N S
@ -40,6 +41,9 @@
* @temp: Last temperature reported (C) * @temp: Last temperature reported (C)
* @temp_handler: Temperature handler * @temp_handler: Temperature handler
* @temp_update: Temperature value locally updated * @temp_update: Temperature value locally updated
* @cpu_load: Last CPU load reported (%)
* @cpu_load_handler: CPU load handler
* @cpu_load_update: CPU load value locally updated
* @update_required: Update shadow immediately * @update_required: Update shadow immediately
* @aws_config: AWS IoT Decive SDK configuration struct * @aws_config: AWS IoT Decive SDK configuration struct
*/ */
@ -47,6 +51,9 @@ typedef struct {
double temp; double temp;
jsonStruct_t temp_handler; jsonStruct_t temp_handler;
unsigned int temp_update; unsigned int temp_update;
double cpu_load;
jsonStruct_t cpu_load_handler;
unsigned int cpu_load_update;
unsigned int update_required; unsigned int update_required;
aws_iot_cfg_t *aws_config; aws_iot_cfg_t *aws_config;
} device_shadow_t; } device_shadow_t;

View File

@ -29,6 +29,7 @@
#define MAX_LENGTH 256 #define MAX_LENGTH 256
#define FILE_CPU_TEMP "/sys/class/thermal/thermal_zone0/temp" #define FILE_CPU_TEMP "/sys/class/thermal/thermal_zone0/temp"
#define FILE_CPU_LOAD "/proc/stat"
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
F U N C T I O N D E C L A R A T I O N S F U N C T I O N D E C L A R A T I O N S
@ -38,6 +39,57 @@ static long read_file(const char * path, char *buffer, long bytes_to_read);
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
F U N C T I O N D E F I N I T I O N S F U N C T I O N D E F I N I T I O N S
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
/*
* get_cpu_load() - Get the CPU load of the system
*
* Return: The CPU load in %, -1 if the value is not available.
*/
double get_cpu_load(void)
{
static unsigned long long last_work = 0, last_total = 0;
char data[MAX_LENGTH] = {0};
unsigned long long int fields[10];
unsigned long long work = 0, total = 0;
double usage = -1;
int i, result;
if (read_file(FILE_CPU_LOAD, data, MAX_LENGTH) <= 0) {
IOT_ERROR("Error reading cpu load file");
return usage;
}
result = sscanf(data, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
&fields[0], &fields[1], &fields[2], &fields[3], &fields[4],
&fields[5], &fields[6], &fields[7], &fields[8], &fields[9]);
if (result < 4) {
IOT_ERROR("CPU load not enough fields error");
return usage;
}
for (i = 0; i < 3; i++) {
work += fields[i];
}
for (i = 0; i < result; i++) {
total += fields[i];
}
if (last_work == 0 && last_total == 0) {
/* The first time report 0%. */
usage = 0;
} else {
unsigned long long diff_work = work - last_work;
unsigned long long diff_total = total - last_total;
usage = diff_work * 100.0 / diff_total;
}
last_total = total;
last_work = work;
return usage;
}
/* /*
* get_cpu_temp() - Get the CPU temperature of the system * get_cpu_temp() - Get the CPU temperature of the system
* *

View File

@ -23,6 +23,7 @@
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
F U N C T I O N D E C L A R A T I O N S F U N C T I O N D E C L A R A T I O N S
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
double get_cpu_load(void);
double get_cpu_temp(void); double get_cpu_temp(void);
#endif /* DEVICE_CONTROL_H_ */ #endif /* DEVICE_CONTROL_H_ */

View File

@ -168,6 +168,8 @@ static int start_aws_iot(const char *config_file)
!check_stop()) { !check_stop()) {
aws_iot_cfg_t *aws_cfg = device_shadow.aws_config; aws_iot_cfg_t *aws_cfg = device_shadow.aws_config;
double t; double t;
double load;
int change_shadow = 0;
rc = aws_iot_mqtt_yield(&mqtt_client, 200); rc = aws_iot_mqtt_yield(&mqtt_client, 200);
@ -182,9 +184,17 @@ static int start_aws_iot(const char *config_file)
device_shadow.temp_update = (t <= (device_shadow.temp - aws_cfg->temp_variation) || device_shadow.temp_update = (t <= (device_shadow.temp - aws_cfg->temp_variation) ||
t >= (device_shadow.temp + aws_cfg->temp_variation)); t >= (device_shadow.temp + aws_cfg->temp_variation));
if (device_shadow.temp_update || load = get_cpu_load();
device_shadow.cpu_load_update = (load <= (device_shadow.cpu_load - aws_cfg->cpuload_variation) ||
load >= (device_shadow.cpu_load + aws_cfg->cpuload_variation));
change_shadow = device_shadow.temp_update ||
device_shadow.cpu_load_update;
if (change_shadow ||
(time(NULL) - time_start) >= aws_cfg->shadow_report_rate) { (time(NULL) - time_start) >= aws_cfg->shadow_report_rate) {
device_shadow.temp = t; device_shadow.temp = t;
device_shadow.cpu_load = load;
IOT_INFO("\n========================================="); IOT_INFO("\n=========================================");
IOT_INFO("Updating shadow..."); IOT_INFO("Updating shadow...");
@ -192,8 +202,12 @@ static int start_aws_iot(const char *config_file)
IOT_INFO( IOT_INFO(
"Temperature variation greater than %dC\n", "Temperature variation greater than %dC\n",
aws_cfg->temp_variation); aws_cfg->temp_variation);
if (device_shadow.cpu_load_update)
IOT_INFO(
"CPU Load variation greater than %d%%\n",
aws_cfg->cpuload_variation);
IOT_INFO("Temperature: %fC", t); IOT_INFO("Temperature: %fC", t);
IOT_INFO("CPU Load: %f%%", load);
IOT_INFO("=========================================\n"); IOT_INFO("=========================================\n");
rc = update_shadow(&mqtt_client); rc = update_shadow(&mqtt_client);