Mario Soranno
Published © MIT

Sanitizing bathrooms after each use

UVC used to sanitize repeatedly shared spaces (public bathrooms after each use or wherever an automatic periodic sanitization is required).

IntermediateFull instructions provided215
Sanitizing bathrooms after each use

Things used in this project

Hardware components

AWS IoT EduKit
Amazon Web Services AWS IoT EduKit
×1
PIR Sensor Human Body Infrared PIR Motion Sensor (AS312)
M5Stack PIR Sensor Human Body Infrared PIR Motion Sensor (AS312)
×1
Unbuckled Grove Cable 1m/2m/50cm/20cm/10cm
M5Stack Unbuckled Grove Cable 1m/2m/50cm/20cm/10cm
×1
Philips hue Philips 62878740 36W 2G11 lampada UV
×2
Lamp Holder, 2G11 Compact Fluorescent Lamps
Lamp Holder, 2G11 Compact Fluorescent Lamps
×2
Electronic Ballast 220-240VAC 2x36W
×1
Solid State Relays
×1
LED (generic)
LED (generic)
For test
×1
Resistor 1k ohm
Resistor 1k ohm
For test
×1

Software apps and online services

Visual Studio Code
AWS IoT
Amazon Web Services AWS IoT
IoT Core and IoT Events

Hand tools and fabrication machines

Drill / Driver, Cordless
Drill / Driver, Cordless
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Support Lamp Reflector

Only one is needed per module.

Support Lamp

Two are needed for each module.

Support Lamp Holder

Only one is needed per module.

Schematics

Electric Schematic

Electrical connection

Code

main.c

C/C++
Main program
/*
 * AWS IoT EduKit - Core2 for AWS IoT EduKit
 * Smart Sanitizing v1.0.0
 * main.c
 * 
 * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
 * Additions Copyright 2021 Mario Soranno
 * 
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
/**
 * @file main.c
 * @brief simple MQTT publish, subscribe, and device shadows for use with AWS IoT EduKit reference hardware.
 *
 * Some configuration is required. Visit https://edukit.workshop.aws
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <math.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#include "esp_log.h"

#include "aws_iot_config.h"
#include "aws_iot_log.h"
#include "aws_iot_version.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_shadow_interface.h"

#include "core2forAWS.h"

#include "wifi.h"
#include "fft.h"
#include "ui.h"

static const char *TAG = "MAIN";

#define STARTING_BATHROOMAVAILABLE true
#define STARTING_BATHROOMOCCUPIED false
#define STARTING_BATHROOMSANITIZATION false
#define STARTING_LAMPOFF true

#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200

/* CA Root certificate */
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");

/* Default MQTT HOST URL is pulled from the aws_iot_config.h */
char HostAddress[255] = AWS_IOT_MQTT_HOST;

/* Default MQTT port is pulled from the aws_iot_config.h */
uint32_t port = AWS_IOT_MQTT_PORT;

#define COUNTON_VALUE 10
#define COUNTOFF_VALUE 30
#define COUNTLAMP_VALUE 800
#define GPIO_PIR GPIO_NUM_33
#define GPIO_LAMP GPIO_NUM_13

bool writePINOK = 0;
uint32_t countLamp = COUNTLAMP_VALUE;

bool bathroomAvailable = STARTING_BATHROOMAVAILABLE;
bool bathroomOccupied = STARTING_BATHROOMOCCUPIED;
bool bathroomSanitization = STARTING_BATHROOMSANITIZATION;
bool LampOFF = STARTING_LAMPOFF;

void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
                                    IoT_Publish_Message_Params *params, void *pData) {
    ESP_LOGI(TAG, "Subscribe callback");
    ESP_LOGI(TAG, "%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *)params->payload);
}

void disconnect_callback_handler(AWS_IoT_Client *pClient, void *data) {
    ESP_LOGW(TAG, "MQTT Disconnect");
    ui_textarea_add("Disconnected from AWS IoT Core...", NULL, 0);

    IoT_Error_t rc = FAILURE;

    if(NULL == pClient) {
        return;
    }

    if(aws_iot_is_autoreconnect_enabled(pClient)) {
        ESP_LOGI(TAG, "Auto Reconnect is enabled, Reconnecting attempt will start now");
    } else {
        ESP_LOGW(TAG, "Auto Reconnect not enabled. Starting manual reconnect...");
        rc = aws_iot_mqtt_attempt_reconnect(pClient);
        if(NETWORK_RECONNECTED == rc) {
            ESP_LOGW(TAG, "Manual Reconnect Successful");
        } else {
            ESP_LOGW(TAG, "Manual Reconnect Failed - %d", rc);
        }
    }
}

static bool shadowUpdateInProgress;

void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
                                const char *pReceivedJsonDocument, void *pContextData) {
    IOT_UNUSED(pThingName);
    IOT_UNUSED(action);
    IOT_UNUSED(pReceivedJsonDocument);
    IOT_UNUSED(pContextData);

    shadowUpdateInProgress = false;

    if(SHADOW_ACK_TIMEOUT == status) {
        ESP_LOGE(TAG, "Update timed out");
    } else if(SHADOW_ACK_REJECTED == status) {
        ESP_LOGE(TAG, "Update rejected");
    } else if(SHADOW_ACK_ACCEPTED == status) {
        ESP_LOGI(TAG, "Update accepted");
    }
}

/********************************************************
 * This callback deactivates the UV-C lamps and brings the 
 * device into the bathroom available condition when it receives 
 * LampOFF == true and the device is in the sanitization phase.
 * *****************************************************/
void LampOFF_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext)
    {
    IOT_UNUSED(pJsonString);
    IOT_UNUSED(JsonStringDataLen);

    bool * statusLamp = (bool *) (pContext->pData);

    if(pContext != NULL) {
        ESP_LOGI(TAG, "Delta - Sanitization state changed to %d ", *statusLamp);
    }

    if((*statusLamp == 1) && (bathroomAvailable == false) && (bathroomOccupied == false) && (bathroomSanitization == true))
        {
        if(writePINOK == 1) Core2ForAWS_Port_Write(GPIO_LAMP, 0); // Lamp OFF -----------------------------------------
        Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0x00ff00);    // Green
        Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0x00ff00);
        Core2ForAWS_Sk6812_Show ();
        bathroomAvailable = true;
        bathroomOccupied = false;
        bathroomSanitization = false;
        countLamp = COUNTLAMP_VALUE;
        LampOFF = false;
        ui_textarea_add("\nBathroom Available!\n", NULL, 0);
        ESP_LOGI(TAG, "bathroom Available ------------------------------------------------");
        }
    }


