DEV Community

Cover image for Plotting Real-Time Air Quality Data from a Bluetooth Air Quality Monitoring Device Using MATLAB
Bleuio tech
Bleuio tech

Posted on

Plotting Real-Time Air Quality Data from a Bluetooth Air Quality Monitoring Device Using MATLAB

With the rise of IoT devices, Bluetooth Low Energy (BLE) technology has emerged as a convenient solution for wireless data transmission. In this tutorial, we’ll explore how to read real-time air quality data from a BLE air quality monitoring device called HibouAir, and plot it using MATLAB. To accomplish this, we’ll utilize the BleuIO BLE USB dongle, which simplifies BLE application development with its AT command interface.

Project Components:

  1. BleuIO BLE USB Dongle: The BleuIO dongle serves as our BLE interface, allowing us to communicate with BLE devices using simple AT commands. Its plug-and-play nature and versatile features make it an ideal choice for BLE application development.
  2. HibouAir Air Quality Monitoring Device: HibouAir is a BLE-enabled air quality monitoring device that measures various parameters such as CO2, temperature, humidity, VOCs, and more. It provides real-time data transmission via BLE, making it suitable for IoT applications.
  3. MATLAB: MATLAB is a powerful computing environment widely used for data analysis, visualization, and algorithm development. We’ll leverage MATLAB’s capabilities to read data from the BleuIO dongle, decode BLE advertisements from HibouAir, and plot the air quality data in real-time.

Project Implementation:

Step 1: Setting up the Hardware

  • Connect the BleuIO BLE USB dongle to your computer’s USB port.
  • Power on the HibouAir air quality monitoring device.

Step 2: Writing MATLAB Code

  • Define the serial port parameters in MATLAB to establish communication with the BleuIO dongle.
  • Scan for a specific HibouAir device with its MAC address to get air quality advertised data.
  • Implement functions to decode BLE advertisement data from HibouAir, including parsing CO2, temperature, humidity, and other relevant parameters.
  • Write code to continuously scan for BLE advertisements, extract air quality data, and plot co2 value real-time using MATLAB’s plotting functions.

How This Project Can Be Helpful for Engineers, Developers, and Analysts

Environmental Monitoring: Engineers and analysts can use this project to create efficient environmental monitoring systems. By integrating BLE air quality monitors with MATLAB’s data analysis tools, they can assess air quality, detect anomalies, and optimize environmental control systems.

Use Case: A civil engineering firm employs this setup to monitor indoor air quality in commercial buildings, identifying areas needing ventilation improvements.

IoT Development: Developers can leverage this project to build IoT applications across various industries. By connecting BLE monitors with cloud platforms and mobile apps, they enable remote monitoring and predictive maintenance.

Use Case: A startup develops a mobile app for real-time air quality monitoring in urban environments, using BLE devices and MATLAB for data analysis.

Research and Analysis: Analysts and researchers can utilize this project to study air quality’s impact on human health and the environment. BLE monitors and MATLAB enable them to collect data, perform statistical analysis, and communicate research findings effectively.

Use Case: Environmental scientists deploy BLE monitors to measure traffic-related air pollution in urban areas, using MATLAB to analyze data and inform urban planning decisions.

Complete MATLAB Code:

% Define the serial port parameters
portName = 'COM8';  % Change this to match your dongle's port identifier
baudRate = 57600;   % Change this to match your dongle's baud rate
macaddress = '220069'; % Change this to match the desired MAC address

% Define adv_data_decode function if not defined already
function env_data = adv_data_decode(data)
    % Initialize output structure
    env_data = struct();

    % Find the position of the start of advertisement data
    pos = strfind(data, '5B070');

    % Convert hexadecimal data to decimal values
    temp_hex = convertNumber(data, pos+22, 4);
    if temp_hex > 1000
        temp_hex = (temp_hex - (65535 + 1)) / 10;
    else
        temp_hex = temp_hex / 10;
    end

    % Decode the advertisement data
    env_data.boardID = data(pos + 8 : pos + 8 + 5);
    env_data.type = hex2dec(data(pos + 6 : pos + 6 + 1));
    env_data.light = convertNumber(data, pos + 14, 4);
    env_data.pressure = convertNumber(data, pos + 18, 4) / 10;
    env_data.temperature = temp_hex;
    env_data.humidity = convertNumber(data, pos + 26, 4) / 10;
    env_data.voc = convertNumber(data, pos + 30, 4);
    env_data.co2 = hex2dec(data(pos + 46 : pos + 46 + 3));
    env_data.ts = datetime('now', 'Format', 'yyyy-MM-dd HH:mm:ss');
end

