dey-examples/awsiot-sample/src/main.c

329 lines
8.7 KiB
C

/*
* Copyright (c) 2017 Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
* =======================================================================
*/
#include <aws_iot_log.h>
#include <aws_iot_version.h>
#include <aws_iot_shadow_interface.h>
#include <getopt.h>
#include <libgen.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "aws_config.h"
#include "aws_control.h"
#include "daemonize.h"
#include "device_control.h"
/*------------------------------------------------------------------------------
D E F I N I T I O N S
------------------------------------------------------------------------------*/
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define VERSION "0.1" GIT_REVISION
#define AWS_IOT_VERSION TOSTRING(VERSION_MAJOR) "." TOSTRING(VERSION_MINOR) "." TOSTRING(VERSION_PATCH) "-" VERSION_TAG
#define USAGE \
"AWS IoT Device SDK demo.\n" \
"Copyright(c) Digi International Inc.\n" \
"\n" \
"Version: %s\n" \
"AWS IoT SDK Version: " AWS_IOT_VERSION "\n" \
"\n" \
"Usage: %s [options]\n\n" \
" -d --daemon Daemonize the process\n" \
" -c --config-file=<PATH> Use a custom configuration file instead of\n" \
" the default one located in " AWS_IOT_CONFIG_FILE "\n" \
" -h --help Print help and exit\n" \
"\n"
/*------------------------------------------------------------------------------
F U N C T I O N D E C L A R A T I O N S
------------------------------------------------------------------------------*/
static int start_aws_iot(const char *config_file);
static int initialize_system(device_shadow_t *dev_shadow);
static int check_stop(void);
static void add_sigkill_signal(void);
static void graceful_shutdown(void);
static void sigint_handler(int signum);
static void usage(char const *const name);
/*------------------------------------------------------------------------------
G L O B A L V A R I A B L E S
------------------------------------------------------------------------------*/
static volatile int stop = 0;
static AWS_IoT_Client mqtt_client;
/*------------------------------------------------------------------------------
F U N C T I O N D E F I N I T I O N S
------------------------------------------------------------------------------*/
int main(int argc, char **argv)
{
int result = EXIT_SUCCESS;
char *name = basename(argv[0]);
static int opt, opt_index;
int create_daemon = 0;
char *config_file = NULL;
static const char *short_options = "dc:h";
static const struct option long_options[] = {
{"daemon", no_argument, NULL, 'd'},
{"config-file", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
while (1) {
opt = getopt_long(argc, argv, short_options, long_options,
&opt_index);
if (opt == -1)
break;
switch (opt) {
case 'd':
create_daemon = 1;
break;
case 'c':
config_file = optarg;
break;
case 'h':
usage(name);
goto done;
default:
usage(name);
result = EXIT_FAILURE;
goto done;
}
}
/* Daemonize if requested. */
if (create_daemon) {
if (start_daemon(name) != 0) {
result = EXIT_FAILURE;
goto done;
}
}
/* Do the real work. */
start_aws_iot(config_file);
done:
return result;
}
/*
* start_aws_iot() - Start AWS IoT Device SDK
*
* @config_file: Absolute path of the configuration file to use.
* NULL to use the default one (/etc/awsiotsdk.conf).
*
* Return: 0 on success, 1 otherwise.
*/
static int start_aws_iot(const char *config_file)
{
IoT_Error_t rc = FAILURE;
device_shadow_t device_shadow;
time_t time_start;
add_sigkill_signal();
rc = initialize_shadow_client(&mqtt_client, config_file);
if (rc != SUCCESS) {
IOT_ERROR("Cannot initialize Shadow client, error: %d", rc);
return rc;
}
rc = connect_shadow_client(&mqtt_client);
if (rc != SUCCESS) {
IOT_ERROR("Unable to connect, error: %d", rc);
return rc;
}
rc = initialize_shadow(&mqtt_client, &device_shadow);
if (rc != SUCCESS) {
IOT_ERROR("Unable to initialize device Shadow, error: %d", rc);
goto done;
}
if (initialize_system(&device_shadow) != 0)
IOT_WARN("Unable to initialize the whole system");
time_start = time(NULL);
/* Loop and publish shadow changes */
while (rc == NETWORK_ATTEMPTING_RECONNECT ||
rc == NETWORK_RECONNECTED ||
rc == SUCCESS ||
!check_stop()) {
aws_iot_cfg_t *aws_cfg = device_shadow.aws_config;
double t;
double load;
int change_shadow = 0;
rc = aws_iot_mqtt_yield(&mqtt_client, 200);
if (rc == NETWORK_ATTEMPTING_RECONNECT) {
sleep(1);
/* If the client is attempting to reconnect,
* skip the rest of the loop */
continue;
}
t = get_cpu_temp();
device_shadow.temp_update = (t <= (device_shadow.temp - aws_cfg->temp_variation) ||
t >= (device_shadow.temp + aws_cfg->temp_variation));
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 ||
device_shadow.led_update;
if (change_shadow ||
(time(NULL) - time_start) >= aws_cfg->shadow_report_rate) {
device_shadow.temp = t;
device_shadow.cpu_load = load;
IOT_INFO("\n=========================================");
IOT_INFO("Updating shadow...");
if (device_shadow.temp_update)
IOT_INFO(
"Temperature variation greater than %dC\n",
aws_cfg->temp_variation);
if (device_shadow.cpu_load_update)
IOT_INFO(
"CPU Load variation greater than %d%%\n",
aws_cfg->cpuload_variation);
if (device_shadow.led_update)
IOT_INFO(
"LED changed to %s\n",
device_shadow.led_on ? ON : OFF);
IOT_INFO("Temperature: %fC", t);
IOT_INFO("CPU Load: %f%%", load);
IOT_INFO(
"LED status: %s",
device_shadow.led_on ? ON : OFF);
IOT_INFO("=========================================\n");
rc = update_shadow(&mqtt_client);
if ((time(NULL) - time_start) >= aws_cfg->shadow_report_rate)
time_start = time(NULL);
}
sleep(1);
}
done:
if (rc != SUCCESS) {
IOT_ERROR("Error occurred in the loop: %d", rc);
graceful_shutdown();
}
return rc;
}
/*
* initialize_system() - Stop application
*
* @dev_shadow: Device shadow.
*
* Return: 0 if it is successfully initialized, -1 otherwise.
*/
static int initialize_system(device_shadow_t *dev_shadow)
{
int led_gpio = dev_shadow->aws_config->led_gpio;
if (led_gpio > -1 &&
(init_gpio(led_gpio) != 0 ||
set_gpio_direction(led_gpio, OUTPUT) != 0 ||
set_gpio_value(led_gpio, dev_shadow->led_on) != 0)) {
IOT_ERROR("Unable to initialize User LED");
dev_shadow->aws_config->led_gpio = -1;
return -1;
}
return 0;
}
/*
* check_stop() - Stop application
*
* Return: 1 if it is successfully stopped, 0 otherwise.
*/
static int check_stop(void)
{
if (stop) {
IoT_Error_t rc = disconnect_shadow_client(&mqtt_client);
if (rc != SUCCESS) {
IOT_ERROR("Disconnect error: %d", rc);
stop = 0;
}
}
return stop;
}
/*
* add_sigkill_signal() - Add the kill signal to the process
*/
static void add_sigkill_signal(void)
{
struct sigaction new_action;
struct sigaction old_action;
/* Setup signal hander. */
atexit(graceful_shutdown);
new_action.sa_handler = sigint_handler;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGINT, &new_action, NULL);
}
/*
* graceful_shutdown() - Stop MQTT connection and all threads
*/
void graceful_shutdown(void)
{
stop = 1;
check_stop();
}
/**
* sigint_handler() - Manage signal received.
*
* @signum: Received signal.
*/
static void sigint_handler(int signum)
{
IOT_DEBUG("Received signal %d to close Cloud connection.", signum);
exit(0);
}
/**
* usage() - Print usage information
*
* @name: Application name.
*/
static void usage(char const *const name)
{
printf(USAGE, VERSION, name);
}