MQTT topic and message description :
Kit have two Capsense button. I used that as two switches.
Capsense 1 --> Topic : cap1 --> Message : TURNON/TURNOFF
Capsense 2 --> Topic : cap2 --> Message : TURNON/TURNOFF
Flow Chart:
Our module code is designed to handle all user operations to control home electronics appliances using our smart home automation system. The system offers four modes of operation:
- Touch: The Cypress capacitive touch technology senses user touch input and reacts based on the last state of the relay value.
- Voice Command: Alexa publishes MQTT messages, which our ESP module subscribes to receive. I2C communication is used between the Cypress chip and the ESP8266 to enable voice command operation.
- IR Remote: Our ESP8266 decodes user input button commands and sends them to the Cypress chip using I2C communication. The Cypress chip reacts based on the input command.
- Smartphone: The user's smartphone can publish MQTT messages, which our ESP module subscribes to receive. I2C communication is used between the Cypress chip and the ESP8266. Based on the received command, the Cypress chip reacts and handles the relay.
Our module code allows for seamless integration of these four modes, offering users flexibility and convenience in controlling their home electronics appliances.
CypressCode:
1. To import C libraries in your code, you need to include their header files using the #include preprocessor directive. This allows you to use functions and data types from the library in your program.
#include "project.h" #include "stdlib.h" #include "cyapicallbacks.h"
2. The code snippet you provided consists of four C function prototypes. These are:
void updateLoad(void); void loadWrite(uint8,uint8); void HandleError(void); void i2cReceive(void);
- void updateLoad(void): A function that updates the load status of a device.
- void loadWrite(uint8, uint8): A function that writes a value to a specific load.
- void HandleError(void): A function that handles errors that may occur during program execution.
- void i2cReceive(void): A function that receives data via the I2C communication protocol.
These function prototypes define the function name, return type, and parameters (if any) that the function accepts. They are often used as a way to declare functions before they are implemented or used in a program, helping to ensure that the function is properly defined and its usage is correct.
3. The code snippet you provided defines two preprocessor directives using the #define keyword.
#define LightloadNumber 4 #define FanLoadNumber 1
- #define LightloadNumber 4 defines a preprocessor macro with the name LightloadNumber and a value of 4. This macro can be used in the code to represent the number of light loads that can be controlled by the program.
- #define FanLoadNumber 1 defines a preprocessor macro with the name FanLoadNumber and a value of 1. This macro can be used in the code to represent the number of fan loads that can be controlled by the program.
These preprocessor directives help to make the code more readable and maintainable by defining values that are used in multiple places throughout the program in one central location. Anytime the program needs to refer to the number of light or fan loads, it can use these macros instead of hardcoding the values, which makes the code more flexible and easier to modify in the future.
4. These lines are declaring and initializing various arrays and variables that will be used in the program for controlling the smart home automation system.
uint8 state_switch[LightloadNumber]; //status of touch switch uint8 pre_switch[LightloadNumber]; //previous status of touch switch uint8 state_load[LightloadNumber]; //status of load uint8 state[LightloadNumber + FanLoadNumber + 1]; //state for communication uint8 pre_state[LightloadNumber + FanLoadNumber + 1]; //state for communication uint8 state_Fswitch[FanLoadNumber]; //status of fan switch uint8 pre_Fswitch[FanLoadNumber]; //previous status of fan switch uint8 fan_state[2];uint8 state_Fan[FanLoadNumber]; //status of fan regulator uint8 Switch[] = {0,1,2,3}; // touch swich for light load(cap sense button 0,1,2,3) uint8 Load[] = {0,1,2,3}; //load connection for switch (L0,L1,L2,L3)(relay) uint8 F_UP_DWN[2] = {5,4}; //fan up and down touch switch(cap sense button 5,6) uint8 Fan[4] = {7,6,5,4}; //fan output connection(L4,L5,L6,L7) uint8 Fan_led[5] = {12,11,10,9,8}; // fan speed indicator led(L8,L9,L10,L11,L12) uint8 white_led_load[] = {13,14,15,16}; //white led for each load(L13,L14,L15,L16) uint8 Fan_UDW[2] = {18,17}; //fan up down white led uint8 Fan_UDB[2] = {22,21}; //fan up down blue led //smd button down /* uint8 F_switch[] = {6}; //fan touch switch (cap sense button 4) uint8 Fan_BW[2] = {20,19}; //fan blue and white led uint8 Scenebut = {7}; //touch switch for smd pad(cap sense button 7) uint8 scene_BW[2] = {23,24}; //smd switch up down blue led */ // smd button up uint8 F_switch[] = {7}; //fan touch switch (cap sense button 4) uint8 Fan_BW[2] = {24,23}; //fan blue and white led uint8 Scenebut = {6}; //touch switch for smd pad(cap sense button 7) uint8 scene_BW[2] = {19,20}; //smd switch up down blue led uint8 ScenebutStatus = 0;uint8 pre_ScenebutStatus = 0; uint8 whiteLed = 1; //status of activation of white led of all loads//i2c uint8 i2cReadBuffer[(LightloadNumber + FanLoadNumber + 1)]; uint8 i2cWriteBuffer[(LightloadNumber + FanLoadNumber + 1)]; uint8 I2CFlag = 0u; uint8 sceneled = 0; uint8 speed = 0; int onOffFlag = 0; uint8 flag = 0;
- The arrays state_switch, pre_switch, state_load, and state_Fswitch are used to keep track of the current and previous status of the touch switches and fan switch.
- The array state and pre_state are used for communication between the modules.
- The arrays Switch, Load, F_UP_DWN, Fan, Fan_led, white_led_load, Fan_UDW, and Fan_UDB are used to define the connections for the touch switches, loads, fan, fan speed indicator led, white led for each load, fan up down white led, and fan up down blue led respectively.
- The variable ScenebutStatus keeps track of the status of the touch switch for the smd pad.
- The arrays i2cReadBuffer and i2cWriteBuffer are used for communication over I2C.
- The variables scene led, speed, onOffFlag, and flag are used for controlling the system.
5. A callback function:
void I2C_I2C_ISR_ExitCallback() { I2CFlag = 1; }
A callback function that is executed when the I2C (Inter-Integrated Circuit) module finishes sending or receiving data. Specifically, it is called when the I2C interrupt is triggered and signals that the I2C communication has completed.
In this particular code, the function sets a flag variable called I2CFlag to 1, indicating that the I2C communication has finished. This flag can be used by other parts of the code to determine when to take further action based on the results of the I2C communication.
6. The code that controls loads (lights and fans) using CapSense touch sensors and an I2C interface.
int main(void)
{
memset(state_switch,0,sizeof(state_switch));
memset(pre_switch,0,sizeof(pre_switch));
memset(state,0,sizeof(state));
memset(state_load,0,sizeof(state_load));
memset(pre_state,0,sizeof(pre_state));
memset(state_Fswitch,0,sizeof(state_Fswitch));
memset(pre_Fswitch,0,sizeof(pre_Fswitch));
memset(fan_state,0,sizeof(fan_state));
memset(i2cReadBuffer,0,sizeof(i2cReadBuffer));
L13_Write(whiteLed);
L14_Write(whiteLed);
L15_Write(whiteLed);
L16_Write(whiteLed);
L17_Write(whiteLed);
L18_Write(whiteLed);
L19_Write(whiteLed);
L23_Write(whiteLed);
I2C_I2CSlaveInitReadBuf(i2cReadBuffer, (LightloadNumber + FanLoadNumber + 1));
I2C_I2CSlaveInitWriteBuf(i2cWriteBuffer, (LightloadNumber + FanLoadNumber + 1));
I2C_I2C_ISR_ExitCallback();
CyGlobalIntEnable;
CySysWdtWriteMode(CY_SYS_WDT_COUNTER1, CY_SYS_WDT_MODE_RESET);
CySysWdtWriteMatch(CY_SYS_WDT_COUNTER1, 0xFA00);
CySysWdtWriteClearOnMatch(CY_SYS_WDT_COUNTER1, 1u);
CySysWdtEnable(CY_SYS_WDT_COUNTER1_MASK);
CapSense_1_Start();
CapSense_1_InitializeAllBaselines();
I2C_Start();
for(;;)
{
if(0u == CapSense_1_IsBusy()){
/* Update all baselines */
CapSense_1_ProcessAllWidgets();
/* Start scanning all enabled sensors */
CapSense_1_ScanAllWidgets();
}
ScenebutStatus = CapSense_1_IsWidgetActive(Scenebut);
if(ScenebutStatus != pre_ScenebutStatus){
if(ScenebutStatus != 0 && onOffFlag == 0){
onOffFlag = 1;
for(int i = 0; i < LightloadNumber+FanLoadNumber; i++){
if(i<LightloadNumber)
loadWrite(Load[i],0);
state[i] = 0;
}
loadWrite(Fan_BW[0],0);
if(whiteLed == 1){
for(int i = 0; i < LightloadNumber; i++){
loadWrite(white_led_load[i],1);
}
loadWrite(Fan_BW[1],1);
}
}
else if(ScenebutStatus != 0 && onOffFlag == 1){
onOffFlag = 0;
for(int i = 0; i < LightloadNumber+FanLoadNumber; i++){
if(i<LightloadNumber)
loadWrite(Load[i],1);
state[i] = 1;
}
loadWrite(Fan_BW[0],1);
if(whiteLed == 1){
for(int i = 0; i < LightloadNumber; i++){
loadWrite(white_led_load[i],0);
}
loadWrite(Fan_BW[1],0);
}
}
pre_ScenebutStatus = ScenebutStatus;
}
if(state[0] != 1 && state[1] != 1 && state[2] != 1 && state[3] != 1 && state[4] != 1){
onOffFlag = 1;
}
else {
onOffFlag = 0;
}
if(state[0] == 1 && state[1] == 1 && state[2] == 1 && state[3] == 1 && state[4] == 1){
if(whiteLed == 1)
loadWrite(scene_BW[0],0);
loadWrite(scene_BW[1],1);
}
else {
if(whiteLed == 1)
loadWrite(scene_BW[0],1);
loadWrite(scene_BW[1],0);
}
for(uint8 i = 0 ; i < LightloadNumber ; i++){
state_switch[i] = CapSense_1_IsWidgetActive(Switch[i]);
if(state_switch[i] != pre_switch[i]){
if(state_switch[i] != 0){
if(state[i] != 0)
state_load[i] = 0;
else
state_load[i] = 1;
loadWrite(Load[i],state_load[i]);
state[i] = state_load[i] ? 1 : 0;
if(whiteLed == 1)
loadWrite(white_led_load[i],!(state_load[i]));
}
pre_switch[i] = state_switch[i];
}
}
state_Fswitch[0] = CapSense_1_IsWidgetActive(F_switch[0]);
if(state_Fswitch[0] != pre_Fswitch[0]){
if(state_Fswitch[0] != 0){
if(state[4] != 0)
state_Fan[0] = 0;
else
state_Fan[0] = 1;
loadWrite(Fan_BW[0],state_Fan[0]);
state[4] = state_Fan[0] ? 1 : 0;
if(whiteLed == 1)
loadWrite(Fan_BW[1],!(state_Fan[0]));
for (uint8 i = 0; i < 4; i++)
loadWrite(Fan[i], 0);
if(state[4] == 1){
if(speed == 1){
loadWrite(Fan[1], 1);
}
else if(speed == 2){
loadWrite(Fan[2], 1);
}
else if(speed == 3){
loadWrite(Fan[0], 1);
loadWrite(Fan[2], 1);
}
else if(speed == 4){
loadWrite(Fan[1], 1);
loadWrite(Fan[2], 1);
}
else if (speed == 5){
loadWrite(Fan[3], 1);
}
}
else if(state[4] == 0){
for (uint8 i = 0; i < 4; i++)
loadWrite(Fan[i], 0);
}
}
pre_Fswitch[0] = state_Fswitch[0];
}
if(CapSense_1_IsWidgetActive(F_UP_DWN[0]) != fan_state[0]){
if(CapSense_1_IsWidgetActive(F_UP_DWN[0]) != 0){
if(speed != 5)
speed++; //fan state[3] increase by 1
else
speed = 0;
fan_state[0] = !(fan_state[0]);
loadWrite(Fan_UDW[0],0); // fan up white led off
loadWrite(Fan_UDB[0],1); //fan up blue led on
}
else{
loadWrite(Fan_UDB[0],0); //fan up blue led off
if(whiteLed == 1)
loadWrite(Fan_UDW[0],1); //fan up white led off
}
fan_state[0] = (CapSense_1_IsWidgetActive(F_UP_DWN[0]));
}
if(CapSense_1_IsWidgetActive(F_UP_DWN[1]) != fan_state[1]){ //check if fan down touch pad is pressed
if(CapSense_1_IsWidgetActive(F_UP_DWN[1]) != 0){
if(speed != 0)
speed--; //fan state[3] decrease by 1
else
speed = 5;
fan_state[1] = !(fan_state[1]);
loadWrite(Fan_UDW[1],0);
loadWrite(Fan_UDB[1],1);
}
else{
loadWrite(Fan_UDB[1],0);
if(whiteLed == 1)
loadWrite(Fan_UDW[1],1);
}
fan_state[1] = (CapSense_1_IsWidgetActive(F_UP_DWN[1]));
}
if(speed == 0){
state[5] = 0;
for(int i = 0;i<5;i++){
loadWrite(Fan_led[i],0);
}
}
else if(speed == 1){
state[5] = 1;
loadWrite(Fan_led[0],1);
for(int i = 1;i<5;i++){
loadWrite(Fan_led[i],0);
}
}
else if(speed == 2){
state[5] = 2;
for(int i = 0;i<2;i++){
loadWrite(Fan_led[i],1);
}
for(int i = 2;i<5;i++){
loadWrite(Fan_led[i],0);
}
}
else if(speed == 3){
state[5] = 3;
for(int i = 0;i<3;i++){
loadWrite(Fan_led[i],1);
}
for(int i = 3;i<5;i++){
loadWrite(Fan_led[i],0);
}
}
else if(speed == 4){
state[5] = 4;
for(int i = 0;i<4;i++){
loadWrite(Fan_led[i],1);
}
loadWrite(Fan_led[4],0);
}
else if(speed == 5){
state[5] = 5;
for(int i = 0;i<5;i++){
loadWrite(Fan_led[i],1);
}
}
if(state[5] != pre_state[5]){
for (uint8 i = 0; i < 4; i++)
loadWrite(Fan[i], 0);
if(state[4] == 1){
if(speed == 1){
loadWrite(Fan[1], 1);
}
else if(speed == 2){
loadWrite(Fan[2], 1);
}
else if(speed == 3){
loadWrite(Fan[0], 1);
loadWrite(Fan[2], 1);
}
else if(speed == 4){
loadWrite(Fan[1], 1);
loadWrite(Fan[2], 1);
}
else if (speed == 5){
loadWrite(Fan[3], 1);
}
}
//pre_state[5] = state[5];
}
if(I2CFlag != 0)
{
I2CFlag = 0;
if (0u != (I2C_I2C_SSTAT_WR_CMPLT & I2C_I2CSlaveStatus()))
{
i2cReceive();
I2C_I2CSlaveClearWriteBuf();
(void) I2C_I2CSlaveClearWriteStatus();
}
if(0u != (I2C_I2C_SSTAT_RD_CMPLT & I2C_I2CSlaveStatus()))
{
I2C_I2CSlaveClearReadBuf();
(void) I2C_I2CSlaveClearReadStatus();
}
}
for(uint8 i = 0 ; i < LightloadNumber + FanLoadNumber + 1; i++){
if(state[i] != pre_state[i]){
if((I2C_I2C_SSTAT_RD_BUSY & I2C_I2CSlaveStatus()) == 0){
pre_state[i] = state[i];
i2cReadBuffer[i] = state[i];
}
}
}
CySysWatchdogFeed(CY_SYS_WDT_COUNTER1);
}
}
The program initializes the various memory locations to zero and sets the state of the loads to zero. It then initializes and enables the Watchdog Timer, CapSense module, and I2C interface.
In the main loop, the program scans all enabled sensors and checks the status of the Scene button. If the Scene button is pressed, the program turns on/off all the loads depending on their previous state. If all loads are on, the program turns on the "All off" button and turns off the "All on" button, and vice versa.
The program then checks the status of the touch sensors for each load and sets the state of the loads accordingly. It also checks the status of the Fan switch and sets the state of the Fan load accordingly. If the white LED is on, the program sets the state of the white LED load accordingly.
The program also sets the various memory locations to their respective values in order to ensure proper functioning. The program then repeats this loop continuously.
7. This is a function that receives data over I2C communication and updates the states of various loads connected to the microcontroller accordingly.
void i2cReceive(void){
for (uint8 i = 0; i < LightloadNumber; i++) {
state[i] = i2cWriteBuffer[i];
if (state[i] == 0) {
loadWrite(Load[i],0);
if(whiteLed == 1)
loadWrite(white_led_load[i],1);
}
else if (state[i] == 1) {
loadWrite(Load[i], 1);
loadWrite(white_led_load[i],0);
}
}
state[4] = i2cWriteBuffer[4];
if(state[4] != 0)
state_Fan[0] = 0;
else
state_Fan[0] = 1;
loadWrite(Fan_BW[0],!state_Fan[0]);
loadWrite(Fan_BW[1],(state_Fan[0]));
state[5] = i2cWriteBuffer[5];
speed = i2cWriteBuffer[5];
for (uint8 i = 0; i < 4; i++)
loadWrite(Fan[i], 0);
if(state[4] == 1){
if(speed == 1){
loadWrite(Fan[1], 1);
}
else if(speed == 2){
loadWrite(Fan[2], 1);
}
else if(speed == 3){
loadWrite(Fan[0], 1);
loadWrite(Fan[2], 1);
}
else if(speed == 4){
loadWrite(Fan[1], 1);
loadWrite(Fan[2], 1);
}
else if (speed == 5){
loadWrite(Fan[3], 1);
}
}
}
The function starts by iterating through a for loop that goes up to a value defined by the macro LightloadNumber. For each iteration, the state of a particular load is updated with the corresponding value received over I2C communication. If the state is zero, the corresponding load is turned off, and if the whiteLed variable is set to one, the white LED load is turned on. If the state is one, the corresponding load is turned on, and the white LED load is turned off.
After the loop, the state of the Fan load is updated based on the value received over I2C communication at index 4 of the i2cWriteBuffer array. If this value is zero, then the Fan load is turned on, and if it is one, the Fan load is turned off. The state of the Fan is then used to set the state of two other loads (Fan_BW[0] and Fan_BW[1]) using bitwise NOT and bitwise AND operations.
Finally, the speed of the Fan load is updated based on the value received over I2C communication at index 5 of the i2cWriteBuffer array. Depending on the value of the speed, different combinations of loads (Fan[0] to Fan[3]) are turned on or off.
8. Function loadWrite
void loadWrite(uint8 loadpin,uint8 state){
switch(loadpin){
case 0:
L0_Write(state);
break;
case 1:
L1_Write(state);
break;
case 2:
L2_Write(state);
break;
case 3:
L3_Write(state);
break;
case 4:
L4_Write(state);
break;
case 5:
L5_Write(state);
break;
case 6:
L6_Write(state);
break;
case 7:
L7_Write(state);
break;
case 8:
L8_Write(state);
break;
case 9:
L9_Write(state);
break;
case 10:
L10_Write(state);
break;
case 11:
L11_Write(state);
break;
case 12:
L12_Write(state);
break;
case 13:
L13_Write(state);
break;
case 14:
L14_Write(state);
break;
case 15:
L15_Write(state);
break;
case 16:
L16_Write(state);
break;
case 17:
L17_Write(state);
break;
case 18:
L18_Write(state);
break;
case 19:
L19_Write(state);
break;
case 20:
L20_Write(state);
break;
case 21:
L21_Write(state);
break;
case 22:
L22_Write(state);
break;
case 23:
L23_Write(state);
break;
case 24:
L24_Write(state);
break;
}
}
This function loadWrite is used to write a digital state (high or low) to a specific load pin. The function takes two arguments: the first argument loadpin is an integer that specifies the load pin number (ranging from 0 to 24), and the second argument state is an integer that specifies the state of the load pin (0 or 1, low or high).
The function uses a switch-case statement to determine which load pin to write to based on the value of loadpin. Each case corresponds to a specific load pin number and calls the appropriate function (e.g. L0_Write, L1_Write, etc.) to write the specified state to that load pin.
9. Function HandleError:
void HandleError(void)
{
/* Disable all interrupts. */
__disable_irq();
/* Infinite loop. */
while(1u) {}
}
The HandleError() function is used to handle errors in the firmware. It disables all interrupts and enters an infinite loop, effectively stopping the execution of the program. This function is typically called when a serious error is detected that cannot be recovered from, such as a hardware fault or a critical software error. By entering an infinite loop, the program is effectively halted, preventing any further damage or malfunction from occurring. This function is commonly used in safety-critical systems where the failure of the system could result in harm to people or damage to property.
Alexa and Google Home Development:
RequiredAccount:
1. AWS account (https://aws.amazon.com/)
2. Alexa Developer (https://developer.amazon.com/en-US/alexa)
3. Google Cloud Developer (https://console.cloud.google.com)
To develop an Amazon Alexa smart home skill, you can follow the steps provided in the video. Be sure to set up a rule that enables the Lambda function to read data from DynamoDB, which will give you the ability to display real-time switch statuses in both the Amazon Alexa and Google Home applications.