Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9049405
Initial commit
JeffMboya Dec 5, 2025
10523e3
Coordinate federated rounds; validate and aggregate updates
JeffMboya Dec 17, 2025
e384e87
Fix CI
JeffMboya Dec 18, 2025
09bdff6
Implemented a Federated Learning workflow for Propeller
JeffMboya Jan 12, 2026
e111d97
Add tests
JeffMboya Jan 12, 2026
b257262
Add FL to embedded proplet
JeffMboya Jan 13, 2026
1b090eb
Address comments
JeffMboya Jan 13, 2026
3ed6ec1
Address comments
JeffMboya Jan 13, 2026
4c9f120
Address comments
JeffMboya Jan 13, 2026
b8f0e49
Fix CI
JeffMboya Jan 14, 2026
b8670db
Refacftor: make manager workload agnostic
JeffMboya Jan 14, 2026
e356a21
Refacftor: replace http with mqtt
JeffMboya Jan 14, 2026
b37e833
Add FML to embedded proplet
JeffMboya Jan 14, 2026
3510850
Move docs file
JeffMboya Jan 14, 2026
178b7af
Updated client.c
JeffMboya Jan 14, 2026
42c1579
Address comments
JeffMboya Jan 15, 2026
8720959
Fix unused import
JeffMboya Jan 15, 2026
4e37228
Fix unused import
JeffMboya Jan 15, 2026
39643ca
Fix build errors
JeffMboya Jan 15, 2026
b878a82
Fix build errors
JeffMboya Jan 15, 2026
80cbd7d
Add external wasmtime
JeffMboya Jan 15, 2026
758bb17
Fix missing envs
JeffMboya Jan 16, 2026
2ac5cc0
Fix FML round detection logic
JeffMboya Jan 16, 2026
53ad978
Fix result handling in coordinator
JeffMboya Jan 16, 2026
2fb2867
Fix result handling in coordinator
JeffMboya Jan 16, 2026
df21a6b
Add lazy loading to coordinator
JeffMboya Jan 16, 2026
2e9b124
Fix duplicate start command
JeffMboya Jan 16, 2026
c2f90e0
Enhance FML implementation
JeffMboya Jan 17, 2026
c28ebc6
Remove mqtt demo app; add http demo app
JeffMboya Jan 17, 2026
df4359a
Add proplet runtime as an HTTP proxy for WASM client
JeffMboya Jan 17, 2026
b966013
Add Real dataset integration; MQTT notifications when rounds complete
JeffMboya Jan 17, 2026
2b0dbd9
Standardize Coordinator → MQTT Broker (fl/rounds/next) → Clients
JeffMboya Jan 17, 2026
2f831ff
Fix build errors
JeffMboya Jan 18, 2026
cf6160a
Fix local dataset fetch
JeffMboya Jan 18, 2026
8a433a5
Fix proplet ID propagation
JeffMboya Jan 18, 2026
bc29ba2
Fix proplet ID propagation
JeffMboya Jan 18, 2026
022bd2b
Add fl demo application on embedded proplet
JeffMboya Jan 18, 2026
74db6c9
Fix errors
JeffMboya Jan 18, 2026
84436a7
Fix unused imports/functions
JeffMboya Jan 18, 2026
b5de54e
Add requirements.txt
JeffMboya Jan 20, 2026
d2a60d3
Delete train.go
JeffMboya Jan 20, 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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ embed-proplet/bootloader
embed-proplet/modules
embed-proplet/tools
embed-proplet/zephyr

# ML-WASM example generated files
examples/ml-wasm/mymodel.pkl
examples/ml-wasm/mymodel.wasm
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ lint:
golangci-lint run --config .golangci.yaml
cd proplet && cargo check --release && cargo fmt --all -- --check && cargo clippy -- -D warnings

test:
go test -v ./manager -run TestAggregateJSONF64
go test -v ./manager -run TestAggregateConcat
go test -v ./manager -run TestAggregateRound
go test -v ./manager -run TestFLWorkflowIntegration

