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
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
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)
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)
It will act as the connection between our phone app and the board.
LCD Screen (LCD1602 I2C)
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)
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 LCDHD44780_Clear()clears the LCDHD44780_SetCursor(x,y)sets the cursor at position x in row yHD44780_PrintStr(str)displays the stringstrstarting 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_INPUTwith theGPIO_PULLUPsetting. - 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 coordinateROW_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 theexpected_summatch, 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 onop_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_selectorto a random value - For addition, subtraction, and multiplication,
num1andnum2are randomly selected whileexpected_sumis calculated usingnum1andnum2 - For division,
expected_sumandnum2are randomly selected whilenum1is the outcome of multiplyingexpected_sumbynum2 input_bufferis reset andinput_indexis 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
- Implement the alarm component
- Integrate all components from part 1
- 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 alarmSTATE_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_TIMEand 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_MONITORand 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_bufferand 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_MONITORstate
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_COUNTDOWNstate
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, andBto save the new setting - When answering the question, send the answer and
Bto 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)
-
Enable experimental Bluetooth daemon:
sudo nano /lib/systemd/system/bluetooth.serviceChange
ExecStart=/usr/lib/bluetooth/bluetoothdto:ExecStart=/usr/lib/bluetooth/bluetoothd -ESave and restart:
sudo systemctl daemon-reload sudo systemctl restart bluetooth -
Enable Chrome flags (both required):
- Go to
chrome://flags/#enable-experimental-web-platform-features→ Enabled - Go to
chrome://flags/#enable-web-bluetooth-new-permissions-backend→ Enabled - Click Relaunch
- Go to
Run
-
Start local server:
python3 -m http.server 8000 -
Open in Chrome:
http://localhost:8000/hm10-sender.html -
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