Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
0a1edc2
Rework provisioning to async
MathiasKoch Jan 4, 2024
f64903a
Working async provisioning based on embedded-mqtt with integration test
MathiasKoch Jan 6, 2024
cadf3d3
Rework topic formatting slightly
MathiasKoch Jan 6, 2024
548be76
Get rid of additional stack allocation for ownership token
MathiasKoch Jan 6, 2024
e81fd6f
Reenable jobs
MathiasKoch Jan 6, 2024
cd14fc8
Rewrite OTA to async
MathiasKoch Jan 8, 2024
4a09047
Working OTA
MathiasKoch Jan 9, 2024
531d6f1
Formatting
MathiasKoch Jan 9, 2024
eaa82b8
Fully working OTA integration test
MathiasKoch Jan 11, 2024
20f9db9
Clean up OTA integration test, make sure it reports success and add m…
MathiasKoch Jan 11, 2024
f3742a4
Use stable 1.75
MathiasKoch Jan 18, 2024
505bb2c
use git embedded-mqtt
MathiasKoch Jan 18, 2024
f225c96
Fix defmt feature
MathiasKoch Jan 18, 2024
7edb08c
Add support for provisioning by CSR to the Fleet Provisioner
MathiasKoch Mar 15, 2024
e225b1f
Update embedded-mqtt dependency
MathiasKoch May 31, 2024
20ece31
Bump embedded-mqtt, and use DeferredPayload
MathiasKoch Jun 11, 2024
34dc52f
Temporarilly subscribe to only accepted topic
MathiasKoch Jun 20, 2024
604ca46
Bump embedded-mqtt
MathiasKoch Jul 18, 2024
d6d4af3
Fix provisioning topic resulting in status code 143, by subscribing t…
MathiasKoch Jul 19, 2024
f424608
Reduce the overhead of of CreateCertificateFromCsr buffer size
MathiasKoch Jul 19, 2024
f924e1e
Feature/async shadows (#57)
MathiasKoch Sep 25, 2024
1763f6c
Add report fn to persisted shadows
MathiasKoch Sep 26, 2024
967c0b5
OTA tests pass again after rewrite
MathiasKoch Oct 3, 2024
16bdbca
Add more docs
MathiasKoch Oct 3, 2024
bb34d44
Update CI actions
MathiasKoch Oct 3, 2024
916296e
Remove local patch
MathiasKoch Oct 3, 2024
d712932
Make sure OTA request momentum is not running prior to subscription
MathiasKoch Oct 4, 2024
01c44a0
Fix(async): Ensure one sub on topic (#64)
KennethKnudsen97 Oct 10, 2024
c3456cd
bump embedded mqtt
KennethKnudsen97 Oct 10, 2024
2378458
Fix OTA & bump dependencies (#67)
MathiasKoch Oct 29, 2024
798f496
Change default block size, and update frequency
MathiasKoch Nov 6, 2024
f942b03
Enhancement: Replace serde_cbor with minicbor (#68)
KennethKnudsen97 Nov 6, 2024
7e7eab8
Fix minicbor serialize returning number of written bytes correctly
MathiasKoch Nov 21, 2024
2c5757d
Bump embassy dependencies to newly released versions
MathiasKoch Jan 13, 2025
3e2cad0
remove locks (#71)
KennethKnudsen97 Feb 6, 2025
9103492
Feature: Implement defender metrics (#70)
KennethKnudsen97 Feb 7, 2025
6f75c9d
Fix(async): Get shadow on startup (#72)
KennethKnudsen97 Feb 21, 2025
4c902a1
drop dao to avoid deadlock (#73)
KennethKnudsen97 Feb 24, 2025
97ed216
better error handling (#74)
KennethKnudsen97 Feb 25, 2025
806832a
bumb embedded mqtt to fix issue with clean session on interface chang…
KennethKnudsen97 Mar 11, 2025
22b38d6
feature(shadows): Rewrite shadow derive, and add support for deriving…
MathiasKoch Mar 17, 2025
505fcdb
Use next_message instead of next, to make sure we resubscribe on clea…
MathiasKoch Mar 19, 2025
cde74d3
resub on clean session (#78)
KennethKnudsen97 Apr 11, 2025
c547e5f
bump mqtt (#79)
KennethKnudsen97 May 7, 2025
1264a8c
add update desired (#80)
KennethKnudsen97 Jun 19, 2025
e602b4e
bump embassy and higher topic length
KennethKnudsen97 Sep 16, 2025
d7fef0c
bumb mqtt and embasys
KennethKnudsen97 Sep 17, 2025
cd0cfb7
bumb embedded-mqtt
KennethKnudsen97 Sep 18, 2025
d6852b9
bump embedded mqtt
KennethKnudsen97 Sep 23, 2025
00f12fb
bump embedded-mqtt
KennethKnudsen97 Sep 25, 2025
f31b093
bump embedded tls
KennethKnudsen97 Sep 26, 2025
ac16ab8
fix bump
KennethKnudsen97 Sep 26, 2025
81e5104
properly handle escape characters
Nov 12, 2025
1599f63
Update dependencies for compatibility
Nov 13, 2025
75e8b79
bump toolchain
Nov 19, 2025
3ee9dd5
fix resubscribe on clean session
Nov 28, 2025
20b9bf2
bump embedded mqtt
Nov 28, 2025
1d4a7c0
use next_message instead of next as next_message breaks on clean sess…
Dec 3, 2025
3f78ef0
add rejected on register device. add write dao on report shadow
Dec 22, 2025
3977b6d
Merge branch 'master' into feature/async
MathiasKoch Feb 17, 2026
f85cf7b
Use mqttrust git dependency
MathiasKoch Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 91 additions & 55 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,89 +6,125 @@ on:
- master
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
ALL_FEATURES: "ota_mqtt_data,ota_http_data"

jobs:
cancel_previous_runs:
name: Cancel previous runs
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: styfle/cancel-workflow-action@0.4.1
with:
access_token: ${{ secrets.GITHUB_TOKEN }}

- name: Checkout source code
uses: actions/checkout@v4

- uses: dsherret/rust-toolchain-file@v1

- name: Build (library)
run: cargo build --all --target thumbv7em-none-eabihf

test:
name: Build & Test
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4

- uses: dsherret/rust-toolchain-file@v1
- name: Build

- name: Doc Tests
uses: actions-rs/cargo@v1
with:
command: build
args: --all --target thumbv7em-none-eabihf --features ${{ env.ALL_FEATURES }}
command: test
args: --doc --features "std,log"

- name: Macro Tests
uses: actions-rs/cargo@v1
with:
command: test
args: -p rustot-derive

- name: Test
- name: Unit Tests
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --features "ota_mqtt_data,log"
args: --lib --features "std,log"

rustfmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3

uses: actions/checkout@v4
- uses: dsherret/rust-toolchain-file@v1
- name: Rustfmt
run: cargo fmt -- --check

- name: Run rustfmt (library)
run: cargo fmt --all -- --check --verbose

# - name: Run rustfmt (examples)
# run: |
# for EXAMPLE in $(ls examples);
# do
# (cd examples/$EXAMPLE && cargo fmt --all -- --check --verbose)
# done

clippy:
name: clippy
runs-on: ubuntu-latest
env:
CLIPPY_PARAMS: -W clippy::all -W clippy::pedantic -W clippy::nursery -W clippy::cargo
steps:
- name: Checkout source code
uses: actions/checkout@v3
- uses: dsherret/rust-toolchain-file@v1
- name: Run clippy
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: -- ${{ env.CLIPPY_PARAMS }}

integration-test:
name: Integration Tests
runs-on: ubuntu-latest
needs: ['test', 'rustfmt', 'clippy']
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- uses: dsherret/rust-toolchain-file@v1
- name: Create OTA Job
run: |
./scripts/create_ota.sh
env:
AWS_DEFAULT_REGION: ${{ secrets.MGMT_AWS_DEFAULT_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.MGMT_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.MGMT_AWS_SECRET_ACCESS_KEY }}
- name: Integration Tests
uses: actions-rs/cargo@v1
with:
command: test
args: --test '*' --features "ota_mqtt_data,log" --target x86_64-unknown-linux-gnu
env:
IDENTITY_PASSWORD: ${{ secrets.DEVICE_ADVISOR_PASSWORD }}
AWS_HOSTNAME: a1vq3mi5y3c6j5-ats.iot.eu-west-1.amazonaws.com

- name: Cleanup OTA Jobs
if: ${{ always() }}
run: |
./scripts/cleanup_ota.sh
env:
AWS_DEFAULT_REGION: ${{ secrets.MGMT_AWS_DEFAULT_REGION }}
AWS_ACCESS_KEY_ID: ${{ secrets.MGMT_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.MGMT_AWS_SECRET_ACCESS_KEY }}

- name: Run clippy (library)
run: cargo clippy --features "log" -- ${{ env.CLIPPY_PARAMS }}

# - name: Run clippy (examples)
# run: |
# for EXAMPLE in $(ls examples);
# do
# (cd examples/$EXAMPLE && cargo clippy -- ${{ env.CLIPPY_PARAMS }})
# done

# integration-test:
# name: Integration Tests
# runs-on: ubuntu-latest
# needs: ["build", "test", "rustfmt", "clippy"]
# steps:
# - name: Checkout source code
# uses: actions/checkout@v4

# - uses: dsherret/rust-toolchain-file@v1

# - name: Create OTA Job
# run: |
# ./scripts/create_ota.sh
# env:
# AWS_DEFAULT_REGION: ${{ secrets.MGMT_AWS_DEFAULT_REGION }}
# AWS_ACCESS_KEY_ID: ${{ secrets.MGMT_AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.MGMT_AWS_SECRET_ACCESS_KEY }}

# - name: Integration Tests
# uses: actions-rs/cargo@v1
# with:
# command: test
# args: --test '*' --features "ota_mqtt_data,log" --target x86_64-unknown-linux-gnu
# env:
# IDENTITY_PASSWORD: ${{ secrets.IDENTITY_PASSWORD }}
# AWS_HOSTNAME: a1vq3mi5y3c6j5-ats.iot.eu-west-1.amazonaws.com

# - name: Cleanup OTA Jobs
# if: ${{ always() }}
# run: |
# ./scripts/cleanup_ota.sh
# env:
# AWS_DEFAULT_REGION: ${{ secrets.MGMT_AWS_DEFAULT_REGION }}
# AWS_ACCESS_KEY_ID: ${{ secrets.MGMT_AWS_ACCESS_KEY_ID }}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.MGMT_AWS_SECRET_ACCESS_KEY }}
8 changes: 5 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.cargo.features": ["log"],
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu"
"rust-analyzer.cargo.features": [
"log",
"ota_mqtt_data"
],
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu",
}
89 changes: 59 additions & 30 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[workspace]
members = ["shadow_derive"]
members = ["rustot_derive"]

[package]
name = "rustot"
version = "0.4.1"
authors = ["Mathias Koch <mk@blackbird.online>"]
version = "0.5.0"
authors = ["Factbird team <support@factbird.com>"]
description = "AWS IoT"
readme = "README.md"
keywords = ["iot", "no-std"]
categories = ["embedded", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/BlackbirdHQ/rustot"
repository = "https://github.com/FactbirdHQ/rustot"
edition = "2021"
documentation = "https://docs.rs/rustot"
exclude = ["/documentation"]
Expand All @@ -22,48 +22,77 @@ name = "rustot"
maintenance = { status = "actively-developed" }

[dependencies]
bitmaps = { version = "^3.1", default-features = false }
heapless = { version = "0.7.0", features = ["serde"] }
mqttrust = { version = "0.6" }
nb = "1"
serde = { version = "1.0.126", default-features = false, features = ["derive"] }
serde-json-core = { version = "0.4.0" }
bitmaps = { version = "3.1", default-features = false }
heapless = { version = "0.9", features = ["serde"] }
serde = { version = "1.0", default-features = false, features = ["derive"] }

minicbor = { version = "0.25", optional = true }
minicbor-serde = { version = "0.3.2", optional = true }

smlang = "0.5.0"
fugit-timer = "0.1.2"
shadow-derive = { path = "shadow_derive", version = "0.2.1" }
embedded-storage = "0.3.0"

log = { version = "^0.4", default-features = false, optional = true }
defmt = { version = "^0.3", optional = true }
serde-json-core = { version = "0.6" }
rustot-derive = { path = "rustot_derive", version = "0.2.1" }
embedded-storage-async = "0.4"
mqttrust = { git = "https://github.com/FactbirdHQ/mqttrust", rev = "6c33c59" }

futures = { version = "0.3.28", default-features = false }

embassy-time = { version = "0.5.0" }
embassy-sync = "0.7.2"
embassy-futures = "0.1.2"

log = { version = "0.4", default-features = false, optional = true }
defmt = { version = "0.3", optional = true }
bon = { version = "3.3.2", default-features = false }

[dev-dependencies]
native-tls = { version = "^0.2" }
embedded-nal = "0.6.0"
no-std-net = { version = "^0.5", features = ["serde"] }
dns-lookup = "1.0.3"
mqttrust_core = { version = "0.6", features = ["log"] }
env_logger = "0.9.0"
native-tls = { version = "0.2" }
embedded-nal-async = "0.9"
env_logger = "0.11"
sha2 = "0.10.1"
ecdsa = { version = "0.13.4", features = ["pkcs8"] }
p256 = "0.10.1"
pkcs8 = { version = "0.8", features = ["encryption", "pem"] }
timebomb = "0.1.2"
hex = "0.4.3"
static_cell = { version = "2", features = ["nightly"] }
log = { version = "0.4" }
serde_json = "1"

tokio = { version = "1.33", default-features = false, features = [
"macros",
"rt",
"net",
"time",
"io-std",
] }
tokio-native-tls = { version = "0.3.1" }
embassy-futures = { version = "0.1.2" }
embassy-time = { version = "0.5", features = ["log", "std", "generic-queue-8"] }
embedded-io-adapters = { version = "0.7.0", features = ["tokio-1"] }

ecdsa = { version = "0.16", features = ["pkcs8", "pem"] }
p256 = "0.13"
pkcs8 = { version = "0.10", features = ["encryption", "pem"] }
hex = { version = "0.4.3", features = ["alloc"] }


[features]
default = ["ota_mqtt_data", "provision_cbor"]
default = ["ota_mqtt_data", "metric_cbor", "provision_cbor"]

metric_cbor = ["dep:minicbor", "dep:minicbor-serde"]

provision_cbor = ["dep:minicbor", "dep:minicbor-serde"]

ota_mqtt_data = ["dep:minicbor", "dep:minicbor-serde"]

ota_http_data = []

std = ["serde/std", "minicbor-serde?/std"]

defmt = ["dep:defmt", "mqttrust/defmt-impl", "heapless/defmt-impl"]
defmt = [
"dep:defmt",
"heapless/defmt",
"mqttrust/defmt",
"embassy-time/defmt",
]
log = ["dep:log", "mqttrust/log"]


graphviz = ["smlang/graphviz"]
# [patch."ssh://git@github.com/FactbirdHQ/mqttrust"]
# mqttrust = { path = "../mqttrust" }
57 changes: 21 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,36 @@
# Rust of things (rustot)
# Rust of Things (rustot)

> A `no_std`, `no_alloc` crate for interacting with AWS IoT services on embedded devices.

**Work in progress**
This crate aims to provide a pure-Rust implementation of essential AWS IoT features for embedded systems, inspired by the Amazon FreeRTOS AWS IoT Device SDK.

> no_std, no_alloc crate for AWS IoT Devices, implementing Jobs, OTA, Device Defender and IoT Shadows
## Features

This crates strives to implement the sum of:
- [AWS OTA](https://github.com/aws/ota-for-aws-iot-embedded-sdk)
- [AWS Device Defender](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk)
- [AWS Jobs](https://github.com/aws/Jobs-for-AWS-IoT-embedded-sdk)
- [AWS Device Shadow](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk)
- [AWS IoT Fleet Provisioning](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk)
- **OTA Updates:** ([`ota`] module)
- Download and apply firmware updates securely over MQTT or HTTP.
- Supports both CBOR and raw binary firmware formats.
- **Device Shadow:** ([`shadows`] module)
- Synchronize device state with the cloud using AWS IoT Device Shadow service.
- Get, update, and delete device shadows.
- **Jobs:** ([`jobs`] module)
- Receive and execute jobs remotely on your devices.
- Track job status and report progress to AWS IoT.
- **Device Defender:** ([`defender_metrics`] module)
- Implement security best practices and detect anomalies on your devices.
- **Fleet Provisioning:** ([`provisioning`] module)
- Securely provision and connect devices to AWS IoT at scale.
- **Lightweight and `no_std`:** Designed specifically for resource-constrained embedded devices.

## Contributing

![Test][test]
[![Code coverage][codecov-badge]][codecov]
![No Std][no-std-badge]
[![Crates.io Version][crates-io-badge]][crates-io]
[![Crates.io Downloads][crates-io-download-badge]][crates-io-download]

Any contributions will be welcomed! Even if they are just suggestions, bugs or reviews!

This is a port of the Amazon-FreeRTOS AWS IoT Device SDK (https://github.com/nguyenvuhung/amazon-freertos/tree/master/libraries/freertos_plus/aws/ota), written in pure Rust.

It is written to work with [mqttrust](https://github.com/BlackbirdHQ/mqttrust), but should work with any other mqtt client, that implements the [Mqtt trait](https://github.com/BlackbirdHQ/mqttrust/blob/master/mqttrust/src/lib.rs) from mqttrust.


## Tests

> The crate is covered by tests. These tests can be run by `cargo test --tests --all-features`, and are run by the CI on every push to master.
Contributions, suggestions, bug reports, and reviews are highly appreciated!

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.
Expand All @@ -45,13 +40,3 @@ at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

<!-- Badges -->
[test]: https://github.com/BlackbirdHQ/rustot/workflows/Test/badge.svg
[no-std-badge]: https://img.shields.io/badge/no__std-yes-blue
[codecov-badge]: https://codecov.io/gh/BlackbirdHQ/rustot/branch/master/graph/badge.svg
[codecov]: https://codecov.io/gh/BlackbirdHQ/rustot
[crates-io]: https://crates.io/crates/rustot
[crates-io-badge]: https://img.shields.io/crates/v/rustot.svg?maxAge=3600
[crates-io-download]: https://crates.io/crates/rustot
[crates-io-download-badge]: https://img.shields.io/crates/d/rustot.svg?maxAge=3600
Loading