This shows you the differences between two versions of the page.
iothings:proiecte:2023:configurableindoorairqualitymonitoringsystem [2024/01/14 19:47] andrei.enescu0512 [4.1 MCU code] |
iothings:proiecte:2023:configurableindoorairqualitymonitoringsystem [2024/06/30 00:59] (current) andrei.enescu0512 [Configurable Indoor Air Quality Monitoring System] |
||
---|---|---|---|
Line 1: | Line 1: | ||
======Configurable Indoor Air Quality Monitoring System====== | ======Configurable Indoor Air Quality Monitoring System====== | ||
* Author: Andrei-George-Lucian ENESCU | * Author: Andrei-George-Lucian ENESCU | ||
- | * Email: <andrei.enescu0512@stud.acs.upb.ro> | + | * Email: <enescu.andrei23@gmail.com> |
- | * Master: AAC | + | * Master : AAC |
- | * Academic year: 2023-2024 | + | * Academic year : 2023-2024 |
- | * Source code: FIXME | + | * Source files : {{:iothings:proiecte:2023:enescu_andrei_iot_design_files.rar|download_design_files}} |
- | * Video: FIXME | + | * Project presentation : {{:iothings:proiecte:2023:enescu_andrei_iot_project_presentation.pdf|download_project_presentation}} |
+ | * Video : [[https://drive.google.com/file/d/12pxGG4WmBNYgOO-bVUk5fnq6-0USTvlY/view?usp=sharing|view_demo_video]] | ||
=====1. Introduction===== | =====1. Introduction===== | ||
- | The aim of this project is to create the infrastructure for an configurable indoor air quality monitoring system. The principle behind this idea is to have multiple devices that can be placed anywhere in an enclosed area. Depending on the user’s needs, the devices can be reconfigured accordingly to meet any demand, without reprogramming them. | + | The aim of this project is to create the infrastructure for a configurable indoor air quality monitoring system. The principle behind this idea is to have multiple devices that can be placed anywhere in an enclosed area. Depending on the user’s needs, the devices can be reconfigured accordingly to meet any demand, without reprogramming them. |
Each device is separated into 2 boards, the first one which has multiple sensors for monitoring the environment, and the second one which’s purpose is to acquire the data read by the previous board and send it to a server. | Each device is separated into 2 boards, the first one which has multiple sensors for monitoring the environment, and the second one which’s purpose is to acquire the data read by the previous board and send it to a server. | ||
The communication between the two boards will be done via a serial protocol. Being small and maneuverable, the device can be easily placed in | The communication between the two boards will be done via a serial protocol. Being small and maneuverable, the device can be easily placed in | ||
- | different parts of the room, and thus, it must be powered up by a battery. | + | different parts of the room, and thus, it must be powered up by a battery. The data acquired will be monitored using a custom web page. |
+ | |||
+ | Project structure: | ||
+ | |||
+ | |||
+ | {{:iothings:proiecte:2023:project_structure.jpeg?400|}} | ||
Line 179: | Line 185: | ||
- | The serial communication between the master and slave boards is implemented using the UART protocol, which runs at the 115200 baud rate, 8 bits, no parity. Any exchange of data between those two is started by the master board. At startup, the master will request the supported parameter list which can be monitored by the slave boards. Depending on the response received, different data commands will be send to the slave board. | + | The serial communication between the master and slave boards is implemented using the **UART protocol**, which runs at the 115200 baud rate, 8 bits, no parity. Any exchange of data between those two is started by the master board. At startup, the master will request the supported parameter list which can be monitored by the slave boards, and it will read and process the sensor data. The master will stop working if a timeout occurs ( the slave does not respond in 5 seconds ). |
The communication state machine can be seen in the image below: | The communication state machine can be seen in the image below: | ||
- | FIXME to add image | ||
- | The length of the commands sent by the master board is 2 bytes, and the responses from the slave boards 4 bytes. | + | {{:iothings:proiecte:2023:serial_comm_state_machine.jpeg?450|}} |
+ | |||
+ | Two commands are implemented, **UART_CMD_READ_SENSORS_STATUS** will read the configuration at startup, and the **UART_CMD_READ_SENSORS_DATA** will request the data from the sensors. The length of both commands is 2 bytes, the responses for the first and second one are 4 and 8, respectively. | ||
===4.1.1 ESP32 code=== | ===4.1.1 ESP32 code=== | ||
+ | |||
+ | The WiFi SSID and password, and the MQTT server IP are required to establish a connection to the MQTT broker | ||
+ | <code C> | ||
+ | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// WIFI SETUP | ||
+ | #include <WiFi.h> | ||
+ | #include <PubSubClient.h> | ||
+ | #include <Wire.h> | ||
+ | |||
+ | const char* ssid = "TO_BE_REPLACED"; // WiFi SSID | ||
+ | const char* password = "TO_BE_REPLACED"; // WiFi password | ||
+ | const char* mqtt_server = "TO_BE_REPLACED"; // MQTT server | ||
+ | |||
+ | WiFiClient espClient; | ||
+ | PubSubClient client( espClient ); | ||
+ | </code> | ||
+ | |||
+ | The functions used for WiFi: | ||
+ | <code C> | ||
+ | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// WIFI FUNCTIONS | ||
+ | // This functions connects your ESP8266 to your router | ||
+ | void setup_wifi() { | ||
+ | delay( 10 ); | ||
+ | Serial.println(); | ||
+ | Serial.print("Connecting to "); | ||
+ | Serial.println( ssid ); | ||
+ | Serial.print("Password used: "); | ||
+ | Serial.println( password ); | ||
+ | WiFi.mode( WIFI_STA ); | ||
+ | WiFi.begin( ssid, password ); | ||
+ | while( WiFi.status() != WL_CONNECTED ) | ||
+ | { | ||
+ | delay( 500 ); | ||
+ | Serial.print( "." ); | ||
+ | } | ||
+ | Serial.println(""); | ||
+ | Serial.print( "WiFi connected - ESP IP address: " ); | ||
+ | Serial.println( WiFi.localIP() ); | ||
+ | } | ||
+ | |||
+ | // This function is executed when some device publishes a message to a topic that your ESP8266 is subscribed to | ||
+ | // Change the function below to add logic to your program, so when a device publishes a message to a topic that | ||
+ | // your ESP8266 is subscribed you can actually do something | ||
+ | void callback( String topic, byte* message, unsigned int length ) | ||
+ | { | ||
+ | Serial.print( "Message arrived on topic: " ); | ||
+ | Serial.println( topic ); | ||
+ | } | ||
+ | |||
+ | // This functions reconnects your ESP8266 to your MQTT broker | ||
+ | // Change the function below if you want to subscribe to more topics with your ESP8266 | ||
+ | void reconnect() | ||
+ | { | ||
+ | while( !client.connected() ) | ||
+ | { | ||
+ | Serial.print( "Attempting MQTT connection..." ); | ||
+ | if( client.connect( "ESP8266Client" ) ) | ||
+ | { | ||
+ | Serial.println( "connected" ); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | Serial.print( "failed, rc=" ); | ||
+ | Serial.print( client.state() ); | ||
+ | Serial.println( " try again in 5 seconds" ); | ||
+ | delay( 5000 ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | The serial communication can be configured by modifying the macros below: | ||
+ | <code C> | ||
+ | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SERIAL COMM SETUP | ||
+ | // general macros | ||
+ | #define TRUE true | ||
+ | #define FALSE false | ||
+ | |||
+ | #define SERIAL_1_BAUDRATE 115200 | ||
+ | #define SERIAL_2_BAUDRATE 115200 | ||
+ | |||
+ | #define ESP_MASTER_RX_PIN 15 | ||
+ | #define ESP_MASTER_TX_PIN 2 | ||
+ | |||
+ | #define UART_CHECK_COUNTER_MAX 10 | ||
+ | #define UART_TIMEOUT_COUNTER_MAX 50 | ||
+ | |||
+ | #define UART_END_BYTE 0x55 | ||
+ | |||
+ | // command list | ||
+ | #define UART_CMD_READ_SENSORS_STATUS 0x10 | ||
+ | #define UART_CMD_READ_SENSORS_DATA 0x20 | ||
+ | |||
+ | // flags pos | ||
+ | #define SENSOR_TEMP_SUPPORTED 0x01 | ||
+ | #define SENSOR_TVOC_SUPPORTED 0x02 | ||
+ | #define SENSOR_SOUND_SUPPORTED 0x04 | ||
+ | |||
+ | #define UART_REQUEST_CMD_MAX_LENGTH 2 | ||
+ | #define UART_RESPONSE_READ_DATA_MAX_LENGTH 8 | ||
+ | #define UART_RESPONSE_INIT_CMD_MAX_LENGTH 4 | ||
+ | |||
+ | #define UART_READ_BUFFER_LENGTH 10 | ||
+ | #define UART_WRITE_BUFFER_LENGTH 5 | ||
+ | |||
+ | // sensor flag position | ||
+ | #define SENSOR_TEMP_SUPPORTED 0x01 | ||
+ | #define SENSOR_TVOC_SUPPORTED 0x02 | ||
+ | #define SENSOR_SOUND_SUPPORTED 0x04 | ||
+ | |||
+ | // UART flags structure | ||
+ | typedef union | ||
+ | { | ||
+ | struct{ | ||
+ | uint8_t is_busy :1, | ||
+ | sensor_temp_supported :1, | ||
+ | sensor_tvoc_supported :1, | ||
+ | sensor_sound_supported :1, | ||
+ | :4; | ||
+ | }; | ||
+ | |||
+ | uint8_t word8; | ||
+ | }UART_COM_FLAGS; | ||
+ | |||
+ | // UART main structure | ||
+ | typedef struct | ||
+ | { | ||
+ | uint8_t write_buffer[UART_WRITE_BUFFER_LENGTH]; | ||
+ | uint8_t read_buffer[UART_READ_BUFFER_LENGTH]; | ||
+ | uint8_t buffer_counter; | ||
+ | |||
+ | uint8_t check_counter; | ||
+ | uint8_t timeout_counter; | ||
+ | |||
+ | UART_COM_FLAGS flags; | ||
+ | }UART_COM_STRUCT; | ||
+ | |||
+ | UART_COM_STRUCT UART_com; | ||
+ | </code> | ||
+ | |||
+ | The starting configuration of the serial protocol is described below. When the function is called, it will write the starting command **UART_CMD_READ_SENSORS_STATUS** to read the slave capabilities. If no response is received, the master board will stop working. | ||
<code C> | <code C> | ||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SETUP FUNCTION | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SETUP FUNCTION | ||
+ | void init_com_protocol_UART() | ||
+ | { | ||
+ | UART_com.flags.word8 = 0x00; | ||
+ | UART_com.flags.is_busy = TRUE; | ||
+ | UART_com.timeout_counter = UART_TIMEOUT_COUNTER_MAX; | ||
+ | UART_com.check_counter = UART_CHECK_COUNTER_MAX; | ||
+ | UART_com.buffer_counter = 0; | ||
+ | UART_com.write_buffer[0] = UART_CMD_READ_SENSORS_STATUS; | ||
+ | UART_com.write_buffer[1] = UART_END_BYTE; | ||
+ | Serial2.write( UART_com.write_buffer, 2 ); | ||
+ | } | ||
</code> | </code> | ||
+ | |||
+ | The WiFi and the serial communications are initialized in the setup functions | ||
<code C> | <code C> | ||
- | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LOOP FUNCTION | + | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SETUP FUNCTION |
+ | void setup() { | ||
+ | // setup the serial comms | ||
+ | Serial.begin( SERIAL_1_BAUDRATE ); | ||
+ | Serial2.begin( SERIAL_2_BAUDRATE, SERIAL_8N1, ESP_MASTER_RX_PIN, ESP_MASTER_TX_PIN ); | ||
+ | delay( 4000 ); | ||
+ | |||
+ | // prepare wifi config | ||
+ | setup_wifi(); | ||
+ | client.setServer( mqtt_server, 1883 ); | ||
+ | client.setCallback( callback ); | ||
+ | |||
+ | // init the serial config | ||
+ | init_com_protocol_UART(); | ||
+ | |||
+ | Serial.println( "data sent" ); | ||
+ | } | ||
</code> | </code> | ||
+ | The master will send periodically the **UART_CMD_READ_SENSORS_DATA** command, and after the response is received, it will send the data to the MQTT broker, depending on the slave's configuration. | ||
+ | <code C> | ||
+ | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LOOP FUNCTION | ||
+ | void loop() | ||
+ | { | ||
+ | uint8_t data_byte_read; | ||
+ | int8_t flags_processed; | ||
+ | // reconnect to MQTT | ||
+ | if( !client.connected() ) | ||
+ | { | ||
+ | reconnect(); | ||
+ | } | ||
+ | if( !client.loop() ) | ||
+ | { | ||
+ | client.connect( "ESP8266Client" ); | ||
+ | } | ||
+ | // check for timeouts | ||
+ | if( UART_com.flags.is_busy == TRUE ) | ||
+ | { | ||
+ | UART_com.timeout_counter--; | ||
+ | if( UART_com.timeout_counter == 0 ) | ||
+ | { | ||
+ | UART_com.flags.word8 = 0x00; | ||
+ | Serial.println( "Communication has been reset and blocked!" ); | ||
+ | while( 1 ); | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | UART_com.check_counter--; | ||
+ | | ||
+ | // read the sensors again | ||
+ | if( UART_com.check_counter == 0 ) | ||
+ | { | ||
+ | UART_com.flags.is_busy = TRUE; | ||
+ | UART_com.check_counter = UART_CHECK_COUNTER_MAX; | ||
+ | UART_com.timeout_counter = UART_TIMEOUT_COUNTER_MAX; | ||
+ | | ||
+ | UART_com.write_buffer[0] = UART_CMD_READ_SENSORS_DATA; | ||
+ | UART_com.write_buffer[1] = UART_END_BYTE; | ||
+ | Serial2.write( UART_com.write_buffer, 2 ); | ||
+ | } | ||
+ | | ||
+ | } | ||
+ | // read every byte available from the receiver's buffer | ||
+ | while( Serial2.available() ) | ||
+ | { | ||
+ | data_byte_read = Serial2.read(); | ||
+ | |||
+ | if( UART_com.flags.is_busy == TRUE ) | ||
+ | { | ||
+ | UART_com.timeout_counter = UART_TIMEOUT_COUNTER_MAX; | ||
+ | UART_com.check_counter = UART_CHECK_COUNTER_MAX; | ||
+ | UART_com.read_buffer[UART_com.buffer_counter] = data_byte_read; | ||
+ | UART_com.buffer_counter++; | ||
+ | |||
+ | if( ( ( UART_com.buffer_counter == UART_RESPONSE_INIT_CMD_MAX_LENGTH ) && ( UART_com.write_buffer[0] == UART_CMD_READ_SENSORS_STATUS ) ) || | ||
+ | ( ( UART_com.buffer_counter == UART_RESPONSE_READ_DATA_MAX_LENGTH ) && ( UART_com.write_buffer[0] == UART_CMD_READ_SENSORS_DATA ) ) ) | ||
+ | { | ||
+ | UART_com.flags.is_busy = FALSE; | ||
+ | UART_com.buffer_counter = 0; | ||
+ | |||
+ | switch( UART_com.read_buffer[0] ) | ||
+ | { | ||
+ | case UART_CMD_READ_SENSORS_STATUS: | ||
+ | Serial.println( "Config read ..." ); | ||
+ | |||
+ | flags_processed = ( int8_t )( ( ( ( uint16_t )UART_com.read_buffer[2] ) << 8 ) | UART_com.read_buffer[1] ); | ||
+ | |||
+ | UART_com.flags.sensor_temp_supported = ( ( flags_processed & SENSOR_TEMP_SUPPORTED ) != 0x00 ) ? TRUE : FALSE; | ||
+ | UART_com.flags.sensor_tvoc_supported = ( ( flags_processed & SENSOR_TVOC_SUPPORTED ) != 0x00 ) ? TRUE : FALSE; | ||
+ | UART_com.flags.sensor_sound_supported = ( ( flags_processed & SENSOR_SOUND_SUPPORTED ) != 0x00 ) ? TRUE : FALSE; | ||
+ | break; | ||
+ | |||
+ | case UART_CMD_READ_SENSORS_DATA: | ||
+ | Serial.println( "Data read ..." ); | ||
+ | |||
+ | if( UART_com.flags.sensor_temp_supported == TRUE ) { client.publish("ESP32/temp", String( ( float )( ( ( uint16_t )UART_com.read_buffer[2] << 8 ) | UART_com.read_buffer[1] ) / 10 ).c_str() ); } | ||
+ | if( UART_com.flags.sensor_tvoc_supported == TRUE ) { client.publish("ESP32/tvoc", String( ( int16_t )( ( ( uint16_t )UART_com.read_buffer[4] << 8 ) | UART_com.read_buffer[3] ) ).c_str() ); } | ||
+ | if( UART_com.flags.sensor_sound_supported == TRUE ) { client.publish("ESP32/sound", String( ( int16_t )( ( ( uint16_t )UART_com.read_buffer[6] << 8 ) | UART_com.read_buffer[5] ) ).c_str() ); } | ||
+ | |||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | delay( 100 ); | ||
+ | } | ||
+ | </code> | ||
Line 223: | Line 489: | ||
</code> | </code> | ||
- | Depending on which define is used, a specific set of sensors will be used. | + | Depending on which board is defined, a specific set of sensors will be used. |
<code C> | <code C> | ||
Line 239: | Line 505: | ||
</code> | </code> | ||
- | The configuration which the sensors need are used depending on the sensors used. | + | The configurations and libraries that are needed by the sensors are defined depending on the previous macros. The following functions are used to read the data provided by them. |
- | The following functions are used to read the data provided by them. | + | |
<code C> | <code C> | ||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SENSOR FUNCTIONS | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SENSOR FUNCTIONS | ||
#ifdef USE_SENSOR_TVOC_MQ2 | #ifdef USE_SENSOR_TVOC_MQ2 | ||
- | #define SENSOR_TVOC_MQ2_PIN A7 | + | #define SENSOR_TVOC_MQ2_PIN A7 |
int16_t measure_sensor_tvoc_MQ2() | int16_t measure_sensor_tvoc_MQ2() | ||
Line 257: | Line 522: | ||
#include <DallasTemperature.h> | #include <DallasTemperature.h> | ||
- | #define SENSOR_TEMP_DS18B20_PIN 7 | + | #define SENSOR_TEMP_DS18B20_PIN 7 |
OneWire oneWire( SENSOR_TEMP_DS18B20_PIN ); | OneWire oneWire( SENSOR_TEMP_DS18B20_PIN ); | ||
Line 270: | Line 535: | ||
#ifdef USE_SENSOR_SOUND_LM393 | #ifdef USE_SENSOR_SOUND_LM393 | ||
- | #define SENSOR_SOUND_LM393_PIN A7 | + | #define SENSOR_SOUND_LM393_PIN A6 |
int16_t measure_sensor_SOUND_LM393() | int16_t measure_sensor_SOUND_LM393() | ||
Line 291: | Line 556: | ||
} | } | ||
#endif | #endif | ||
- | |||
</code> | </code> | ||
- | Only the sensors used are initialized at startup. | + | The function below is used to initialize all sensors that are being used. |
<code C> | <code C> | ||
Line 301: | Line 565: | ||
{ | { | ||
#ifdef USE_SENSOR_TVOC_MQ2 | #ifdef USE_SENSOR_TVOC_MQ2 | ||
- | // Serial.println( "\tTesting the tvoc sensor MQ2 ..." ); | ||
pinMode( SENSOR_TVOC_MQ2_PIN, INPUT ); | pinMode( SENSOR_TVOC_MQ2_PIN, INPUT ); | ||
#endif | #endif | ||
#ifdef USE_SENSOR_TEMP_DS18B20 | #ifdef USE_SENSOR_TEMP_DS18B20 | ||
- | // Serial.println( "\tTesting the temperature sensor DS18B20 ..." ); | ||
pinMode( SENSOR_TEMP_DS18B20_PIN, INPUT ); | pinMode( SENSOR_TEMP_DS18B20_PIN, INPUT ); | ||
#endif | #endif | ||
#ifdef USE_SENSOR_SOUND_LM393 | #ifdef USE_SENSOR_SOUND_LM393 | ||
- | // Serial.println( "\tTesting the sound sensor LM393 ..." ); | ||
pinMode( SENSOR_SOUND_LM393_PIN, INPUT ); | pinMode( SENSOR_SOUND_LM393_PIN, INPUT ); | ||
#endif | #endif | ||
#ifdef USE_SENSOR_TEMP_ADT7410 | #ifdef USE_SENSOR_TEMP_ADT7410 | ||
- | // Serial.println( "\tTesting the temp sensor ADT7410 ..." ); | ||
if( !temp_sensor_ADT7410.begin() ) | if( !temp_sensor_ADT7410.begin() ) | ||
{ | { | ||
Line 323: | Line 583: | ||
</code> | </code> | ||
- | The serial structure and macros used are defined below: | + | The serial communication is implemented using the following macros: |
<code C> | <code C> | ||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SERIAL MACROS AND VARIABLES | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SERIAL MACROS AND VARIABLES | ||
+ | // general macros used | ||
#define UART_REQUEST_CMD_MAX_LENGTH 2 | #define UART_REQUEST_CMD_MAX_LENGTH 2 | ||
#define UART_RESPONSE_CMD_MAX_LENGTH 4 | #define UART_RESPONSE_CMD_MAX_LENGTH 4 | ||
Line 333: | Line 594: | ||
#define UART_END_BYTE 0x55 | #define UART_END_BYTE 0x55 | ||
- | // command list | + | // commands used |
#define UART_CMD_READ_SENSORS_STATUS 0x10 | #define UART_CMD_READ_SENSORS_STATUS 0x10 | ||
- | #define UART_CMD_READ_TEMP_SENSOR_VALUE 0x21 | + | #define UART_CMD_READ_SENSORS_DATA 0x20 |
- | #define UART_CMD_READ_TVOC_SENSOR_VALUE 0x31 | + | |
- | #define UART_CMD_READ_SOUND_SENSOR_VALUE 0x41 | + | |
- | // sensor supported flags | + | // flag positions |
- | #define SENSOR_TEMP_SUPPORTED 0x01 | + | #define SENSOR_TEMP_SUPPORTED 0x01 |
- | #define SENSOR_TVOC_SUPPORTED 0x02 | + | #define SENSOR_TVOC_SUPPORTED 0x02 |
- | #define SENSOR_SOUND_SUPPORTED 0x04 | + | #define SENSOR_SOUND_SUPPORTED 0x04 |
+ | |||
+ | // length of buffers | ||
+ | #define UART_READ_BUFFER_LENGTH 5 | ||
+ | #define UART_WRITE_BUFFER_LENGTH 5 | ||
- | // serial config | ||
- | #define UART_READ_BUFFER_LENGTH 5 | ||
- | #define UART_WRITE_BUFFER_LENGTH 5 | ||
typedef struct | typedef struct | ||
{ | { | ||
Line 358: | Line 618: | ||
</code> | </code> | ||
- | The UART protocol is started with the 115200 baud rate and the sensors are initialized. | + | The UART protocol is started with the 115200 baud rate and the sensors are initialized at startup. |
<code C> | <code C> | ||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SETUP FUNCTION | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SETUP FUNCTION | ||
- | void setup() { | + | void setup() |
+ | { | ||
Serial.begin( 115200 ); | Serial.begin( 115200 ); | ||
delay( 1000 ); | delay( 1000 ); | ||
Line 374: | Line 635: | ||
<code C> | <code C> | ||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LOOP FUNCTION | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LOOP FUNCTION | ||
- | void loop() { | + | void loop() |
+ | { | ||
int16_t response_data_word16; | int16_t response_data_word16; | ||
Line 386: | Line 648: | ||
serial_com.buffer_counter = 0; | serial_com.buffer_counter = 0; | ||
response_data_word16 = -32768; | response_data_word16 = -32768; | ||
- | + | ||
+ | serial_com.write_buffer[0] = serial_com.read_buffer[0]; | ||
switch( serial_com.read_buffer[UART_CMD_BYTE_POS] ) | switch( serial_com.read_buffer[UART_CMD_BYTE_POS] ) | ||
{ | { | ||
+ | |||
case UART_CMD_READ_SENSORS_STATUS: | case UART_CMD_READ_SENSORS_STATUS: | ||
response_data_word16 = ( int16_t )( 0x00 | response_data_word16 = ( int16_t )( 0x00 | ||
Line 400: | Line 664: | ||
| ( SENSOR_SOUND_SUPPORTED ) | | ( SENSOR_SOUND_SUPPORTED ) | ||
#endif | #endif | ||
- | ); | + | ); |
+ | |||
+ | serial_com.write_buffer[1] = response_data_word16 & 0xFF; | ||
+ | serial_com.write_buffer[2] = ( response_data_word16 >> 8 ) & 0xFF; | ||
+ | serial_com.write_buffer[3] = UART_END_BYTE; | ||
+ | Serial.write( serial_com.write_buffer, 4 ); | ||
break; | break; | ||
- | case UART_CMD_READ_TEMP_SENSOR_VALUE: | + | case UART_CMD_READ_SENSORS_DATA: |
#ifdef USE_SENSOR_TEMP_ADT7410 | #ifdef USE_SENSOR_TEMP_ADT7410 | ||
response_data_word16 = measure_sensor_temp_ADT7410(); | response_data_word16 = measure_sensor_temp_ADT7410(); | ||
Line 409: | Line 678: | ||
#ifdef USE_SENSOR_TEMP_DS18B20 | #ifdef USE_SENSOR_TEMP_DS18B20 | ||
response_data_word16 = measure_sensor_temp_DS18B20(); | response_data_word16 = measure_sensor_temp_DS18B20(); | ||
- | #endif | + | #else |
+ | response_data_word16 = 0x00; | ||
+ | #endif | ||
#endif | #endif | ||
- | break; | + | serial_com.write_buffer[1] = response_data_word16 & 0xFF; |
- | case UART_CMD_READ_TVOC_SENSOR_VALUE: | + | serial_com.write_buffer[2] = ( response_data_word16 >> 8 ) & 0xFF; |
#ifdef USE_SENSOR_TVOC_MQ2 | #ifdef USE_SENSOR_TVOC_MQ2 | ||
- | response_data_word16 = measure_sensor_tvoc_MQ2(); | + | response_data_word16 = measure_sensor_tvoc_MQ2(); |
+ | #else | ||
+ | response_data_word16 = 0x00; | ||
#endif | #endif | ||
- | break; | + | |
- | case UART_CMD_READ_SOUND_SENSOR_VALUE: | + | serial_com.write_buffer[3] = response_data_word16 & 0xFF; |
+ | serial_com.write_buffer[4] = ( response_data_word16 >> 8 ) & 0xFF; | ||
#ifdef USE_SENSOR_SOUND_LM393 | #ifdef USE_SENSOR_SOUND_LM393 | ||
- | response_data_word16 = measure_sensor_SOUND_LM393(); | + | response_data_word16 = measure_sensor_SOUND_LM393(); |
+ | #else | ||
+ | response_data_word16 = 0x00; | ||
#endif | #endif | ||
+ | | ||
+ | serial_com.write_buffer[5] = response_data_word16 & 0xFF; | ||
+ | serial_com.write_buffer[6] = ( response_data_word16 >> 8 ) & 0xFF; | ||
+ | | ||
+ | serial_com.write_buffer[7] = UART_END_BYTE; | ||
+ | Serial.write( serial_com.write_buffer, 8 ); | ||
break; | break; | ||
} | } | ||
- | |||
- | serial_com.write_buffer[0] = serial_com.read_buffer[0]; | ||
- | serial_com.write_buffer[1] = response_data_word16 & 0xFF; | ||
- | serial_com.write_buffer[2] = ( response_data_word16 >> 8 ) & 0xFF; | ||
- | serial_com.write_buffer[3] = UART_END_BYTE; | ||
- | |||
- | Serial.write( serial_com.write_buffer, UART_RESPONSE_CMD_MAX_LENGTH ); | ||
} | } | ||
} | } | ||
Line 439: | Line 716: | ||
The data acquired by the master board and send to a server can be view using the following Dashboard: | The data acquired by the master board and send to a server can be view using the following Dashboard: | ||
- | FIXME to add image | + | |
+ | {{:iothings:proiecte:2023:node_red_webpage_dashboard.jpeg?600|}} | ||
The **Dashboard** was developed using **Node-RED**, which is a programming tool used for creating web pages. It provides a browser-based editor from which we can wire together flows between different components. | The **Dashboard** was developed using **Node-RED**, which is a programming tool used for creating web pages. It provides a browser-based editor from which we can wire together flows between different components. | ||
Line 446: | Line 724: | ||
The components of the MQTT protocol are the following: | The components of the MQTT protocol are the following: | ||
* **MQTT client** -> multiple clients can connect to network; in our case there are 2 clients, the website and the master board | * **MQTT client** -> multiple clients can connect to network; in our case there are 2 clients, the website and the master board | ||
- | * **MQTT broker** -> it handles the communication between the MQTT clients; only 1 broker can exist, and the protocol cannot function without it; the broker is hosted locally on laptop | + | * **MQTT broker** -> it handles the communication between the MQTT clients; the protocol cannot function without it; the broker is hosted locally on laptop |
+ | |||
+ | MQTT architecture: | ||
+ | |||
+ | {{:iothings:proiecte:2023:MQTT_structure.jpeg?600|}} | ||
The MQTT is a lightweight protocol designed for IOT devices, since the clients do not need to connect or keep tracking other clients, they only need to exchange data with the broker, using topics. A client can publish ( post data ) or subscribe ( receive data ) on a topic. | The MQTT is a lightweight protocol designed for IOT devices, since the clients do not need to connect or keep tracking other clients, they only need to exchange data with the broker, using topics. A client can publish ( post data ) or subscribe ( receive data ) on a topic. | ||
Line 464: | Line 746: | ||
=====5. Conclusion===== | =====5. Conclusion===== | ||
- | In conclusion, this project’s aim was to create the infrastructure for an configurable indoor air quality monitoring system, which was successfully obtained. The advantages of using this infrastructure are that any device can be added with ease to the Dashboard, and the MQTT can support a large number ( even reach up to 1000 clients ), and the configuration of a device can be changed, requiring a minimum amount of effort. | + | In conclusion, this project’s aim was to create the infrastructure for a configurable indoor air quality monitoring system, which was successfully obtained. The advantages of using this infrastructure are that any device can be added with ease to the Dashboard, and the MQTT can support a large number ( even reach up to 1000 clients ), and the configuration of a device can be changed, requiring a minimum amount of effort. |
=====Resources===== | =====Resources===== | ||