-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: motion detection and server notifier
- Loading branch information
0 parents
commit add04b9
Showing
19 changed files
with
505 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[build] | ||
target = "xtensa-esp32-espidf" | ||
|
||
[target.xtensa-esp32-espidf] | ||
linker = "ldproxy" | ||
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x | ||
runner = "espflash flash --monitor" # Select this runner for espflash v2.x.x | ||
rustflags = [ | ||
"--cfg", | ||
"espidf_time64", | ||
] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110 | ||
|
||
[unstable] | ||
build-std = ["std", "panic_abort"] | ||
|
||
[env] | ||
MCU = "esp32" | ||
# Note: this variable is not used by the pio builder (`cargo build --features pio`) | ||
ESP_IDF_VERSION = "v5.1.1" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
name: Continuous Integration | ||
|
||
on: | ||
push: | ||
paths-ignore: | ||
- "**/README.md" | ||
pull_request: | ||
workflow_dispatch: | ||
|
||
env: | ||
CARGO_TERM_COLOR: always | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
jobs: | ||
rust-checks: | ||
name: Rust Checks | ||
runs-on: ubuntu-latest | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
action: | ||
- command: build | ||
args: --release | ||
- command: fmt | ||
args: --all -- --check --color always | ||
- command: clippy | ||
args: --all-targets --all-features --workspace -- -D warnings | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
- name: Enable caching | ||
uses: Swatinem/rust-cache@v2 | ||
- name: Setup Rust | ||
uses: esp-rs/xtensa-toolchain@v1.5 | ||
with: | ||
default: true | ||
buildtargets: esp32 | ||
ldproxy: true | ||
- name: Run command | ||
run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/.vscode | ||
/.embuild | ||
/target | ||
/Cargo.lock | ||
/src/config/config.rs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
[package] | ||
name = "esp32-motion-detector-and-server-notifier-rust" | ||
version = "0.2.0" | ||
authors = ["Andrei Dodu"] | ||
edition = "2021" | ||
resolver = "2" | ||
rust-version = "1.71" | ||
|
||
[profile.release] | ||
opt-level = "s" | ||
|
||
[profile.dev] | ||
debug = true # Symbols are nice and they don't increase the size on Flash | ||
opt-level = "z" | ||
|
||
[features] | ||
|
||
default = ["std", "hal", "esp-idf-sys/native"] | ||
|
||
|
||
pio = ["esp-idf-sys/pio"] | ||
all = ["std", "nightly", "experimental", "embassy"] | ||
hal = ["esp-idf-hal", "embedded-svc", "esp-idf-svc"] | ||
std = [ | ||
"alloc", | ||
"esp-idf-sys/std", | ||
"esp-idf-sys/binstart", | ||
"embedded-svc?/std", | ||
"esp-idf-hal?/std", | ||
"esp-idf-svc?/std", | ||
] | ||
alloc = ["embedded-svc?/alloc", "esp-idf-hal?/alloc", "esp-idf-svc?/alloc"] | ||
nightly = [ | ||
"embedded-svc?/nightly", | ||
"esp-idf-svc?/nightly", | ||
] # Future: "esp-idf-hal?/nightly" | ||
experimental = ["embedded-svc?/experimental", "esp-idf-svc?/experimental"] | ||
embassy = [ | ||
"esp-idf-hal?/embassy-sync", | ||
"esp-idf-hal?/critical-section", | ||
"esp-idf-svc?/embassy-time-driver", | ||
"esp-idf-svc?/embassy-time-isr-queue", | ||
] | ||
|
||
[dependencies] | ||
macaddr = "1.0.1" | ||
anyhow = "1.0.75" | ||
log = { version = "0.4.17", default-features = false } | ||
esp-idf-sys = { version = "0.33", default-features = false } | ||
esp-idf-hal = { version = "0.42.5", optional = true, default-features = false } | ||
esp-idf-svc = { version = "0.47.3", optional = true, default-features = false } | ||
embedded-svc = { version = "0.26.4", optional = true, default-features = false } | ||
serde = { version = "1.0.193", features = ["derive"] } | ||
serde_json = { version = "1.0.108", features = ["raw_value"] } | ||
|
||
[build-dependencies] | ||
embuild = "0.31.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# ESP32 IDF | Motion Detector and Server Notifier (Rust) | ||
|
||
Motion Detector and Server Notifier (Rust) is a motion detector application for ESP32 device (should be [this one](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-devkitc.html#get-started-esp32-devkitc-board-front)), implemented using Rust programming language, that allows to detect movements and send an alert to a server which will send a notification to a smartphone. **Please refer to the `How to configure and install it?` section if your application does not compiles** (it is a configuration issue). | ||
|
||
# Architecture | ||
|
||
Motion Detector application uses 3 devices: | ||
|
||
- led - used for notifying the motion sensor status and application errors. The led is configured to work with GPIO5(Out); | ||
- buzzer - used to emit a sound in order to notify the success of communication with the server after a motion detection. It is configured on GPIO15(Out); | ||
- movement sensor - around which the entire application revolves. It is configured on GPIO4(In). | ||
|
||
# How it works? | ||
|
||
When the ESP32 is turned on, the application tries to establish an WiFi connection. If the device fails to connect to the WiFi, the application will retry until it succeeds. Then the led will blink one time for one second: this means that the software is configured correctly. After a movement detection, a post request is made which contains the MAC address wrapped in a JSON, useful to identify the device that sent the request. If this request was sent successfully then the the led blinks for less that one second and the buzzer emits a short sound. If the request to the server fails, the led blinks for 2 times. The request then is handled by the server, that I wrote using Java (Spring Boot), and a new message is sent to a Discord channel. So that I receive a notification on my smartphone. If the notification was sent successfully, the server sends a positive status, else, a false is returned wrapped in a JSON. | ||
|
||
# How to configure and install it? | ||
|
||
Before installing the Motion Detector application on a ESP32, it is necessary to rename the `src/config/config.sample.rs` to `src/config/config.rs`. Then you should change the configuration in the `config.rs` by defining your WiFi SSID, password and your remote server alert request handler. | ||
I suppose that the environment is configured correctly, so that in order to run ESP32 Motion Detector application on an ESP32 device just run `cargo clean && cargo build && cargo run` (sometime I succeed in installing the software by doing a simple `cargo run`, other times i had to hold the boot button of ESP32). | ||
|
||
# Photo | ||
|
||
![board](images/board.jpg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
embuild::espidf::sysenv::output(); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[toolchain] | ||
channel = "esp" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K) | ||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000 | ||
|
||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default). | ||
# This allows to use 1 ms granuality for thread sleeps (10 ms by default). | ||
#CONFIG_FREERTOS_HZ=1000 | ||
|
||
# Workaround for https://github.com/espressif/esp-idf/issues/7631 | ||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n | ||
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n | ||
CONFIG_ESP_TASK_WDT_PANIC=n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// rename the file in config.rs | ||
// customize your settings by editing this variables | ||
pub const WIFI_SSID: &str = "wifi name"; | ||
pub const WIFI_PASS: &str = "wifi password"; | ||
pub const ALERT_URL: &str = "http://server_url:8080/alert"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use anyhow::Ok; | ||
use esp_idf_sys as _; | ||
mod service; | ||
mod util; | ||
use crate::service::orchestrator_service::orchestrate; | ||
mod config; | ||
fn main() -> anyhow::Result<()> { | ||
esp_idf_svc::sys::link_patches(); | ||
esp_idf_svc::log::EspLogger::initialize_default(); | ||
|
||
orchestrate(); | ||
|
||
return Ok(()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub mod config; | ||
pub mod service; | ||
pub mod util; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
use anyhow::{Error, Ok}; | ||
use embedded_svc::{http::client::Client as HttpClient, io::Write, utils::io}; | ||
use esp_idf_svc::http::client::EspHttpConnection; | ||
use esp_idf_sys as _; | ||
use log::{error, info}; | ||
use serde::Serialize; | ||
|
||
pub struct ClientService { | ||
alert_url: String, | ||
} | ||
|
||
impl ClientService { | ||
pub fn new(alert_url: &str) -> ClientService { | ||
ClientService { | ||
alert_url: alert_url.to_owned(), | ||
} | ||
} | ||
|
||
pub fn post_request(&self, mac_address: &str) -> anyhow::Result<(), anyhow::Error> { | ||
let mut client = HttpClient::wrap(EspHttpConnection::new(&Default::default())?); | ||
|
||
let payload = serde_json::to_string(&RequestAlert::new(mac_address.to_owned())).unwrap(); | ||
let payload = payload.as_bytes(); | ||
|
||
let content_length_header = format!("{}", payload.len()); | ||
let headers = [ | ||
("content-type", "application/json"), | ||
("content-length", &*content_length_header), | ||
]; | ||
|
||
let request = client.post(&self.alert_url, &headers); | ||
|
||
if request.is_err() { | ||
let message = format!("connection error: {:?}", request.err()); | ||
error!("{}", message); | ||
return Err(Error::msg(message)); | ||
} | ||
let mut request = request.unwrap(); | ||
|
||
if request.write_all(payload).is_err() { | ||
let message = format!("connection error while trying to write all"); | ||
error!("{}", message); | ||
return Err(Error::msg(message)); | ||
} | ||
if request.flush().is_err() { | ||
let message = format!("connection error while trying to flush"); | ||
error!("{}", message); | ||
return Err(Error::msg(message)); | ||
} | ||
info!("-> POST {}", self.alert_url); | ||
let response = request.submit(); | ||
if response.is_err() { | ||
let message = format!("connection error while trying to read response"); | ||
error!("{}", message); | ||
return Err(Error::msg(message)); | ||
} | ||
let mut response = response.unwrap(); | ||
|
||
let status = response.status(); | ||
info!("<- {}", status); | ||
let mut buf = [0u8; 1024]; | ||
let bytes_read = io::try_read_full(&mut response, &mut buf).map_err(|e| e.0); | ||
|
||
if bytes_read.is_err() { | ||
let message = format!( | ||
"connection error while trying to read response: {:?}", | ||
bytes_read.err() | ||
); | ||
error!("{}", message); | ||
return Err(Error::msg(message)); | ||
} else { | ||
let bytes_read = bytes_read.unwrap(); | ||
info!("Read {} bytes", bytes_read); | ||
match std::str::from_utf8(&buf[0..bytes_read]) { | ||
std::result::Result::Ok(body_string) => info!( | ||
"Response body (truncated to {} bytes): {:?}", | ||
buf.len(), | ||
body_string | ||
), | ||
Err(e) => error!("Error decoding response body: {}", e), | ||
}; | ||
|
||
// Drain the remaining response bytes | ||
while response.read(&mut buf).unwrap_or(0) > 0 {} | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Serialize)] | ||
#[warn(non_snake_case)] | ||
struct RequestAlert { | ||
macAddress: String, | ||
} | ||
|
||
impl RequestAlert { | ||
pub fn new(mac_address: String) -> RequestAlert { | ||
RequestAlert { | ||
macAddress: mac_address, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub mod client_service; | ||
pub mod orchestrator_service; | ||
pub mod peripheral_service; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use super::{client_service, peripheral_service::PeripheralService}; | ||
use crate::{config::config, util::thread_util}; | ||
use log::info; | ||
|
||
pub fn orchestrate() { | ||
let mut peripheral_service = PeripheralService::new(config::WIFI_SSID, config::WIFI_PASS); | ||
let client_service = client_service::ClientService::new(config::ALERT_URL); | ||
|
||
let mut detection = false; | ||
peripheral_service.led_blink_1_time_long(); | ||
|
||
loop { | ||
if !peripheral_service.is_motion_detected() && detection { | ||
info!("no detection"); | ||
detection = false; | ||
peripheral_service.power_off_output_devices(); | ||
} else if peripheral_service.is_motion_detected() && !detection { | ||
info!("MOVEMENT DETECTED"); | ||
while !peripheral_service.retry_wifi_connection_if_necessary_and_return_status() { | ||
peripheral_service.led_blink_3_time_long(); | ||
thread_util::sleep_short(); | ||
} | ||
let mac_address = peripheral_service.get_mac_address(); | ||
let mac_address = &mac_address.as_str(); | ||
if client_service.post_request(mac_address).is_err() { | ||
peripheral_service.led_blink_2_time_long(); | ||
detection = false; | ||
} else { | ||
peripheral_service.led_blink_1_time_short(); | ||
peripheral_service.buzz_1_time_short(); | ||
detection = true; | ||
} | ||
} | ||
thread_util::sleep_time(20); | ||
} | ||
} |
Oops, something went wrong.