G1: Smart Alarm System - shalan/CSCE4301-WiKi GitHub Wiki

Submitted By

Name GitHub
MagdElDin AbdalRaaof MagdElDinAhmed
Tarek Kassab TataKassab
Youssef Mansour youssef-mansor

Github Repo

https://github.com/youssef-mansor/stm32-wakemath-system

The Proposal

WakeMath is an embedded systems project built on the STM32 Nucleo-L432KC. It detects prolonged inactivity using a PIR motion sensor, triggers a buzzer alarm, and requires the user to solve a math challenge on a Qapass LCD using the Digilent Pmod KYPD keypad before the alarm will stop. Additionally, a mobile app will be used to change settings of the alarm like the duration before activation.

Proposed Features

  • PIR-based inactivity detection
  • Buzzer alarm triggered after inactivity timeout
  • LCD math challenge displayed on a Qapass character LCD
  • User input via Digilent Pmod KYPD
  • Alarm deactivates only when the correct answer is entered
  • Mobile Application to modify the system settings

Current HW Block Diagram

Current Flow Chart

Proposed Components

All hardware was provided courtesy of the CSCE Workshop.

STM32-L432KC

F1438574-01-3179008049

The STM32-L432KC is a significantly weaker board than the original Raspberry Pi 4 as intended. Additionally, the CubeMX software allows for easy pin and connectivity configuration. Furthermore, our lab work provides us with a solid basis for how to program for this board.

HC-SR501 PIR Motion Sensor

hc-sr501-pir-ir-passive-infrared-motion-detector-sensor-module-for-arduino-diy-450778_480x480-1424195945

This PIR motion sensor proved effective at detecting motion in one of the senior projects presented back in the Spring 2025 semester. Alternatives such as heart rate monitors were considered, but this was the least invasive. Most importantly, it is significantly cheaper than the Raspberry Pi Camera it is meant to replace.

Keypad (Pmod KYPD)

2335471-3684496124

Its availability combined with ease of use makes it perfect for the portion of our application that requires solving the math problems.

Bluetooth Module (HM-10)

hm-10-ble-40-firmware-v540-bluetooth-low-energy-module-3039719580

It will act as the connection between our phone app and the board.

LCD Screen (LCD1602 I2C)

i2c-serial-lcd-1602-module-1581311608

The use of the I2C version was necessary to conserve pins on the board and the LCD is meant to display the math problems on screen as well as the user's answer as they are writing it.

Buzzer

(Not exact photo)

D_NQ_NP_932322-MLM46724371667_072021-V-1363314137

It turns on when the alarm signal is activated and only turned off when the math problem is solved.

First Update

Motion Detection (HC-SR501 PIR Motion Sensor)

By setting pin PA8 (AKA pin D9 on the physical board) to GPIO input, we can take readings from the PIR on whether or not motion was detected. It is yet to be integrated with the remainder of the project.

https://github.com/user-attachments/assets/2b1f4dc5-a614-4f80-af1d-bc69530c2ee8

LCD Display (Qapass LCD1602 I2C)

By setting the SDA and SDC pins of the I2C1 interface on the board to PA10 and PA9 respectively (D0 and D1 on the actual board), we can connect the LCD to the board. However, the connection is not direct since additional SDA and SDC pull up resistances are required due to the lack of pull up resistance in the MCU and the LCD. The resistances amount to 2.8 kOhm for SDA and another 2.8 kOhm for SDC.

To properly send the strings to the LCD, we utilize the liquidcrystal_i2c library found online to allow for easy LCD initialization and printing.

  • HD44780_Init(2) initializes the LCD
  • HD44780_Clear() clears the LCD
  • HD44780_SetCursor(x,y) sets the cursor at position x in row y
  • HD44780_PrintStr(str) displays the string str starting from the cursor position

Keypad (Pmod KYPD)

Pins

  • Pin PA1, and pins PA3 to PA5 (A1 to A4 on the board) correspond to columns 4 to 1 on the keypad and are set to GPIO_INPUT with the GPIO_PULLUP setting.
  • Pins PA6, PA7, PB0, and PB1 (A5, A6, D3, and D6 on the board) correspond to rows 4 to 1 on the keypad and are set to GPIO_OUTPUT_PP

Variables

  • KEYPAD_MAP: A 2D array that stores the character on the keypad in the corresponding coordinate
  • ROW_PORTS, ROW_PINS, COL_PORTS, COL_PINS: Arrays of size 4 that mark the port and pin of each row and column

Operation

  • Iterate through every row
  • Set the corresponding row to low for each iteration
  • Inside the row loop, iterate through each column
  • If the column output is low, then a button press is detected and return the character that corresponds to the row-column combination from KEYPAD_MAP
  • The row is set back to high at the end of the row iteration or before returning in case of a button press
  • If no button press is detected, return 0

Math Problem Generator

Variables

  • num1 and num2: They are the two numbers, each ranging from 1 to 9 inclusive, that will make up the problem. For instance, in the problem "1+2=?", num1 would be 1 and num2 would be 2.
  • expected_sum: It is the number the MCU compares the user's answer to. If the user's answer and the expected_sum match, then the answer is deemed correct. The answer is deemed incorrect otherwise.
  • op_selector: It is an integer selected at random from the range 0 to 4 inclusive to determine which operation will be used in the problem. 0 means addition, 1 means subtraction, 2 means multiplication, and 3 means division.
  • op_char: It is the character chosen as a result of a switch statement on op_selector. It can be +. -. *, or / and is displayed on the LCD.
  • input_buffer: A 5 character array that stores the user's answer.
  • input_index: An integer that defines which part of the input buffer the user is on.

