Add Fabric Synchronization Guide (#34195)
* Add Fabric Synchronization Guide
* Update docs/guides/fabric_synchronization_guide.md
Co-authored-by: Andrei Litvin <andy314@gmail.com>
* Address review comments
* Update docs/guides/fabric_synchronization_guide.md
Co-authored-by: Andrei Litvin <andy314@gmail.com>
* Update scripts with mutiple pathes
* grep for /fabric-bridge-app without the prefix
---------
Co-authored-by: Andrei Litvin <andy314@gmail.com>
diff --git a/docs/guides/fabric_synchronization_guide.md b/docs/guides/fabric_synchronization_guide.md
new file mode 100644
index 0000000..3610774
--- /dev/null
+++ b/docs/guides/fabric_synchronization_guide.md
@@ -0,0 +1,164 @@
+# Fabric Synchronization Guide
+
+- [Fabric Synchronization Guide](#fabric-synchronization-guide)
+ - [Fabric Sync Example Applications](#fabric-sync-example-applications)
+ - [Run Fabric Sync Demo on RP4](#run-fabric-sync-demo-on-rp4)
+
+## Fabric Sync Example Applications
+
+Fabric-Admin and Fabric-Bridge example applications are provided to demonstrate
+Fabric Synchronization feature. You can find them in the examples.
+
+
+
+Fabric-Admin example app implements the Fabric Administrator role and
+communicates with the Fabric-Bridge-App on the other side, facilitating the
+Fabric Synchronization process.
+
+Fabric-Bridge-App example app implements the Aggregator device type with Fabric
+Synchronization condition met and demonstrates the end-to-end Fabric
+Synchronization feature using dynamic endpoints.
+
+Fabric Synchronization can be triggered from either side. The initiator of the
+Fabric Synchronization process, who shares their devices, takes on the
+Commissioner role. The recipient of the Fabric Synchronization request, who
+receives the shared devices, assumes the Commissionee role. This flexibility
+enables a seamless and efficient synchronization process.
+
+### Building the Example Application
+
+- Building the Fabric-Admin Application
+
+ [Fabric-Admin](https://github.com/project-chip/connectedhomeip/tree/master/examples/fabric-admin/README.md)
+
+* Building the Fabric-Bridge Application
+
+ [Fabric-Bridge](https://github.com/project-chip/connectedhomeip/tree/master/examples/fabric-bridge-app/linux/README.md)
+
+## Run Fabric Sync Demo on RP4
+
+### Setup Fabric Source
+
+Connect to the Fabric Source server:
+
+```
+ssh ubuntu@xxx.xxx.xxx.xxx
+```
+
+Password: <password>
+
+Run the Fabric Source script:
+
+```
+./run_fabric_source.sh
+```
+
+### Setup Fabric Sink
+
+Connect to the Fabric Sink server:
+
+```
+ssh ubuntu@xxx.xxx.xxx.xxx
+```
+
+Password: <password>
+
+Run the Fabric Sink script:
+
+```
+./run_fabric_sink.sh
+```
+
+### Fabric Sync Setup
+
+Enable Fabric Auto Sync:
+
+In Fabric-Sync console:
+
+```
+fabricsync enable-auto-sync 1
+```
+
+Pair the Fabric-Source bridge to Fabric-Sync with node ID 1:
+
+```
+fabricsync add-bridge 1 <fabric-sink-ip>
+```
+
+### Pair Light Example to Fabric-Source
+
+Pair the Light Example with node ID 3 using its payload number:
+
+```
+pairing already-discovered 3 20202021 <ip> 5540
+```
+
+After the Light Example is successfully paired in Fabric-Source, it will be
+synced to Fabric-Sink with a new assigned node ID.
+
+Toggle the Light Example:
+
+From Fabric-Source:
+
+```
+onoff on <node-id> 1
+onoff off <node-id> 1
+```
+
+From Fabric-Sink: (Use the node ID assigned)
+
+```
+onoff on x 1
+onoff off x 1
+```
+
+### Remove Light Example from Fabric-Source
+
+Unpair the Light Example:
+
+```
+pairing unpair <node-id>
+```
+
+After the Light Example is successfully unpaired from Fabric-Source, it will
+also be removed from the Fabric-Sink.
+
+### Pair Commercial Switch to Fabric-Source
+
+Pair the switch using its payload number:
+
+In Fabric-Source console:
+
+```
+pairing code-wifi <node-id> <ssid> <passwd> <payload>
+```
+
+After the switch is successfully paired in Fabric-Source, it will be synced to
+Fabric-Sink with a new assigned node ID.
+
+Toggle the switch:
+
+From Fabric-Source:
+
+```
+onoff on <node-id> 1
+onoff off <node-id> 1
+```
+
+From Fabric-Sink: (Use the node ID assigned)
+
+```
+onoff on <node-id> 1
+onoff off <node-id> 1
+```
+
+### Remove Switch from Fabric-Source
+
+Unpair the switch:
+
+```
+pairing unpair <node-id>
+```
+
+After the switch is successfully unpaired from Fabric-Source, it will also be
+removed from the Fabric-Sink.
diff --git a/docs/guides/images/matter_fabric_synchronization.png b/docs/guides/images/matter_fabric_synchronization.png
new file mode 100644
index 0000000..95c99c4
--- /dev/null
+++ b/docs/guides/images/matter_fabric_synchronization.png
Binary files differ
diff --git a/examples/fabric-admin/scripts/run_fabric_sink.sh b/examples/fabric-admin/scripts/run_fabric_sink.sh
new file mode 100755
index 0000000..3013965
--- /dev/null
+++ b/examples/fabric-admin/scripts/run_fabric_sink.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Default paths
+DEFAULT_CHOICES=(
+ "./fabric-admin"
+ "out/debug/standalone/fabric-admin"
+ "out/linux-x64-fabric-admin/fabric-admin"
+ "out/darwin-arm64-fabric-admin/fabric-admin"
+)
+FABRIC_ADMIN_LOG="/tmp/fabric_admin.log"
+FABRIC_ADMIN_PATH=""
+
+# Function to find fabric-admin binary
+find_fabric_admin() {
+ local choices=("$@")
+ for path in "${choices[@]}"; do
+ if [[ -e "$path" ]]; then
+ echo "$path"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Parse arguments
+VERBOSE=false
+SPECIFIED_PATH=""
+
+for arg in "$@"; do
+ case $arg in
+ --verbose)
+ VERBOSE=true
+ ;;
+ --path=*)
+ SPECIFIED_PATH="${arg#*=}"
+ ;;
+ esac
+done
+
+# Use specified path if provided
+if [[ -n "$SPECIFIED_PATH" ]]; then
+ if [[ -e "$SPECIFIED_PATH" ]]; then
+ FABRIC_ADMIN_PATH="$SPECIFIED_PATH"
+ else
+ echo >&2 "Specified path does not exist: $SPECIFIED_PATH"
+ exit 1
+ fi
+else
+ FABRIC_ADMIN_PATH=$(find_fabric_admin "${DEFAULT_CHOICES[@]}")
+ if [[ $? -ne 0 ]]; then
+ echo >&2 "Could not find the fabric-admin binary"
+ exit 1
+ fi
+fi
+
+echo "PATH IS: $FABRIC_ADMIN_PATH"
+
+# Kill fabric-admin if it is running
+echo "Checking for running fabric-admin process..."
+fabric_admin_pid=$(pgrep -f "$FABRIC_ADMIN_PATH")
+if [[ -n "$fabric_admin_pid" ]]; then
+ echo "Found fabric-admin with PID $fabric_admin_pid, attempting to kill..."
+ kill -9 "$fabric_admin_pid"
+ echo "Killed fabric-admin with PID $fabric_admin_pid"
+fi
+
+# Remove /tmp/chip_* files and directories
+echo "Removing /tmp/chip_* files and directories..."
+sudo rm -rf /tmp/chip_*
+echo "Removed /tmp/chip_* files and directories"
+
+# Start fabric-admin with or without log file path based on --verbose option
+echo "Starting fabric-admin..."
+if [ "$VERBOSE" = true ]; then
+ "$FABRIC_ADMIN_PATH"
+else
+ "$FABRIC_ADMIN_PATH" --log-file-path "$FABRIC_ADMIN_LOG"
+fi
diff --git a/examples/fabric-admin/scripts/run_fabric_source.sh b/examples/fabric-admin/scripts/run_fabric_source.sh
new file mode 100755
index 0000000..95df7a1
--- /dev/null
+++ b/examples/fabric-admin/scripts/run_fabric_source.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+# Get the path to the current script
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Default paths
+DEFAULT_ADMIN_CHOICES=(
+ "./fabric-admin"
+ "out/debug/standalone/fabric-admin"
+ "out/linux-x64-fabric-admin/fabric-admin"
+ "out/darwin-arm64-fabric-admin/fabric-admin"
+)
+DEFAULT_BRIDGE_CHOICES=(
+ "./fabric-bridge-app"
+ "out/debug/standalone/fabric-bridge-app"
+ "out/linux-x64-fabric-bridge-app/fabric-bridge-app"
+ "out/darwin-arm64-fabric-bridge-app/fabric-bridge-app"
+)
+FABRIC_ADMIN_LOG="/tmp/fabric_admin.log"
+FABRIC_BRIDGE_APP_LOG="/tmp/fabric_bridge_app.log"
+FABRIC_ADMIN_PATH=""
+FABRIC_BRIDGE_APP_PATH=""
+
+# Function to find a binary
+find_binary() {
+ local choices=("$@")
+ for path in "${choices[@]}"; do
+ if [[ -e "$path" ]]; then
+ echo "$path"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Parse arguments
+VERBOSE=false
+SPECIFIED_ADMIN_PATH=""
+SPECIFIED_BRIDGE_PATH=""
+
+for arg in "$@"; do
+ case $arg in
+ --verbose)
+ VERBOSE=true
+ ;;
+ --admin-path=*)
+ SPECIFIED_ADMIN_PATH="${arg#*=}"
+ ;;
+ --bridge-path=*)
+ SPECIFIED_BRIDGE_PATH="${arg#*=}"
+ ;;
+ esac
+done
+
+# Use specified paths if provided
+if [[ -n "$SPECIFIED_ADMIN_PATH" ]]; then
+ if [[ -e "$SPECIFIED_ADMIN_PATH" ]]; then
+ FABRIC_ADMIN_PATH="$SPECIFIED_ADMIN_PATH"
+ else
+ echo >&2 "Specified admin path does not exist: $SPECIFIED_ADMIN_PATH"
+ exit 1
+ fi
+else
+ FABRIC_ADMIN_PATH=$(find_binary "${DEFAULT_ADMIN_CHOICES[@]}")
+ if [[ $? -ne 0 ]]; then
+ echo >&2 "Could not find the fabric-admin binary"
+ exit 1
+ fi
+fi
+
+if [[ -n "$SPECIFIED_BRIDGE_PATH" ]]; then
+ if [[ -e "$SPECIFIED_BRIDGE_PATH" ]]; then
+ FABRIC_BRIDGE_APP_PATH="$SPECIFIED_BRIDGE_PATH"
+ else
+ echo >&2 "Specified bridge path does not exist: $SPECIFIED_BRIDGE_PATH"
+ exit 1
+ fi
+else
+ FABRIC_BRIDGE_APP_PATH=$(find_binary "${DEFAULT_BRIDGE_CHOICES[@]}")
+ if [[ $? -ne 0 ]]; then
+ echo >&2 "Could not find the fabric-bridge-app binary"
+ exit 1
+ fi
+fi
+
+echo "Admin path: $FABRIC_ADMIN_PATH"
+echo "Bridge path: $FABRIC_BRIDGE_APP_PATH"
+
+# Determine the path to stop_fabric_source.sh based on the location of run_fabric_source.sh
+RUN_FABRIC_SOURCE_PATH=$(find_binary "$SCRIPT_DIR/run_fabric_source.sh")
+if [[ $? -ne 0 ]]; then
+ echo >&2 "Could not find the run_fabric_source.sh script"
+ exit 1
+fi
+STOP_FABRIC_SOURCE_PATH="${RUN_FABRIC_SOURCE_PATH/run_fabric_source/stop_fabric_source}"
+
+# Stop any running instances and clean up
+if [[ -e "$STOP_FABRIC_SOURCE_PATH" ]]; then
+ "$STOP_FABRIC_SOURCE_PATH"
+else
+ echo >&2 "Could not find the stop_fabric_source.sh script"
+ exit 1
+fi
+
+# Start fabric-bridge-app if available and redirect its output to /dev/null
+if [ -f "$FABRIC_BRIDGE_APP_PATH" ]; then
+ "$FABRIC_BRIDGE_APP_PATH" >"$FABRIC_BRIDGE_APP_LOG" 2>&1 &
+ echo "Started fabric-bridge-app"
+fi
+
+# Start fabric-admin with or without log file path based on --verbose option
+if [ "$VERBOSE" = true ]; then
+ "$FABRIC_ADMIN_PATH"
+else
+ "$FABRIC_ADMIN_PATH" --log-file-path "$FABRIC_ADMIN_LOG"
+fi
diff --git a/examples/fabric-admin/scripts/stop_fabric_source.sh b/examples/fabric-admin/scripts/stop_fabric_source.sh
new file mode 100755
index 0000000..85fff9e
--- /dev/null
+++ b/examples/fabric-admin/scripts/stop_fabric_source.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+FABRIC_ADMIN_PATH="/fabric-admin"
+FABRIC_BRIDGE_APP_PATH="/fabric-bridge-app"
+
+# Kill fabric-admin if it is running
+fabric_admin_pid=$(pgrep -f "$FABRIC_ADMIN_PATH")
+if [ ! -z "$fabric_admin_pid" ]; then
+ kill -9 "$fabric_admin_pid"
+ echo "Killed fabric-admin with PID $fabric_admin_pid"
+fi
+
+# Kill fabric-bridge-app if it is running
+fabric_bridge_app_pid=$(pgrep -f "$FABRIC_BRIDGE_APP_PATH")
+if [ ! -z "$fabric_bridge_app_pid" ]; then
+ kill -9 "$fabric_bridge_app_pid"
+ echo "Killed fabric-bridge-app with PID $fabric_bridge_app_pid"
+fi
+
+# Remove /tmp/chip_* files and directories
+sudo rm -rf /tmp/chip_*
+echo "Removed /tmp/chip_* files and directories"