test-all:
go test -v ./...
cd proplet && cargo test --release

start-supermq:
docker compose -f docker/compose.yaml --env-file docker/.env up -d

Expand All @@ -143,6 +153,8 @@ help:
@echo " install: install the binary i.e copies to GOBIN"
@echo " clean: clean the build directory and Rust target"
@echo " lint: run golangci-lint"
@echo " test: run FL unit and integration tests"
@echo " test-all: run all tests (Go and Rust)"
@echo " dockers: build and push all Docker images (Go and Rust services)"
@echo " dockers_dev: build all Go service dev Docker images"
@echo " dockers_rust: build all Rust service Docker images"
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- 🔧 **WAMR on Zephyr RTOS**: Deploy lightweight Wasm workloads on constrained devices running Zephyr RTOS via the WebAssembly Micro Runtime (WAMR).
- 🛠️ **Powerful Service Mesh**: Integrates with **[SuperMQ](https://github.com/absmach)** for secure, efficient IoT device communication.
- 🔒 **Security at the Core**: Propeller ensures secure workload execution and communication for IoT environments.
- 🤖 **Federated Learning**: Built-in support for federated machine learning workflows with FedAvg aggregation, enabling privacy-preserving distributed training across edge devices.

## 🛠️ How It Works

Expand All @@ -32,6 +33,13 @@ For setup instructions, API references, and usage examples, see the documentatio
- 🛡️ **Secure Workloads**: Run isolated, portable workloads securely on cloud or edge devices.
- 🌎 **Smart Cities**: Power scalable IoT networks with efficient communication and dynamic workloads.
- ☁️ **Serverless Applications**: Deploy FaaS applications leveraging Propeller's Wasm orchestration capabilities.
- 🧠 **Federated Machine Learning**: Train machine learning models across distributed edge devices without exposing raw data, perfect for privacy-sensitive applications.

### Architecture Notes

- **Rust Proplet Only**: Propeller now uses only the Rust proplet implementation (Wasmtime runtime) for executing FL workloads
- **MQTT Communication**: FL coordination uses MQTT topics under `m/{domain}/c/{channel}/control/...`
- **Chunked Transport**: Large model artifacts are automatically chunked for efficient MQTT transport

## 🤝 Contributing

Expand Down
104 changes: 104 additions & 0 deletions cli/fl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package cli

import (
"encoding/json"
"fmt"

"github.com/spf13/cobra"
)

var flCmd = []cobra.Command{
{
Use: "round-start",
Short: "Start a federated learning round",
Long: `Publish a round start message to trigger FL training. This is a sample FML application command.`,
Run: func(cmd *cobra.Command, args []string) {
roundID, _ := cmd.Flags().GetString("round-id")
modelURI, _ := cmd.Flags().GetString("model-uri")
taskWasmImage, _ := cmd.Flags().GetString("task-wasm-image")
participants, _ := cmd.Flags().GetStringSlice("participants")
kOfN, _ := cmd.Flags().GetInt("k-of-n")
timeoutS, _ := cmd.Flags().GetInt("timeout-s")

// Build hyperparams
hyperparams := make(map[string]interface{})
if epochs, _ := cmd.Flags().GetInt("epochs"); epochs > 0 {
hyperparams["epochs"] = epochs
}
if lr, _ := cmd.Flags().GetFloat64("learning-rate"); lr > 0 {
hyperparams["lr"] = lr
}
if batchSize, _ := cmd.Flags().GetInt("batch-size"); batchSize > 0 {
hyperparams["batch_size"] = batchSize
}

// Validate required fields
if roundID == "" {
logErrorCmd(*cmd, fmt.Errorf("round-id is required"))
return
}
if modelURI == "" {
logErrorCmd(*cmd, fmt.Errorf("model-uri is required"))
return
}
if taskWasmImage == "" {
logErrorCmd(*cmd, fmt.Errorf("task-wasm-image is required"))
return
}
if len(participants) == 0 {
logErrorCmd(*cmd, fmt.Errorf("at least one participant is required"))
return
}

// Build round start message
roundStart := map[string]interface{}{
"round_id": roundID,
"model_uri": modelURI,
"task_wasm_image": taskWasmImage,
"participants": participants,
"k_of_n": kOfN,
"timeout_s": timeoutS,
}

if len(hyperparams) > 0 {
roundStart["hyperparams"] = hyperparams
}

roundStartJSON, err := json.MarshalIndent(roundStart, "", " ")
if err != nil {
logErrorCmd(*cmd, err)
return
}

fmt.Println("Round start message (publish to fl/rounds/start):")

Check failure on line 73 in cli/fl.go

View workflow job for this annotation

GitHub Actions / Go Lint and Build

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
fmt.Println(string(roundStartJSON))

Check failure on line 74 in cli/fl.go

View workflow job for this annotation

GitHub Actions / Go Lint and Build

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
fmt.Println("\nNote: This is a sample FML application. Use an MQTT client to publish this message.")

Check failure on line 75 in cli/fl.go

View workflow job for this annotation

GitHub Actions / Go Lint and Build

use of `fmt.Println` forbidden by pattern `^(fmt\.Print(|f|ln)|print|println)$` (forbidigo)
},
},
}

func NewFLCmd() *cobra.Command {
cmd := cobra.Command{
Use: "fl",
Short: "Federated Learning (sample FML application)",
Long: `Sample FML application commands. FL is implemented as an external application, not a core Propeller feature.`,
}

for i := range flCmd {
cmd.AddCommand(&flCmd[i])
}

// Flags for round-start command
roundStartCmd := &flCmd[0]
roundStartCmd.Flags().StringP("round-id", "r", "", "Round identifier (required)")
roundStartCmd.Flags().StringP("model-uri", "m", "", "Model URI (required)")
roundStartCmd.Flags().StringP("task-wasm-image", "i", "", "Task Wasm image OCI ref (required)")
roundStartCmd.Flags().StringSliceP("participants", "p", []string{}, "List of proplet IDs (required)")
roundStartCmd.Flags().IntP("k-of-n", "k", 3, "Minimum participants required for aggregation")
roundStartCmd.Flags().IntP("timeout-s", "t", 30, "Round timeout in seconds")
roundStartCmd.Flags().IntP("epochs", "e", 1, "Local training epochs")
roundStartCmd.Flags().Float64P("learning-rate", "l", 0.01, "Learning rate")
roundStartCmd.Flags().IntP("batch-size", "b", 16, "Batch size")

return &cmd
}
3 changes: 2 additions & 1 deletion cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ func main() {

tasksCmd := cli.NewTasksCmd()
provisionCmd := cli.NewProvisionCmd()
flCmd := cli.NewFLCmd()

rootCmd.AddCommand(tasksCmd, provisionCmd)
rootCmd.AddCommand(tasksCmd, provisionCmd, flCmd)

rootCmd.PersistentFlags().StringVarP(
&managerURL,
Expand Down
3 changes: 3 additions & 0 deletions docker/Dockerfile.proplet
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ WORKDIR /build

RUN apk add --no-cache \
musl-dev \
openssl-dev \
openssl-libs-static \
pkgconfig \
upx

COPY proplet/ ./
Expand Down
5 changes: 4 additions & 1 deletion embed-proplet/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ CONFIG_NET_MAX_CONTEXTS=10

# MQTT Client
CONFIG_MQTT_LIB=y
# Enable Sockets (used by MQTT lib)
# Enable Sockets (used by MQTT lib and HTTP client)
CONFIG_NET_SOCKETS=y
# HTTP Client support
CONFIG_HTTP_CLIENT=y
CONFIG_HTTP_CLIENT_BUFFER_SIZE=4096

# Uncomment to enable TLS support for socket MQTT Library.
# CONFIG_MQTT_LIB_TLS=y
Expand Down
Loading
Loading