void aws_iot_task(void *param) {

    IoT_Error_t rc = FAILURE;

    char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
    size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);

    jsonStruct_t bathroomAvailableHandler;
    bathroomAvailableHandler.cb = NULL;
    bathroomAvailableHandler.pKey = "bathroomAvailable";
    bathroomAvailableHandler.pData = &bathroomAvailable;
    bathroomAvailableHandler.type = SHADOW_JSON_BOOL;
    bathroomAvailableHandler.dataLength = sizeof(bool);

    jsonStruct_t bathroomOccupiedHandler;
    bathroomOccupiedHandler.cb = NULL;
    bathroomOccupiedHandler.pKey = "bathroomOccupied";
    bathroomOccupiedHandler.pData = &bathroomOccupied;
    bathroomOccupiedHandler.type = SHADOW_JSON_BOOL;
    bathroomOccupiedHandler.dataLength = sizeof(bool);

    jsonStruct_t bathroomSanitizationHandler;
    bathroomSanitizationHandler.cb = NULL;
    bathroomSanitizationHandler.pKey = "bathroomSanitization";
    bathroomSanitizationHandler.pData = &bathroomSanitization;
    bathroomSanitizationHandler.type = SHADOW_JSON_BOOL;
    bathroomSanitizationHandler.dataLength = sizeof(bool);

    jsonStruct_t LampOFFActuator;
    LampOFFActuator.cb = LampOFF_Callback;
    LampOFFActuator.pKey = "LampOFF";
    LampOFFActuator.pData = &LampOFF;
    LampOFFActuator.type = SHADOW_JSON_BOOL;
    LampOFFActuator.dataLength = sizeof(bool);

    ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);

    // initialize the mqtt client
    AWS_IoT_Client iotCoreClient;

    ShadowInitParameters_t sp = ShadowInitParametersDefault;
    sp.pHost = HostAddress;
    sp.port = port;
    sp.enableAutoReconnect = false;
    sp.disconnectHandler = disconnect_callback_handler;

    sp.pRootCA = (const char *)aws_root_ca_pem_start;
    sp.pClientCRT = "#";
    sp.pClientKey = "#0";
    
    #define CLIENT_ID_LEN (ATCA_SERIAL_NUM_SIZE * 2)
    char *client_id = malloc(CLIENT_ID_LEN + 1);
    ATCA_STATUS ret = Atecc608_GetSerialString(client_id);
    if (ret != ATCA_SUCCESS){
        ESP_LOGE(TAG, "Failed to get device serial from secure element. Error: %i", ret);
        abort();
    }

    ui_textarea_add("\nDevice client Id:\n>> %s <<\n", client_id, CLIENT_ID_LEN);

    /* Wait for WiFI to show as connected */
    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
                        false, true, portMAX_DELAY);

    ESP_LOGI(TAG, "Shadow Init");

    rc = aws_iot_shadow_init(&iotCoreClient, &sp);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "aws_iot_shadow_init returned error %d, aborting...", rc);
        abort();
    }

    ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
    scp.pMyThingName = client_id;
    scp.pMqttClientId = client_id;
    scp.mqttClientIdLen = CLIENT_ID_LEN;

    ESP_LOGI(TAG, "Shadow Connect");
    rc = aws_iot_shadow_connect(&iotCoreClient, &scp);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "aws_iot_shadow_connect returned error %d, aborting...", rc);
        abort();
    }
    ui_textarea_add("\nConnected to AWS IoT Core and pub/sub to the device shadow state\n", NULL, 0);

    /*
     * Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
     *  #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
     *  #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
     */
    rc = aws_iot_shadow_set_autoreconnect_status(&iotCoreClient, true);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d, aborting...", rc);
        abort();
    }

    // register delta callback for LampOFFActuator
    rc = aws_iot_shadow_register_delta(&iotCoreClient, &LampOFFActuator);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "Shadow Register Delta Error");
    }

    // loop and publish changes
    while(NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
        rc = aws_iot_shadow_yield(&iotCoreClient, 200);
        if(NETWORK_ATTEMPTING_RECONNECT == rc || shadowUpdateInProgress) {
            rc = aws_iot_shadow_yield(&iotCoreClient, 1000);
            // If the client is attempting to reconnect, or already waiting on a shadow update,
            // we will skip the rest of the loop.
            continue;
        }

        //ESP_LOGI(TAG, "*****************************************************************************************");
        //ESP_LOGI(TAG, "On Device: bathroomAvailable %s", bathroomAvailable ? "true" : "false");
        //ESP_LOGI(TAG, "On Device: bathroomOccupied %s", bathroomOccupied ? "true" : "false");
        //ESP_LOGI(TAG, "On Device: bathroomSanitization %s", bathroomSanitization ? "true" : "false");

        rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
        if(SUCCESS == rc) {
            rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 4,
                                             &bathroomAvailableHandler, &bathroomOccupiedHandler, &bathroomSanitizationHandler, &LampOFFActuator);
            if(SUCCESS == rc) {
                rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
                if(SUCCESS == rc) {
                    ESP_LOGI(TAG, "Update Shadow: %s", JsonDocumentBuffer);
                    rc = aws_iot_shadow_update(&iotCoreClient, client_id, JsonDocumentBuffer,
                                               ShadowUpdateStatusCallback, NULL, 4, true);
                    shadowUpdateInProgress = true;
                }
            }
        }
        //ESP_LOGI(TAG, "*****************************************************************************************");
        //ESP_LOGI(TAG, "Stack remaining for task '%s' is %d bytes", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL));
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "An error occurred in the loop %d", rc);
    }

    ESP_LOGI(TAG, "Disconnecting");
    rc = aws_iot_shadow_disconnect(&iotCoreClient);

    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "Disconnect error %d", rc);
    }

    vTaskDelete(NULL);
}


