Node parameters
Sometimes you may want to run multiple instances of the same node with different input parameters. For example, a camera node might point to /dev/video0 on your system while another one points to /dev/video1.
Parameters allow you to run multiple instances of the same node with different input settings.
Adding parameters
Section titled “Adding parameters”In a new folder, initialize a new node:
-
Initialize the node:
Terminal window peppy node init --toolchain uv hello_world_paramTerminal window peppy node init --toolchain cargo hello_world_param -
Navigate into the directory:
Terminal window cd hello_world_param
Then modify the peppy.json5 configuration to look like this:
{ schema_version: 1, manifest: { name: "hello_world_param", tag: "0.1.0", language: "python", }, process: { add_cmd: [ "uv", "sync" ], start_cmd: [ "uv", "run", "hello_world_param" ] }, parameters: { name: "string", }, interfaces: { exposes: { topics: [ { name: "message_stream", qos_profile: "sensor_data", message_format: { message: "string" }, } ], } }}{ schema_version: 1, manifest: { name: "hello_world_param", tag: "0.1.0", language: "rust", }, process: { add_cmd: [ "cargo", "build", "--release" ], start_cmd: [ "./target/release/hello_world_param" ] }, parameters: { name: "string", }, interfaces: { exposes: { topics: [ { name: "message_stream", qos_profile: "sensor_data", message_format: { message: "string" }, } ], } }}With the new parameter key.
Synchronizing the interfaces
Section titled “Synchronizing the interfaces”Now let’s try to create a new snapshot of our node in the node stack:
peppy node add .You’ll get an error similar to this one:
Error: Fingerprint verification failed: Node config fingerprint mismatch: expected 9a58e1936c52c83d47d31621108e32bb78d2197c2d1989f0001e945a754e29a8, got ca1b1d51711a782db3152a723c6cdc255191c2a1721c7a19088e878fc9879c39.The config may have been modified after code generation. Run `node sync` to update the peppygen lib on your node.This error occurs because any changes to peppy.json5 need to be synced with the generated interfaces first. This safeguard guarantees that peppy.json5 always stays in sync with the node’s actual behavior.
To update the interfaces, run:
peppy node syncThis ensures that peppy node add . will succeed on the next run. Before doing that, let’s modify the source code first.
Using the parameter
Section titled “Using the parameter”Now that we’ve synchronized our project, the new parameter can be used in the main file by modifying it like this:
import asynciofrom peppygen import NodeBuilder, NodeRunnerfrom peppygen.parameters import Parametersfrom peppygen.exposed_topics import message_stream
async def emit_hello_world_loop(node_runner: NodeRunner, name: str): counter = 0 while True: counter += 1 message = f"hello {name} count {counter}" print(message, flush=True) await message_stream.emit(node_runner, message) await asyncio.sleep(3)
async def setup(params: Parameters, node_runner: NodeRunner) -> list[asyncio.Task]: return [asyncio.create_task(emit_hello_world_loop(node_runner, params.name))]
def main(): NodeBuilder().run(setup)
if __name__ == "__main__": main()use std::sync::Arc;use std::time::Duration;
use peppygen::{NodeBuilder, NodeRunner, Parameters, Result};use peppylib::runtime::CancellationToken;
/// Emits a "hello world count X" message every 3 seconds, starting immediately./// The loop runs until the cancellation token is triggered.async fn emit_hello_world_loop(runner: Arc<NodeRunner>, token: CancellationToken, name: String) { let mut counter: u64 = 0; let mut interval = tokio::time::interval(Duration::from_secs(3)); loop { tokio::select! { _ = token.cancelled() => break, _ = interval.tick() => { counter += 1; let message = format!("hello {name} count {counter}"); println!("{message}"); if let Err(e) = peppygen::exposed_topics::message_stream::emit(&runner, message).await { eprintln!("Failed to emit hello world: {e}"); } } } }}
fn main() -> Result<()> { NodeBuilder::new().run(|args: Parameters, node_runner| async move { let runner = node_runner.clone(); let token = node_runner.cancellation_token().clone();
// We use tokio::spawn to avoid blocking the closure tokio::spawn(emit_hello_world_loop(runner, token, args.name.clone()));
Ok(()) })}Next, add the node to the stack:
peppy node add .To verify the node was added, inspect the stack:
peppy stack list