Operation

  • The implementation as of now works in an infinite while loop.
  • Every iteration, a new question is created
  • The operation is chosen randomly by setting op_selector to a random value
  • For addition, subtraction, and multiplication, num1 and num2 are randomly selected while expected_sum is calculated using num1 and num2
  • For division, expected_sum and num2 are randomly selected while num1 is the outcome of multiplying expected_sum by num2
  • input_buffer is reset and input_index is set to 0
  • The question is printed on the LCD
  • The program keeps scanning for keypad inputs until the answer is submitted
  • We only register the numbers 0 to 9 and the letters C and D as inputs
  • C clears the buffer and the screen to erase the current answer
  • D submits the answer for review
  • The user's answer is translated into an integer using the atoi() function
  • A different message appears depending on whether or not the answer is correct or not

To-Do

  1. Implement the alarm component
  2. Integrate all components from part 1
  3. Create the mobile application to control settings

Second Update

The general idea is that we combined the math problem generator with the PIR sensor and the alarm. Additionally, we introduced alarm setting control via keypad and Bluetooth.

Motion States

We keep track of both the current state and the previous state

The states are as follows:

  • STATE_MONITOR:
  • STATE_COUNTDOWN: This state is responsible for the countdown process when no motion is detected (countdown is 5 seconds by default)
  • STATE_ALARM: This state is responsible for generating the math problem and sounding the alarm
  • STATE_SET_TIME: This state is responsible for allowing the time-to-alarm to be modified (cannot be used while alarm is currently active)

Math Problem Generator:

The problem is now generated inside the OperationMode function and retains the logic from the previous milestone in addition to triggering a state change to STATE_ALARM.

Input Handling (handle_input()):

Case 1 (the A key is pressed and the alarm is not active):

  • Set the state to STATE_SET_TIME and clear the buffer responsible for storing the modified value of the timer

Case 2 (the alarm is active)

  • If the input is numeric and (between 0 and 9 inclusive) and no more than 2 numbers have already been input, place the key press in the input buffer, increment the input index and write the character to the LCD
  • If the input is the C key, clear the answer from the LCD and clear the input buffer
  • If the input is the B key, submit the answer for review and either mark it as correct and change the state to STATE_MONITOR and turn off the alarm, or generate a different question if the answer was incorrect

Case 3 (the mode is STATE_SET_TIME):

  • We handle the numeric inputs similar to the input when the alarm is active, we just instead have 5 digits instead of 2 (time is input in seconds)
  • The C button clears the time_buffer and the characters related to it on the LCD
  • The B button confirms the input and sets it as the value for the timer used to trigger the alarm before changing the state to STATE_MONITOR
  • The A button just takes us back to the STATE_MONITOR state

Case 4 (Bluetooth):

  • Handled via UART interrupt and checks if the character is one of the accepted ones
  • Overrides the keypad entry if the Bluetooth entry is valid

Keeping Track of Motion setMotionState()

  • If the raw state of the PIR sensor changed, reset the timer for when the PIR last changed
  • Only solidify the change in state if the new state remains for a set period of time (1 second by default)

Handling States handle_State()

STATE_MONITOR

  • Turn off the buzzer
  • If no motion detected, start the timer and enter the STATE_COUNTDOWN state

STATE_COUNTDOWN

  • If motion occurs, go back to STATE_MONITOR
  • If the timer runs out and no motion is detected, change the state to STATE_ALARM, turn on the alarm, and generate the question

STATE_ALARM

  • Keep the alarm on
  • If state changes back to STATE_MONITOR, turn off the alarm

Main Block

  • Set initial state to STATE_MONITOR
  • Scan for keypad input or Bluetooth input (priority goes to Bluetooth input)
  • Scan for input using handle_input()
  • Check the motion sensor using setMotionState()
  • Handle the current state using handle_State()

Desktop Web GUI

  • Check for Bluetooth availability
  • Allow user to connect to the HMSoft module
  • When setting the timer, send the chain of characters that corresponds to A, the timer value, and B to save the new setting
  • When answering the question, send the answer and B to submit the answer properly
  • Allow for user to disconnect from the HMSoft module

Usage Instructions

Requirements

  • Chrome browser (not Firefox/Safari)
  • BlueZ 5.40+ on Linux
  • HM-10 BLE module powered on

Linux Setup (One-time)

  1. Enable experimental Bluetooth daemon:

    sudo nano /lib/systemd/system/bluetooth.service
    

    Change ExecStart=/usr/lib/bluetooth/bluetoothd to:

    ExecStart=/usr/lib/bluetooth/bluetoothd -E
    

    Save and restart:

    sudo systemctl daemon-reload
    sudo systemctl restart bluetooth
    
  2. Enable Chrome flags (both required):

    • Go to chrome://flags/#enable-experimental-web-platform-featuresEnabled
    • Go to chrome://flags/#enable-web-bluetooth-new-permissions-backendEnabled
    • Click Relaunch

Run

  1. Start local server:

    python3 -m http.server 8000
    
  2. Open in Chrome:

    http://localhost:8000/hm10-sender.html
    
  3. Use:

    • Click "Connect to HM-10" → select "HMSoft"
    • Set Timer: Enter number → sends A{number}B
    • Submit Answer: Enter number → sends {number}B

Video Demo

Alarm Loop

https://github.com/user-attachments/assets/5c386acd-b782-40af-8a22-63cd92b8719d

Timer Set

https://github.com/user-attachments/assets/2dc2107a-6c36-44fe-9338-4ddf9776735d

Bluetooth Operation

https://github.com/user-attachments/assets/0e0ce73e-3432-4993-9780-37d7636a38bf

Desktop Web GUI

https://github.com/user-attachments/assets/df5b9d8f-4c19-4a30-a547-ae1c051c38ac