/******************************************************
 * This function reads the GPIO_PIR pin. According to 
 * the values stored in the three variables bathroomAvailable, 
 * bathroomOccupied and bathroomSanitization, the function 
 * decides whether to indicate the bathroom as free, 
 * occupied or in sanitization and activates or deactivates 
 * the UVC lamps via the GPIO_LAMP pin.
 * 
 * The countLamp variable defines the duration of the sinification.
 * The delay is 100ms so the timeout of the sanitization will be 
 * countLamp * 100ms (800*100ms).
 
 * If during the sinification the IR sensor is activated, the sanitization is interrupted 
 * and the device goes into occupied bathroom mode.
 * ***************************************************/
void pir_read_task(){
    bool readPIN = 0;
    uint8_t countON = COUNTON_VALUE;
    uint8_t countOFF = COUNTOFF_VALUE;

    for(;;){
        readPIN = Core2ForAWS_Port_Read(GPIO_PIR);
        if(readPIN == 1) 
            {
            Core2ForAWS_LED_Enable(1);
            //ESP_LOGI(TAG, "Sensor plugged in == 1 (yes)");
            }
        else
            {
            Core2ForAWS_LED_Enable(0);
            //ESP_LOGI(TAG, "Sensor plugged in == 0 (no)");
            } 

        if((bathroomAvailable == true) && (bathroomOccupied == false) && (bathroomSanitization == false))
            {
            if(readPIN == 1)
                {
                if(countON == 0)
                    {
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0xff00000);    // Red
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0xff0000);
                    Core2ForAWS_Sk6812_Show ();
                    bathroomAvailable = false;
                    bathroomOccupied = true;
                    bathroomSanitization = false;
                    countON = COUNTON_VALUE;
                    ui_textarea_add("\nBathroom Occupied!\n", NULL, 0);
                    ESP_LOGI(TAG, "bathroom Occupied ------------------------------------------------");
                    }    
                else 
                    {
                    countON--;
                    //ESP_LOGI(TAG, "countON = %d", countON);
                    }
                }
            else countON = COUNTON_VALUE;
            }
        else if((bathroomAvailable == false) && (bathroomOccupied == true) && (bathroomSanitization == false))
            {
            if(readPIN == 0)
                {
                if(countOFF == 0)
                    {
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0x0000ff);    // Blue
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0x0000ff);
                    Core2ForAWS_Sk6812_Show ();
                    bathroomAvailable = false;
                    bathroomOccupied = false;
                    bathroomSanitization = true;
                    countOFF = COUNTOFF_VALUE;
                    ui_textarea_add("\nBathroom Sanitization!\n", NULL, 0);
                    ESP_LOGI(TAG, "bathroom Sanitization ------------------------------------------------");
                    }    
                else 
                    {
                    countOFF--;
                    //ESP_LOGI(TAG, "countOFF = %d", countOFF);
                    }
                }
            else countOFF = COUNTOFF_VALUE;
            }
        else if((bathroomAvailable == false) && (bathroomOccupied == false) && (bathroomSanitization == true))
            {
            if(readPIN == 1)
                {
                if(writePINOK == 1) Core2ForAWS_Port_Write(GPIO_LAMP, 0); // Lamp OFF -----------------------------------------
                Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0xff00000);    // Red
                Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0xff0000);
                Core2ForAWS_Sk6812_Show ();
                
                bathroomAvailable = false;
                bathroomOccupied = true;
                bathroomSanitization = false;
                countLamp = COUNTLAMP_VALUE;
                ESP_LOGI(TAG, "LAMP OFF  ------------------------------------------------");
                ui_textarea_add("\nBathroom Occupied!\n", NULL, 0);                
                ESP_LOGI(TAG, "Bathroom Occupied! ------------------------------------------------");
                }
            else 
                {
                if(writePINOK == 1) Core2ForAWS_Port_Write(GPIO_LAMP, 1);   // Lamp ON -----------------------------------------
                if(countLamp == 0)
                    { // Timeout Lamp
                    if(writePINOK == 1) Core2ForAWS_Port_Write(GPIO_LAMP, 0); // Lamp OFF -----------------------------------------
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0x00ff00);    // Green
                    Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0x00ff00);
                    Core2ForAWS_Sk6812_Show ();
                    bathroomAvailable = true;
                    bathroomOccupied = false;
                    bathroomSanitization = false;
                    countLamp = COUNTLAMP_VALUE;
                    ui_textarea_add("\nBathroom Available!\n", NULL, 0);
                    ESP_LOGI(TAG, "bathroom Available ------------------------------------------------");
                    }
                else 
                    {
                    countLamp--;
                    ESP_LOGI(TAG, "countLamp = %d", countLamp);
                    }
                }
            }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}


/******************************************************
 * This function reads the 6-axis Inertial Measurement
 * Unit (IMU). If the acceleration on the y axis is higher 
 * than the value stored in the sensibility variable and 
 * the sanitization is active, then the sanitization is 
 * deactivated via the GPIO_LAMP pin and the device switches 
 * to bathroom occupied mode.
 * ***************************************************/
static void accel_task(void* pvParameters)
    {
    float accel_x = 0.00;
    float accel_y = 0.00;
    float accel_z = 0.00;
    float sensibility = 0.15;

    for(;;)
        {
        MPU6886_GetAccelData(&accel_x, &accel_y, &accel_z);
        if(accel_z > sensibility)
            {
            ESP_LOGI(TAG, "Porta aperta! | X: %.2f -- Y; %.2f -- Z: %.2f", accel_x, accel_y, accel_z);
            if((bathroomAvailable == false) && (bathroomOccupied == false) && (bathroomSanitization == true))
                {
                if(writePINOK == 1) Core2ForAWS_Port_Write(GPIO_LAMP, 0); // Lamp OFF -----------------------------------------
                Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_LEFT , 0xff00000);    // Red
                Core2ForAWS_Sk6812_SetSideColor ( SK6812_SIDE_RIGHT , 0xff0000);
                Core2ForAWS_Sk6812_Show ();
                
                bathroomAvailable = false;
                bathroomOccupied = true;
                bathroomSanitization = false;
                countLamp = COUNTLAMP_VALUE;
                ESP_LOGI(TAG, "LAMP OFF  ------------------------------------------------");
                ui_textarea_add("\nBathroom: Door is open!\n", NULL, 0);
                ui_textarea_add("\nBathroom Occupied!\n", NULL, 0);   
                }
            }
        vTaskDelay(pdMS_TO_TICKS(100));
        }
    vTaskDelete(NULL); /* Should never get to here... */
    }


void app_main()
    {  
    esp_err_t err;

    Core2ForAWS_Init();
    Core2ForAWS_Display_SetBrightness(80);
    Core2ForAWS_LED_Enable(0);
    Core2ForAWS_Sk6812_Init();
    
    ui_init();
    initialise_wifi();

    Core2ForAWS_Sk6812_SetSideColor (SK6812_SIDE_LEFT , 0x00ff00);     // Green
    Core2ForAWS_Sk6812_SetSideColor (SK6812_SIDE_RIGHT , 0x00ff00);    // Green
    Core2ForAWS_Sk6812_Show();

    err = Core2ForAWS_Port_PinMode(GPIO_PIR, INPUT);
    ESP_LOGI( TAG , "Return value GPIO_NUM_%d: %d ----------------------------------------\n", GPIO_PIR, err);

    err = Core2ForAWS_Port_PinMode(GPIO_LAMP, OUTPUT);
    ESP_LOGI( TAG , "Return value GPIO_NUM_%d: %d ----------------------------------------\n", GPIO_LAMP, err);
    if(err == ESP_OK)
        {
        writePINOK = 1;
        Core2ForAWS_Port_Write(GPIO_LAMP, 0); // Lamp OFF -----------------------------------------
        ui_textarea_add("\nGPIO Lamp OK!\n", NULL, 0);
        }
    else ui_textarea_add("\nGPIO Lamp KO!\n", NULL, 0);

    ui_textarea_add("\nBathroom Available!\n", NULL, 0);
    ESP_LOGI(TAG, "bathroom Available ------------------------------------------------");

    xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 4096*2, NULL, 5, NULL, 1);

    xTaskCreatePinnedToCore(&pir_read_task, "pir_read_task" , 1024*4, NULL, 2, NULL, 1);

    xTaskCreatePinnedToCore(&accel_task, "accel_task" , 1024*4, NULL, 1, NULL, 1);
    }

IoT Events - Inputs

JSON
IoT Events - Inputs
{
  "current": {
    "state": {
      "reported": {
        "bathroomAvailable": true,
        "bathroomOccupied": false,
        "bathroomSanitization": false,
        "LampOFF": true
      }
    },
    "version": 13
  },
  "timestamp": 1606282489
}

SanitizationModel

JSON
AWS IoT Events - Detector Model
{
    "detectorModelDefinition": {
        "states": [
            {
                "stateName": "BathroomAvailable",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "StartOccupied",
                            "condition": "!$input.Sanitizing.current.state.reported.bathroomAvailable && $input.Sanitizing.current.state.reported.bathroomOccupied && !$input.Sanitizing.current.state.reported.bathroomSanitization",
                            "actions": [],
                            "nextState": "BathroomOccupied"
                        }
                    ]
                },
                "onEnter": {
                    "events": []
                },
                "onExit": {
                    "events": []
                }
            },
            {
                "stateName": "BathroomOccupied",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "StartSanitization",
                            "condition": "!$input.Sanitizing.current.state.reported.bathroomAvailable && !$input.Sanitizing.current.state.reported.bathroomOccupied && $input.Sanitizing.current.state.reported.bathroomSanitization",
                            "actions": [],
                            "nextState": "BathroomSanitization"
                        }
                    ]
                },
                "onEnter": {
                    "events": []
                },
                "onExit": {
                    "events": []
                }
            },
            {
                "stateName": "BathroomSanitization",
                "onInput": {
                    "events": [],
                    "transitionEvents": [
                        {
                            "eventName": "reStartOccupied",
                            "condition": "!$input.Sanitizing.current.state.reported.bathroomAvailable && $input.Sanitizing.current.state.reported.bathroomOccupied && !$input.Sanitizing.current.state.reported.bathroomSanitization",
                            "actions": [],
                            "nextState": "BathroomOccupied"
                        },
                        {
                            "eventName": "Timeout",
                            "condition": "timeout(\"SanTimer\")",
                            "actions": [
                                {
                                    "iotTopicPublish": {
                                        "mqttTopic": "'$aws/things/CLIENT_ID/shadow/update/delta'",
                                        "payload": {
                                            "contentExpression": "'{\"state\": {\"desired\": {\"LampOFF\": true}}}'",
                                            "type": "JSON"
                                        }
                                    }
                                }
                            ],
                            "nextState": "Transition"
                        }
                    ]
                },
                "onEnter": {
                    "events": [
                        {
                            "eventName": "TimerSanitization",
                            "condition": "true",
                            "actions": [
                                {
                                    "setTimer": {
                                        "timerName": "SanTimer",
                                        "seconds": 60,
                                        "durationExpression": null
                                    }
                                }
                            ]
                        }
                    ]
                },
                "onExit": {
                    "events": []
                }
            },
            {
                "stateName": "Transition",
                "onInput": {
                    "events": [
                        {
                            "eventName": "LampOFF",
                            "condition": "true",
                            "actions": [
                                {
                                    "iotTopicPublish": {
                                        "mqttTopic": "'$aws/things/CLIENT_ID/shadow/update/delta'",
                                        "payload": {
                                            "contentExpression": "'{\"state\": {\"desired\": {\"LampOFF\": true}}}'",
                                            "type": "JSON"
                                        }
                                    }
                                }
                            ]
                        }
                    ],
                    "transitionEvents": [
                        {
                            "eventName": "StartAvailable",
                            "condition": "$input.Sanitizing.current.state.reported.bathroomAvailable && !$input.Sanitizing.current.state.reported.bathroomOccupied && !$input.Sanitizing.current.state.reported.bathroomSanitization",
                            "actions": [
                                {
                                    "clearTimer": {
                                        "timerName": "TimeOutTimer"
                                    }
                                }
                            ],
                            "nextState": "BathroomAvailable"
                        }
                    ]
                },
                "onEnter": {
                    "events": []
                },
                "onExit": {
                    "events": []
                }
            }
        ],
        "initialStateName": "BathroomAvailable"
    },
    "detectorModelDescription": null,
    "detectorModelName": "SanitizationModel",
    "evaluationMethod": "BATCH",
    "key": null,
    "roleArn": "xxxxxxxxxxxxxxxxxxxxxxxxxxxx/AWS_IoTEvents_HelloWorld_ActionRole"
}

Credits

Mario Soranno

Mario Soranno

9 projects • 24 followers
I have a Bachelor's Degree in Industrial Engineering - Electronics. I am an expert in hardware design, I can program in C/C++,Python and ROS

Comments