function num = convertNumber(data, start, len)
    % Convert hexadecimal string to decimal number
    hex_str = data(start : start + len - 1);
    num = typecast(uint32(hex2dec(hex_str)), 'int32');
end

% Create a function to handle the scanning and decoding
function scanAndDecode(~, ~, s, macaddress, hObject)
    try
        % Retrieve stored data from the figure's appdata
        fig = ancestor(hObject, 'figure');
        storedData = guidata(fig);
        timeArray = storedData.timeArray;
        co2Array = storedData.co2Array;

        % Send the commands
        writeline(s, "AT+CENTRAL");
        write(s,13,"char");
        writeline(s, "AT+FINDSCANDATA="+macaddress+"=4");
        write(s,13,"char");

        % Pause for 4 seconds (assuming this is the time needed for scanning)
        pause(4);

        % Read the response
        response = '';
        while s.NumBytesAvailable > 0
            response = response + readline(s);
        end

        % Extract advertisement data from the last string
        lastLine = strsplit(response, newline);
        lastLine = lastLine{end};  % Get the last line
        advData = regexp(lastLine, '\[ADV\]:\s+(\w+)', 'tokens');

        % Display the advertisement data
        if ~isempty(advData)
            theData = adv_data_decode(advData{1}{1});
            disp(theData.co2); % Display CO2 data for example

            % Append new data points to arrays
            timeArray = [timeArray, datenum(theData.ts)]; % Convert datetime to serial date number
            co2Array = [co2Array, theData.co2];

            % Update stored data in the figure's appdata
            storedData.timeArray = timeArray;
            storedData.co2Array = co2Array;
            guidata(fig, storedData);

            % Update plot with new data points
            set(hObject, 'XData', timeArray, 'YData', co2Array);
            % Set x-axis to display time in the format of hours, minutes, and seconds
            datetick('x', 'HH:MM:SS');
            drawnow;
        else
            disp('No advertisement data found.');
        end

    catch e
        % Display any errors that occur
        disp("An error occurred: " + e.message);
    end
end

try
    % Create a serial port object
    s = serialport(portName, baudRate,"Timeout",2);
    configureTerminator(s, "LF");

    % Create a figure for plotting
    fig = figure;
    plotHandle = plot(NaN, NaN, 'o-');
    xlabel('Time');
    ylabel('CO2 Value');
    title('CO2 Value vs. Time');

    % Store data in the figure's appdata
    storedData.timeArray = [];
    storedData.co2Array = [];
    guidata(fig, storedData);

    % Create a timer object to run scanAndDecode every 10 seconds
    t = timer('ExecutionMode', 'fixedRate', 'Period', 10, ...
              'TimerFcn', {@scanAndDecode, s, macaddress, plotHandle});

    % Set the closerequestfcn callback to stop the timer and clear the serial port
    set(fig, 'closerequestfcn', {@stopScript, t, s});

    % Start the timer
    start(t);

catch e
    % Display any errors that occur
    disp("An error occurred: " + e.message);

    % Stop and delete the timer
    if exist('t', 'var') && isvalid(t)
        stop(t);
        delete(t);
    end

    % Close the serial port
    if exist('s', 'var') && isvalid(s)
        clear s;
    end
end

% Enable data cursors
dcm = datacursormode(gcf);
set(dcm, 'UpdateFcn', @customDataCursor);

% Custom data cursor function
function output_txt = customDataCursor(~, event_obj)
    % Get the data cursor position
    pos = get(event_obj, 'Position');

    % Convert the x-coordinate (time) to a formatted string
    timeString = datestr(pos(1), 'HH:MM:SS');

    % Create the output text to display
    output_txt = {['X: ', timeString], ['Y: ', num2str(pos(2))]}; % Customize as needed
end

function stopScript(~, ~, t, s)
    % Stop and delete the timer
    if exist('t', 'var') && isvalid(t)
        stop(t);
        delete(t);
    end

    % Close the serial port
    if exist('s', 'var') && isvalid(s)
        % Close the serial port
        delete(s);
    end

    % Close the figure
    delete(gcf);
end
Enter fullscreen mode Exit fullscreen mode

Output

In this tutorial, we demonstrated how to read real-time air quality data from a BLE air quality monitoring device, such as HibouAir, using the BleuIO BLE USB dongle and MATLAB. By following the steps outlined in this tutorial, engineers, developers, and analysts can develop applications for monitoring air quality in various environments. This project has numerous potential applications, including indoor air quality monitoring in smart buildings, environmental monitoring in industrial settings, and health monitoring in healthcare facilities. By leveraging the power of BLE technology and MATLAB’s data analysis capabilities, users can gain valuable insights into air quality trends and make informed decisions to improve environmental conditions and human health.

Top comments (0)