contact_sensor (0.1.0)

Published 2026-03-07 20:25:55 +00:00 by faicel

Installation

[registries.forgejo]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add contact_sensor@0.1.0 --registry forgejo

About this package

Contact sensor logic with encryption for IoT security systems

Contact Sensor Library

Portable Rust no_std library for IoT contact sensors with encryption.

Overview

contact_sensor provides reusable business logic for contact sensors (door, window, etc.) with encrypted LoRa communication. This library is portable and runs on any microcontroller that supports embedded Rust.

Features

  • Cryptography: Key derivation with HKDF-SHA256
  • State machine: Robust system state management
  • Testable: Automated tests on host target
  • Portable: no_std, works on any MCU
  • Flexible: Uses embedded-hal for hardware abstraction

Installation

Add to your Cargo.toml:

[dependencies]
contact_sensor = { path = "../libs/contact_sensor" }

Usage

Module config: Key management

use contact_sensor::config;

// Get the master key
let master_key = config::get_master_key();

// Derive an installation key
let install_key = config::derive_install_key();

Module state: State machine

use contact_sensor::state::{StateMachine, SystemState};

// Create a new state machine
let mut sm = StateMachine::new(SystemState::NotInstalled);

// Transitions
sm.set_installed();  // NotInstalled → Installed
sm.set_alarm();      // Installed → Alarm
sm.clear_alarm();    // Alarm → Installed

// Check state
if sm.current().is_alarm_active() {
    println!("Alarm active!");
}

Module alarm: Alarm control

use contact_sensor::alarm::AlarmController;

// With your specific HAL
let led = pins.pa21.into_push_pull_output();
let buzzer = pins.pa22.into_push_pull_output();
let mut alarm = AlarmController::new(led, buzzer);

// Activate alarm
alarm.activate().unwrap();

// Deactivate alarm
alarm.deactivate().unwrap();

// Toggle
alarm.toggle().unwrap();

Module timeout: Timeout handling

use contact_sensor::timeout::{with_timeout_and_retry, TimeoutResult};

let mut delay = hal::delay::Delay::new(core_peripherals.SYST, clocks);

let result = with_timeout_and_retry(
    || send_lora_message(),
    1000,  // timeout ms
    3,     // max retries
    500,   // retry delay ms
    &mut delay
);

match result {
    TimeoutResult::Success(value) => println!("Success!"),
    TimeoutResult::Error => println!("Failed after retries"),
    TimeoutResult::Timeout => println!("Timeout"),
}

Tests

Run tests on the host target:

# All tests
cargo test --features std

# Specific test suites
cargo test --test config_tests
cargo test --test state_tests
cargo test --test alarm_tests
cargo test --test timeout_tests

Result: 32 tests pass

  • 7 tests for config (cryptography)
  • 6 tests for state (state machine)
  • 6 tests for alarm (LED/buzzer control with embedded-hal-mock)
  • 8 tests for timeout (timeout/retry handling with embedded-hal-mock)
  • 5 doctests

Modules

Module Description Tests
config Key management (HKDF-SHA256) 7
state State machine (NotInstalled → Installed → Alarm) 6
alarm Alarm control (LED + Buzzer, embedded-hal) 6
timeout Timeout and retry handling (embedded-hal) 8

Firmware integration

Example with RTIC (SAMD21)

// Cargo.toml
[dependencies]
contact_sensor = { path = "../libs/contact_sensor" }
atsamd-hal = "0.22.2"
rtic = "2.2.0"

// main.rs
use contact_sensor::{config, state};

#[rtic::app]
mod app {
    use super::*;

    #[shared]
    struct Shared {
        state_machine: state::StateMachine,
    }

    #[init]
    fn init(cx: init::Context) -> (Shared, Local) {
        // Use contact_sensor logic
        let install_key = config::derive_install_key();
        let state_machine = state::StateMachine::new(
            state::SystemState::NotInstalled
        );

        (Shared { state_machine }, Local {})
    }
}

Example with Embassy (ESP32)

use contact_sensor::{config, state};
use embassy_executor::Spawner;

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let mut sm = state::StateMachine::new(state::SystemState::NotInstalled);
    let key = config::derive_install_key();

    // Your logic...
}

Architecture

┌─────────────────────────────────────────────┐
│  contact_sensor (portable lib)              │
│  - config: Key management                   │
│  - state: State machine                     │
│  - alarm: Alarm (embedded-hal)              │
└─────────────────────────────────────────────┘
                   ▲
                   │ used by
                   │
┌─────────────────────────────────────────────┐
│  Specific firmware (SAMD21, ESP32, etc.)    │
│  - RTIC / Embassy / bare-metal              │
│  - Specific HAL                              │
│  - Hardware configuration                    │
└─────────────────────────────────────────────┘

Documentation

Generate full documentation:

cargo doc --no-default-features --features std --open

Security

Important: The MASTER_KEY is hardcoded for development. In production:

  • Use a Secure Element (e.g. ATECC608A)
  • Load from encrypted storage
  • Never commit production keys

License

Personal Use Only — Non-Commercial (see LICENSE).

Author

Faicel - faicelbhk@gmail.com

Contributing

Contributions are welcome. This library is designed to be generic and reusable.

Dependencies

ID Version
embedded-hal ^1.0
hkdf ^0.12
sha2 ^0.10
embedded-hal-mock ^0.11
Details
Cargo
2026-03-07 20:25:55 +00:00
10
faicel <faicelbhk@gmail.com>
14 KiB
Assets (1)
Versions (1) View all
0.1.0 2026-03-07