CO2_MonitorHealthySpaces/src/main.h (102 lines of code) (raw):
/* Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. */
#pragma once
#include "dx_deferred_update.h"
#include "dx_gpio.h"
#include "dx_json_serializer.h"
#include "dx_i2c.h"
#include "dx_pwm.h"
#include "dx_terminate.h"
#include "dx_timer.h"
#include "dx_utilities.h"
#include "dx_version.h"
#include "hw/co2_monitor.h" // Hardware definition
#include "app_exit_codes.h" // application specific exit codes
#include "Onboard/onboard_sensors.h"
#include "Onboard/azure_status.h"
#include "co2_sensor.h"
#include <applibs/applications.h>
#include <applibs/log.h>
#include <applibs/powermanagement.h>
// https://learn.microsoft.com/en-us/azure/iot-pnp/overview-iot-plug-and-play
#define IOT_PLUG_AND_PLAY_MODEL_ID "dtmi:com:example:azuresphere:co2monitor;2"
#define NETWORK_INTERFACE "wlan0"
#define CO2_MONITOR_FIRMWARE_VERSION "3.02"
/***********************************************************************************************************
* Forward declarations
**********************************************************************************************************/
static DX_DIRECT_METHOD_RESPONSE_CODE restart_device_handler(JSON_Value *json, DX_DIRECT_METHOD_BINDING *directMethodBinding,
char **responseMsg);
static void co2_alert_buzzer_off_handler(EventLoopTimer *eventLoopTimer);
static void co2_alert_handler(EventLoopTimer *eventLoopTimer);
static void delayed_restart_device_handler(EventLoopTimer *eventLoopTimer);
static void publish_telemetry_handler(EventLoopTimer *eventLoopTimer);
static void read_buttons_handler(EventLoopTimer *eventLoopTimer);
static void read_telemetry_handler(EventLoopTimer *eventLoopTimer);
static void set_co2_alert_level(DX_DEVICE_TWIN_BINDING *deviceTwinBinding);
static void set_device_altitude(DX_DEVICE_TWIN_BINDING *deviceTwinBinding);
static void update_device_twins(EventLoopTimer *eventLoopTimer);
static void watchdog_handler(EventLoopTimer *eventLoopTimer);
void azure_status_led_off_handler(EventLoopTimer *eventLoopTimer);
void azure_status_led_on_handler(EventLoopTimer *eventLoopTimer);
/***********************************************************************************************************
* Declare global variables
**********************************************************************************************************/
#define Log_Debug(f_, ...) dx_Log_Debug((f_), ##__VA_ARGS__)
static char Log_Debug_Time_buffer[128];
#define JSON_MESSAGE_BYTES 256
static char msgBuffer[JSON_MESSAGE_BYTES] = {0};
// Set alert level to a reasonable default. This is updated by CO2PPMAlertLevel device twin
static int32_t co2_alert_level = 1000;
static bool be_quiet = false;
ENVIRONMENT telemetry;
static DX_USER_CONFIG dx_config;
bool azure_connected = false;
static const struct itimerspec watchdogInterval = {{60, 0}, {60, 0}};
static timer_t watchdogTimer;
/***********************************************************************************************************
* Common content properties for publish messages to IoT Hub/Central
**********************************************************************************************************/
/// <summary>
/// Publish sensor telemetry using the following properties for efficient IoT Hub routing
/// https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-d2c
/// </summary>
static DX_MESSAGE_PROPERTY *messageProperties[] = {&(DX_MESSAGE_PROPERTY){.key = "appid", .value = "co2monitor"},
&(DX_MESSAGE_PROPERTY){.key = "type", .value = "telemetry"},
&(DX_MESSAGE_PROPERTY){.key = "schema", .value = "1"}};
static DX_MESSAGE_CONTENT_PROPERTIES contentProperties = {.contentEncoding = "utf-8", .contentType = "application/json"};
/***********************************************************************************************************
* declare device twin bindings
**********************************************************************************************************/
static DX_DEVICE_TWIN_BINDING dt_co2_ppm_alert_level = {
.propertyName = "AlertLevel", .twinType = DX_DEVICE_TWIN_INT, .handler = set_co2_alert_level};
static DX_DEVICE_TWIN_BINDING dt_altitude_in_meters = {
.propertyName = "AltitudeInMeters", .twinType = DX_DEVICE_TWIN_INT, .handler = set_device_altitude};
static DX_DEVICE_TWIN_BINDING dt_humidity = {.propertyName = "Humidity", .twinType = DX_DEVICE_TWIN_INT};
static DX_DEVICE_TWIN_BINDING dt_pressure = {.propertyName = "Pressure", .twinType = DX_DEVICE_TWIN_INT};
static DX_DEVICE_TWIN_BINDING dt_temperature = {.propertyName = "Temperature", .twinType = DX_DEVICE_TWIN_INT};
static DX_DEVICE_TWIN_BINDING dt_carbon_dioxide = {.propertyName = "CarbonDioxide", .twinType = DX_DEVICE_TWIN_INT};
static DX_DEVICE_TWIN_BINDING dt_startup_utc = {.propertyName = "StartupUtc", .twinType = DX_DEVICE_TWIN_STRING};
static DX_DEVICE_TWIN_BINDING dt_sw_version = {.propertyName = "SoftwareVersion", .twinType = DX_DEVICE_TWIN_STRING};
static DX_DEVICE_TWIN_BINDING dt_defer_requested = {.propertyName = "DeferredUpdateRequest", .twinType = DX_DEVICE_TWIN_STRING};
/***********************************************************************************************************
* declare direct methods
**********************************************************************************************************/
static DX_DIRECT_METHOD_BINDING dm_restart_device = {.methodName = "RestartDevice", .handler = restart_device_handler};
/***********************************************************************************************************
* declare gpio bindings
**********************************************************************************************************/
DX_GPIO_BINDING gpio_network_led = {
.pin = AZURE_CONNECTED_LED, .name = "network_led", .direction = DX_OUTPUT, .initialState = GPIO_Value_Low, .invertPin = true};
static DX_GPIO_BINDING gpio_button_b = {.pin = BUTTON_B, .name = "button_b", .direction = DX_INPUT, .detect = DX_GPIO_DETECT_LOW};
/***********************************************************************************************************
* declare timer bindings
**********************************************************************************************************/
DX_TIMER_BINDING tmr_azure_status_led_off = {.name = "tmr_azure_status_led_off", .handler = azure_status_led_off_handler};
DX_TIMER_BINDING tmr_azure_status_led_on = {
.period = {0, 500 * ONE_MS}, .name = "tmr_azure_status_led_on", .handler = azure_status_led_on_handler};
static DX_TIMER_BINDING tmr_co2_alert_buzzer_off_oneshot = {.name = "tmr_co2_alert_buzzer_off_oneshot",
.handler = co2_alert_buzzer_off_handler};
static DX_TIMER_BINDING tmr_co2_alert_timer = {.period = {8, 0}, .name = "tmr_co2_alert_timer", .handler = co2_alert_handler};
static DX_TIMER_BINDING tmr_delayed_restart_device = {.name = "tmr_delayed_restart_device", .handler = delayed_restart_device_handler};
static DX_TIMER_BINDING tmr_publish_telemetry = {.period = {20, 0}, .name = "tmr_publish_telemetry", .handler = publish_telemetry_handler};
static DX_TIMER_BINDING tmr_read_buttons = {.period = {0, 100 * ONE_MS}, .name = "tmr_read_buttons", .handler = read_buttons_handler};
static DX_TIMER_BINDING tmr_read_telemetry = {.name = "tmr_read_telemetry", .handler = read_telemetry_handler};
static DX_TIMER_BINDING tmr_update_device_twins = {.period = {15, 0}, .name = "tmr_update_device_twins", .handler = update_device_twins};
static DX_TIMER_BINDING tmr_watchdog = {.period = {30, 0}, .name = "tmr_publish_telemetry", .handler = watchdog_handler};
/***********************************************************************************************************
* declare pwm bindings
**********************************************************************************************************/
static DX_PWM_CONTROLLER pwm_click_controller = {.controllerId = PWM_CLICK_CONTROLLER, .name = "PWM Click Controller"};
static DX_PWM_CONTROLLER pwm_rgb_controller = {.controllerId = PWM_RGB_CONTROLLER, .name = "PWM RBG Controller"};
static DX_PWM_BINDING pwm_buzz_click = {.pwmController = &pwm_click_controller, .channelId = 0, .name = "click 1 buzz"};
static DX_PWM_BINDING pwm_led_red = {.pwmController = &pwm_rgb_controller, .channelId = 0, .name = "pwm red led"};
static DX_PWM_BINDING pwm_led_green = {.pwmController = &pwm_rgb_controller, .channelId = 1, .name = "pwm green led"};
static DX_PWM_BINDING pwm_led_blue = {.pwmController = &pwm_rgb_controller, .channelId = 2, .name = "pwm green led"};
/***********************************************************************************************************
* declare i2c bindings
**********************************************************************************************************/
DX_I2C_BINDING i2c_co2_sensor = {.interfaceId = I2C_ISU2, .speedInHz = I2C_BUS_SPEED_STANDARD, .name = "i2c co2 sensor"};
DX_I2C_BINDING i2c_onboard_sensors = {.interfaceId = I2C_ISU2, .speedInHz = I2C_BUS_SPEED_STANDARD, .name = "i2c co2 sensor"};
/***********************************************************************************************************
* declare binding sets
**********************************************************************************************************/
// All bindings referenced in the following binding sets are initialised in the InitPeripheralsAndHandlers function
static DX_DEVICE_TWIN_BINDING *device_twin_bindings[] = {&dt_co2_ppm_alert_level, &dt_startup_utc, &dt_sw_version,
&dt_temperature, &dt_pressure, &dt_humidity,
&dt_carbon_dioxide, &dt_defer_requested, &dt_altitude_in_meters};
static DX_PWM_BINDING *pwm_bindings[] = {&pwm_buzz_click, &pwm_led_green, &pwm_led_red, &pwm_led_blue};
DX_I2C_BINDING *i2c_bindings[] = {&i2c_co2_sensor, &i2c_onboard_sensors};
static DX_GPIO_BINDING *gpio_bindings[] = {&gpio_network_led, &gpio_button_b};
static DX_DIRECT_METHOD_BINDING *direct_method_bindings[] = {&dm_restart_device};
static DX_TIMER_BINDING *timer_bindings[] = {&tmr_read_telemetry,
&tmr_co2_alert_buzzer_off_oneshot,
&tmr_co2_alert_timer,
&tmr_azure_status_led_on,
&tmr_azure_status_led_off,
&tmr_publish_telemetry,
&tmr_update_device_twins,
&tmr_read_buttons,
&tmr_watchdog,
&tmr_delayed_restart_device};