
Awareness of Air quality monitoring importance for health and productivity has been increasing lately, especially in indoor environments like offices and homes. In this tutorial, we’ll demonstrate how to create a real-time CO₂ monitoring application usingGo, a modern programming language with a vibrant community, alongside theBleuIO BLE USB dongle andHibouAir, a BLE-enabled air quality sensor.
This project showcases how to use Go’s simplicity and performance to build an efficient application that scans for CO₂ data, decodes it, and providesreal-time notifications on macOS when the CO₂ level exceeds a critical threshold. By using BleuIO’s integrated AT commands, you can focus on your application logic without worrying about complex embedded BLE programming.
Project Overview
The goal of this project is to:
- UseBleuIO to scan for BLE advertisements fromHibouAir, which broadcasts real-time CO₂ levels.
- Decode the advertised data to extract CO₂ concentration.
- Send areal-time macOS notification when CO₂ levels exceed a specified threshold (1000 ppm in this example).
Notifications are implemented using the macOSosascript
utility, ensuring you are immediately alerted about high CO₂ levels on your laptop screen.
Why This Project Is Useful
When you’re focused on work, you might not notice subtle changes in your environment. This application ensures you’re notified directly on your laptop screen when CO₂ levels become unsafe. This is especially helpful for:
- Office Workers: Monitor meeting rooms or shared spaces where ventilation may be insufficient.
- Remote Workers: Ensure a healthy workspace at home without distractions.
- Educational Settings: Keep classrooms or labs safe for students and staff.
Technical Details
Tools and Devices
- Programming Language:Go – Chosen for its simplicity, performance, and active community.
- BLE USB Dongle:BleuIO – Simplifies BLE communication with built-in AT commands.
- CO₂ Monitoring Device:HibouAir – Provides real-time air quality metrics over BLE.
How It Works
- Initialize the Dongle:
- Set the BleuIO dongle to thecentral role to enable scanning for BLE devices.
- Scan for Advertised Data:
- Use the
AT+FINDSCANDATA
command to scan for HibouAir’s advertisements containing air quality data.
- Use the
- Decode CO₂ Information:
- Extract and convert the relevant part of the advertisement to get the CO₂ level in ppm.
- Send Notifications:
- Use Go’s
exec.Command
to invoke macOSosascript
and display a desktop notification if the CO₂ level exceeds the threshold.
- Use Go’s
Implementation
Here is the source code for the project:
package mainimport ( "bufio" "fmt" "log" "os/exec" "strconv" "strings" "time" "go.bug.st/serial")func main() { // Open the serial port mode := &serial.Mode{ BaudRate: 9600, } port, err := serial.Open("/dev/cu.usbmodem4048FDE52CF21", mode) if err != nil { log.Fatalf("Failed to open port: %v", err) } defer port.Close() // Initial setup: Set the dongle to central mode err = setupDongle(port) if err != nil { log.Fatalf("Failed to set up dongle: %v", err) } // Repeatedly scan for advertised data and process it for { err := scanAndProcessData(port) if err != nil { log.Printf("Error during scan and process: %v", err) } time.Sleep(10 * time.Second) // Wait before the next scan (interval) }}// setupDongle sets the dongle to central modefunc setupDongle(port serial.Port) error { _, err := port.Write([]byte("AT+CENTRAL\r")) if err != nil { return fmt.Errorf("failed to write AT+CENTRAL: %w", err) } time.Sleep(1 * time.Second) // Ensure the command is processed buf := make([]byte, 100) _, err = port.Read(buf) if err != nil { return fmt.Errorf("failed to read response from AT+CENTRAL: %w", err) } fmt.Println("Dongle set to central mode.") return nil}// scanAndProcessData scans for advertised data and processes itfunc scanAndProcessData(port serial.Port) error { _, err := port.Write([]byte("AT+FINDSCANDATA=220069=2\r")) if err != nil { return fmt.Errorf("failed to write AT+FINDSCANDATA: %w", err) } time.Sleep(3 * time.Second) // Wait for scan to complete buf := make([]byte, 1000) n, err := port.Read(buf) if err != nil { return fmt.Errorf("failed to read scan response: %w", err) } response := string(buf[:n]) // Extract the first advertised data firstAdvertisedData := extractFirstAdvertisedData(response) if firstAdvertisedData == "" { fmt.Println("No advertised data found.") return nil } // Extract the specific part (6th from last to 3rd from last) and convert to decimal if len(firstAdvertisedData) >= 6 { extractedHex := firstAdvertisedData[len(firstAdvertisedData)-6 : len(firstAdvertisedData)-2] decimalValue, err := strconv.ParseInt(extractedHex, 16, 64) if err != nil { return fmt.Errorf("failed to convert hex to decimal: %w", err) } fmt.Printf("CO₂ Value: %d ppm\n", decimalValue) // Send notification if CO₂ value exceeds 1000 if decimalValue > 1000 { sendNotification("CO₂ Alert", fmt.Sprintf("High CO₂ level detected: %d ppm", decimalValue)) } } else { fmt.Println("Advertised data is too short to extract the desired part.") } return nil}// extractFirstAdvertisedData extracts the first advertised data from the responsefunc extractFirstAdvertisedData(response string) string { scanner := bufio.NewScanner(strings.NewReader(response)) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "Device Data [ADV]:") { parts := strings.Split(line, ": ") if len(parts) > 1 { return parts[1] } } } if err := scanner.Err(); err != nil { log.Printf("Error scanning response: %v", err) } return ""}// sendNotification sends a macOS notification with the specified title and messagefunc sendNotification(title, message string) { script := `display notification "` + message + `" with title "` + title + `"` cmd := exec.Command("osascript", "-e", script) err := cmd.Run() if err != nil { log.Printf("Error sending notification: %v", err) }}
Source code
Source code is available onhttps://github.com/smart-sensor-devices-ab/monitor-realtime-co2-go
Output
This project demonstrates how to build a real-time CO₂ monitoring application using Go, BleuIO, and HibouAir. By using Go’s capabilities and BleuIO’s ease of use, you can focus on the logic of your application and quickly adapt the solution to your specific needs.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse