diff --git a/Taskfile.yml b/Taskfile.yml index 10ef00c7..9803e3dd 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,8 +8,8 @@ vars: GOLANGCI_LINT_VERSION: v2.4.0 GOIMPORTS_VERSION: v0.29.0 DPRINT_VERSION: 0.48.0 - EXAMPLE_VERSION: "0.5.1" - RUNNER_VERSION: "0.5.0" + EXAMPLE_VERSION: "0.6.0" + RUNNER_VERSION: "0.6.1" VERSION: # if version is not passed we hack the semver by encoding the commit as pre-release sh: echo "${VERSION:-0.0.0-$(git rev-parse --short HEAD)}" diff --git a/cmd/arduino-app-cli/app/new.go b/cmd/arduino-app-cli/app/new.go index 066f9a7b..fec533b9 100644 --- a/cmd/arduino-app-cli/app/new.go +++ b/cmd/arduino-app-cli/app/new.go @@ -32,7 +32,6 @@ func newCreateCmd(cfg config.Configuration) *cobra.Command { icon string description string bricks []string - noPyton bool noSketch bool fromApp string ) @@ -44,7 +43,7 @@ func newCreateCmd(cfg config.Configuration) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { cobra.MinimumNArgs(1) name := args[0] - return createHandler(cmd.Context(), cfg, name, icon, description, noPyton, noSketch, fromApp) + return createHandler(cmd.Context(), cfg, name, icon, description, noSketch, fromApp) }, } @@ -52,14 +51,12 @@ func newCreateCmd(cfg config.Configuration) *cobra.Command { cmd.Flags().StringVarP(&description, "description", "d", "", "Description for the app") cmd.Flags().StringVarP(&fromApp, "from-app", "", "", "Create the new app from the path of an existing app") cmd.Flags().StringArrayVarP(&bricks, "bricks", "b", []string{}, "List of bricks to include in the app") - cmd.Flags().BoolVarP(&noPyton, "no-python", "", false, "Do not include Python files") cmd.Flags().BoolVarP(&noSketch, "no-sketch", "", false, "Do not include Sketch files") - cmd.MarkFlagsMutuallyExclusive("no-python", "no-sketch") return cmd } -func createHandler(ctx context.Context, cfg config.Configuration, name string, icon string, description string, noPython, noSketch bool, fromApp string) error { +func createHandler(ctx context.Context, cfg config.Configuration, name string, icon string, description string, noSketch bool, fromApp string) error { if fromApp != "" { id, err := servicelocator.GetAppIDProvider().ParseID(fromApp) if err != nil { @@ -88,7 +85,6 @@ func createHandler(ctx context.Context, cfg config.Configuration, name string, i Name: name, Icon: icon, Description: description, - SkipPython: noPython, SkipSketch: noSketch, }, servicelocator.GetAppIDProvider(), cfg) if err != nil { diff --git a/cmd/gendoc/docs.go b/cmd/gendoc/docs.go index 8e85e2a8..0b36ffe8 100644 --- a/cmd/gendoc/docs.go +++ b/cmd/gendoc/docs.go @@ -609,7 +609,6 @@ Contains a JSON object with the details of an error. Path: "/v1/apps", Request: handlers.CreateAppRequest{}, Parameters: (*struct { - SkipPython bool `query:"skip-python" description:"If true, the app will not be created with the python part."` SkipSketch bool `query:"skip-sketch" description:"If true, the app will not be created with the sketch part."` })(nil), CustomSuccessResponse: &CustomResponseDef{ diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md deleted file mode 100644 index ba9da420..00000000 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md +++ /dev/null @@ -1,107 +0,0 @@ -# cloud_llm API Reference - -## Index - -- Class `CloudLLM` -- Class `CloudModel` - ---- - -## `CloudLLM` class - -```python -class CloudLLM(api_key: str, model: Union[str, CloudModel], system_prompt: str, temperature: Optional[float], timeout: int) -``` - -A simplified, opinionated wrapper for common LangChain conversational patterns. - -This class provides a single interface to manage stateless chat and chat with memory. - -### Parameters - -- **api_key**: The API key for the LLM service. -- **model**: The model identifier as per LangChain specification (e.g., "anthropic:claude-3-sonnet-20240229") -or by using a CloudModels enum (e.g. CloudModels.OPENAI_GPT). Defaults to CloudModel.ANTHROPIC_CLAUDE. -- **system_prompt**: The global system-level instruction for the AI. -- **temperature**, default=0.7: The sampling temperature for response generation. Defaults to 0.7. -- **timeout**, default=30 seconds: The maximum time to wait for a response from the LLM service, in seconds. Defaults to 30 seconds. - -### Raises - -- **ValueError**: If the API key is missing. - -### Methods - -#### `with_memory(max_messages: int)` - -Enables conversational memory for this instance. - -This allows the chatbot to remember previous user and AI messages. -Calling this modifies the instance to be stateful. - -##### Parameters - -- **max_messages**: The total number of past messages (user + AI) to -keep in the conversation window. Set to 0 to disable memory. - -##### Returns - -- (*self*): The current CloudLLM instance for method chaining. - -#### `chat(message: str)` - -Sends a single message to the AI and gets a complete response synchronously. - -This is the primary way to interact. It automatically handles memory -based on how the instance was configured. - -##### Parameters - -- **message**: The user's message. - -##### Returns - --: The AI's complete response as a string. - -##### Raises - -- **RuntimeError**: If the chat model is not initialized or if text generation fails. - -#### `chat_stream(message: str)` - -Sends a single message to the AI and streams the response as a synchronous generator. - -Use this to get tokens as they are generated, perfect for a streaming UI. - -##### Parameters - -- **message**: The user's message. - -##### Returns - -- (*str*): Chunks of the AI's response as they become available. - -##### Raises - -- **RuntimeError**: If the chat model is not initialized or if text generation fails. -- **AlreadyGenerating**: If the chat model is already streaming a response. - -#### `stop_stream()` - -Signals the LLM to stop generating a response. - -#### `clear_memory()` - -Clears the conversational memory. - -This only has an effect if with_memory() has been called. - - ---- - -## `CloudModel` class - -```python -class CloudModel() -``` - diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/air_quality_monitoring/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/air_quality_monitoring/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/air_quality_monitoring/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/air_quality_monitoring/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/arduino_cloud/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/arduino_cloud/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/arduino_cloud/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/arduino_cloud/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md similarity index 91% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md index 87a5213e..7573beee 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md @@ -67,7 +67,7 @@ Stop real-time audio classification. Terminates audio capture and releases any associated resources. -#### `classify_from_file(audio_path: str, confidence: int)` +#### `classify_from_file(audio_path: str, confidence: float)` Classify audio content from a WAV file. @@ -80,9 +80,8 @@ Supported sample widths: ##### Parameters - **audio_path** (*str*): Path to the `.wav` audio file to classify. -- **confidence** (*int*) (optional): Confidence threshold (0–1). If None, -the default confidence level specified during initialization -will be applied. +- **confidence** (*float*) (optional): Minimum confidence threshold (0.0–1.0) required +for a detection to be considered valid. Defaults to 0.8 (80%). ##### Returns diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/camera_code_detection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/camera_code_detection/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/camera_code_detection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/camera_code_detection/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md new file mode 100644 index 00000000..d2dd5903 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md @@ -0,0 +1,120 @@ +# cloud_llm API Reference + +## Index + +- Class `CloudLLM` +- Class `CloudModel` + +--- + +## `CloudLLM` class + +```python +class CloudLLM(api_key: str, model: Union[str, CloudModel], system_prompt: str, temperature: Optional[float], timeout: int) +``` + +A Brick for interacting with cloud-based Large Language Models (LLMs). + +This class wraps LangChain functionality to provide a simplified, unified interface +for chatting with models like Claude, GPT, and Gemini. It supports both synchronous +'one-shot' responses and streaming output, with optional conversational memory. + +### Parameters + +- **api_key** (*str*): The API access key for the target LLM service. Defaults to the +'API_KEY' environment variable. +- **model** (*Union[str, CloudModel]*): The model identifier. Accepts a `CloudModel` +enum member (e.g., `CloudModel.OPENAI_GPT`) or its corresponding raw string +value (e.g., `'gpt-4o-mini'`). Defaults to `CloudModel.ANTHROPIC_CLAUDE`. +- **system_prompt** (*str*): A system-level instruction that defines the AI's persona +and constraints (e.g., "You are a helpful assistant"). Defaults to empty. +- **temperature** (*Optional[float]*): The sampling temperature between 0.0 and 1.0. +Higher values make output more random/creative; lower values make it more +deterministic. Defaults to 0.7. +- **timeout** (*int*): The maximum duration in seconds to wait for a response before +timing out. Defaults to 30. + +### Raises + +- **ValueError**: If `api_key` is not provided (empty string). + +### Methods + +#### `with_memory(max_messages: int)` + +Enables conversational memory for this instance. + +Configures the Brick to retain a window of previous messages, allowing the +AI to maintain context across multiple interactions. + +##### Parameters + +- **max_messages** (*int*): The maximum number of messages (user + AI) to keep +in history. Older messages are discarded. Set to 0 to disable memory. +Defaults to 10. + +##### Returns + +- (*CloudLLM*): The current instance, allowing for method chaining. + +#### `chat(message: str)` + +Sends a message to the AI and blocks until the complete response is received. + +This method automatically manages conversation history if memory is enabled. + +##### Parameters + +- **message** (*str*): The input text prompt from the user. + +##### Returns + +- (*str*): The complete text response generated by the AI. + +##### Raises + +- **RuntimeError**: If the internal chain is not initialized or if the API request fails. + +#### `chat_stream(message: str)` + +Sends a message to the AI and yields response tokens as they are generated. + +This allows for processing or displaying the response in real-time (streaming). +The generation can be interrupted by calling `stop_stream()`. + +##### Parameters + +- **message** (*str*): The input text prompt from the user. + +##### Returns + +- (*str*): Chunks of text (tokens) from the AI response. + +##### Raises + +- **RuntimeError**: If the internal chain is not initialized or if the API request fails. +- **AlreadyGenerating**: If a streaming session is already active. + +#### `stop_stream()` + +Signals the active streaming generation to stop. + +This sets an internal flag that causes the `chat_stream` iterator to break +early. It has no effect if no stream is currently running. + +#### `clear_memory()` + +Clears the conversational memory history. + +Resets the stored context. This is useful for starting a new conversation +topic without previous context interfering. Only applies if memory is enabled. + + +--- + +## `CloudModel` class + +```python +class CloudModel() +``` + diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/image_classification/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/image_classification/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/image_classification/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/image_classification/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/keyword_spotting/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/keyword_spotting/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/keyword_spotting/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/keyword_spotting/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/mood_detector/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/mood_detector/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/mood_detector/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/mood_detector/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/motion_detection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/motion_detection/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/motion_detection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/motion_detection/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/mqtt/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/mqtt/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/mqtt/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/mqtt/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md similarity index 90% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md index c8c84812..bf58415c 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md @@ -19,6 +19,14 @@ This module processes an input image and returns: - Corresponding class labels - Confidence scores for each detection +### Parameters + +- **confidence** (*float*): Minimum confidence threshold for detections. Default is 0.3 (30%). + +### Raises + +- **ValueError**: If model information cannot be retrieved. + ### Methods #### `detect_from_file(image_path: str, confidence: float)` @@ -60,7 +68,7 @@ Draw bounding boxes on an image enclosing detected objects using PIL. ##### Returns -: Image with bounding boxes and key points drawn. -None if no detection or invalid image. +None if input image or detections are invalid. #### `process(item)` diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/streamlit_ui/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/streamlit_ui/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/streamlit_ui/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/streamlit_ui/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/video_imageclassification/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/video_imageclassification/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/video_imageclassification/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/video_imageclassification/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/video_objectdetection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/video_objectdetection/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/video_objectdetection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/video_objectdetection/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md new file mode 100644 index 00000000..f8977727 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md @@ -0,0 +1,151 @@ +# wave_generator API Reference + +## Index + +- Class `WaveGenerator` + +--- + +## `WaveGenerator` class + +```python +class WaveGenerator(sample_rate: int, wave_type: WaveType, block_duration: float, attack: float, release: float, glide: float, speaker: Speaker) +``` + +Continuous wave generator brick for audio synthesis. + +This brick generates continuous audio waveforms (sine, square, sawtooth, triangle) +and streams them to a USB speaker in real-time. It provides smooth transitions +between frequency and amplitude changes using configurable envelope parameters. + +The generator runs continuously in a background thread, producing audio blocks +at a steady rate with minimal latency. + +### Parameters + +- **sample_rate** (*int*): Audio sample rate in Hz (default: 16000). +- **wave_type** (*WaveType*): Initial waveform type (default: "sine"). +- **block_duration** (*float*): Duration of each audio block in seconds (default: 0.01). +- **attack** (*float*): Attack time for amplitude envelope in seconds (default: 0.01). +- **release** (*float*): Release time for amplitude envelope in seconds (default: 0.03). +- **glide** (*float*): Frequency glide time (portamento) in seconds (default: 0.02). +- **speaker** (*Speaker*) (optional): Pre-configured Speaker instance. If None, WaveGenerator +will create an internal Speaker optimized for real-time synthesis with: +- periodsize aligned to block_duration (eliminates buffer mismatch) +- queue_maxsize=8 (low latency: ~80ms max buffer) +- format=FLOAT_LE, channels=1 + +If providing an external Speaker, ensure: +- sample_rate matches WaveGenerator's sample_rate +- periodsize = int(sample_rate × block_duration) for optimal alignment +- Speaker is started/stopped manually (WaveGenerator won't manage its lifecycle) + +Example external Speaker configuration: + speaker = Speaker( + device="plughw:CARD=UH34", + sample_rate=16000, + format="FLOAT_LE", + periodsize=160, # 16000 × 0.01 = 160 frames + queue_maxsize=8 + ) + +### Raises + +- **SpeakerException**: If no USB speaker is found or device is busy. + +### Attributes + +- **sample_rate** (*int*): Audio sample rate in Hz (default: 16000). +- **wave_type** (*WaveType*): Type of waveform to generate. +- **frequency** (*float*): Current output frequency in Hz. +- **amplitude** (*float*): Current output amplitude (0.0-1.0). + +### Methods + +#### `start()` + +Start the wave generator and audio output. + +This starts the speaker device (if internally owned) and launches the producer thread +that continuously generates and streams audio blocks. + +#### `stop()` + +Stop the wave generator and audio output. + +This stops the producer thread and closes the speaker device (if internally owned). + +#### `set_frequency(frequency: float)` + +Set the target output frequency. + +The frequency will smoothly transition to the new value over the +configured glide time. + +##### Parameters + +- **frequency** (*float*): Target frequency in Hz (typically 20-8000 Hz). + +#### `set_amplitude(amplitude: float)` + +Set the target output amplitude. + +The amplitude will smoothly transition to the new value over the +configured attack/release time. + +##### Parameters + +- **amplitude** (*float*): Target amplitude in range [0.0, 1.0]. + +#### `set_wave_type(wave_type: WaveType)` + +Change the waveform type. + +##### Parameters + +- **wave_type** (*WaveType*): One of "sine", "square", "sawtooth", "triangle". + +##### Raises + +- **ValueError**: If wave_type is not valid. + +#### `set_volume(volume: int)` + +Set the speaker volume level. + +This is a wrapper that controls the hardware volume of the USB speaker device. + +##### Parameters + +- **volume** (*int*): Hardware volume level (0-100). + +##### Raises + +- **SpeakerException**: If the mixer is not available or if volume cannot be set. + +#### `get_volume()` + +Get the current speaker volume level. + +##### Returns + +- (*int*): Current hardware volume level (0-100). + +#### `set_envelope_params(attack: float, release: float, glide: float)` + +Update envelope parameters. + +##### Parameters + +- **attack** (*float*) (optional): Attack time in seconds. +- **release** (*float*) (optional): Release time in seconds. +- **glide** (*float*) (optional): Frequency glide time in seconds. + +#### `get_state()` + +Get current generator state. + +##### Returns + +- (*dict*): Dictionary containing current frequency, amplitude, wave type, etc. + diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/weather_forecast/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/weather_forecast/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/weather_forecast/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/weather_forecast/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md similarity index 76% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md index 4619aed5..ec08afdb 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md @@ -9,7 +9,7 @@ ## `WebUI` class ```python -class WebUI(addr: str, port: int, ui_path_prefix: str, api_path_prefix: str, assets_dir_path: str, certs_dir_path: str, use_ssl: bool) +class WebUI(addr: str, port: int, ui_path_prefix: str, api_path_prefix: str, assets_dir_path: str, certs_dir_path: str, use_tls: bool, use_ssl: bool | None) ``` Module for deploying a web server that can host a web application and expose APIs to its clients. @@ -24,21 +24,38 @@ and support real-time communication between the client and the server. - **ui_path_prefix** (*str*) (optional), default="" (root): URL prefix for UI routes. Defaults to "" (root). - **api_path_prefix** (*str*) (optional), default="" (root): URL prefix for API routes. Defaults to "" (root). - **assets_dir_path** (*str*) (optional), default="/app/assets": Path to static assets directory. Defaults to "/app/assets". -- **certs_dir_path** (*str*) (optional), default="/app/certs": Path to SSL certificates directory. Defaults to "/app/certs". -- **use_ssl** (*bool*) (optional), default=False: Enable SSL/HTTPS. Defaults to False. +- **certs_dir_path** (*str*) (optional), default="/app/certs": Path to TLS certificates directory. Defaults to "/app/certs". +- **use_tls** (*bool*) (optional), default=False: Enable TLS/HTTPS. Defaults to False. +- **use_ssl** (*bool*) (optional), default=None: Deprecated. Use use_tls instead. Defaults to None. ### Methods +#### `local_url()` + +Get the locally addressable URL of the web server. + +##### Returns + +- (*str*): The server's URL (including protocol, address, and port). + +#### `url()` + +Get the externally addressable URL of the web server. + +##### Returns + +- (*str*): The server's URL (including protocol, address, and port). + #### `start()` Start the web server asynchronously. -This sets up static file routing and WebSocket event handlers, configures SSL if enabled, and launches the server using Uvicorn. +This sets up static file routing and WebSocket event handlers, configures TLS if enabled, and launches the server using Uvicorn. ##### Raises - **RuntimeError**: If 'index.html' is missing in the static assets directory. -- **RuntimeError**: If SSL is enabled but certificates are missing or fail to generate. +- **RuntimeError**: If TLS is enabled but certificates fail to generate. - **RuntimeWarning**: If the server is already running. #### `stop()` @@ -47,7 +64,7 @@ Stop the web server gracefully. Waits up to 5 seconds for current requests to finish before terminating. -#### `expose_api(method: str, path: str, function: callable)` +#### `expose_api(method: str, path: str, function: Callable)` Register a route with the specified HTTP method and path. @@ -57,7 +74,7 @@ The path will be prefixed with the api_path_prefix configured during initializat - **method** (*str*): HTTP method to use (e.g., "GET", "POST"). - **path** (*str*): URL path for the API endpoint (without the prefix). -- **function** (*callable*): Function to execute when the route is accessed. +- **function** (*Callable*): Function to execute when the route is accessed. #### `on_connect(callback: Callable[[str], None])` @@ -79,7 +96,7 @@ The callback should accept a single argument: the session ID (sid) of the discon - **callback** (*Callable[[str], None]*): Function to call when a client disconnects. Receives the session ID (sid) as its only argument. -#### `on_message(message_type: str, callback: Callable[[str, any], any])` +#### `on_message(message_type: str, callback: Callable[[str, Any], Any])` Register a callback function for a specific WebSocket message type received by clients. @@ -91,10 +108,10 @@ with a message type suffix "_response". ##### Parameters - **message_type** (*str*): The message type name to listen for. -- **callback** (*Callable[[str, any], any]*): Function to handle the message. Receives two arguments: +- **callback** (*Callable[[str, Any], Any]*): Function to handle the message. Receives two arguments: the session ID (sid) and the incoming message data. -#### `send_message(message_type: str, message: dict | str, room: str)` +#### `send_message(message_type: str, message: dict | str, room: str | None)` Send a message to connected WebSocket clients. diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/microphone/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/microphone/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/microphone/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/microphone/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md similarity index 79% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md index 3cddad0f..94c64118 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md @@ -21,7 +21,7 @@ Custom exception for Speaker errors. ## `Speaker` class ```python -class Speaker(device: str, sample_rate: int, channels: int, format: str) +class Speaker(device: str, sample_rate: int, channels: int, format: str, periodsize: int, queue_maxsize: int) ``` Speaker class for reproducing audio using ALSA PCM interface. @@ -32,6 +32,12 @@ Speaker class for reproducing audio using ALSA PCM interface. - **sample_rate** (*int*): Sample rate in Hz (default: 16000). - **channels** (*int*): Number of audio channels (default: 1). - **format** (*str*): Audio format (default: "S16_LE"). +- **periodsize** (*int*): ALSA period size in frames (default: None = use hardware default). +For real-time synthesis, set to match generation block size. +For streaming/file playback, leave as None for hardware-optimal value. +- **queue_maxsize** (*int*): Maximum application queue depth in blocks (default: 100). +Lower values (5-20) reduce latency for interactive audio. +Higher values (50-200) provide stability for streaming. ### Raises diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/usb_camera/API.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/usb_camera/API.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/usb_camera/API.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/api-docs/arduino/app_peripherals/usb_camera/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/bricks-list.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/bricks-list.yaml similarity index 93% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/bricks-list.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/bricks-list.yaml index a4747e86..8d79e540 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/bricks-list.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/bricks-list.yaml @@ -5,7 +5,6 @@ bricks: local database. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: storage @@ -17,7 +16,6 @@ bricks: \ or with custom object detection models trained on Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -38,7 +36,6 @@ bricks: ' require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: text @@ -47,7 +44,6 @@ bricks: description: Scans a camera for barcodes and QR codes require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -64,7 +60,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: audio @@ -81,7 +76,6 @@ bricks: description: Connects to Arduino Cloud require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -90,6 +84,17 @@ bricks: description: Arduino Cloud Device ID - name: ARDUINO_SECRET description: Arduino Cloud Secret +- id: arduino:wave_generator + name: Wave Generator + description: Continuous wave generator for audio synthesis. Generates sine, square, + sawtooth, and triangle waveforms with smooth frequency and amplitude transitions. + require_container: false + require_model: false + mount_devices_into_container: false + ports: [] + category: audio + required_devices: + - speaker - id: arduino:image_classification name: Image Classification description: "Brick for image classification using a pre-trained model. It processes\ @@ -98,7 +103,6 @@ bricks: \ image classification models trained on Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -115,7 +119,6 @@ bricks: description: A simplified user interface based on Streamlit and Python. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: - 7000 @@ -135,7 +138,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -155,7 +157,6 @@ bricks: APIs and a WebSocket exposed by a web server. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: - 7000 @@ -172,7 +173,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: audio @@ -202,7 +202,6 @@ bricks: ' require_container: true require_model: true - require_devices: true mount_devices_into_container: true ports: [] category: video @@ -224,7 +223,6 @@ bricks: and weather APIs. Requires an internet connection. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: miscellaneous @@ -241,7 +239,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -259,7 +256,6 @@ bricks: built on top of InfluxDB. require_container: true require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: storage @@ -283,7 +279,6 @@ bricks: \ detection models trained on the Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: image @@ -312,7 +307,6 @@ bricks: ' require_container: true require_model: true - require_devices: true mount_devices_into_container: true ports: [] category: null @@ -328,3 +322,15 @@ bricks: description: path to the model file - name: VIDEO_DEVICE default_value: /dev/video1 +- id: arduino:cloud_llm + name: Cloud LLM + description: Cloud LLM Brick enables seamless integration with cloud-based Large + Language Models (LLMs) for advanced AI capabilities in your Arduino projects. + require_container: false + require_model: false + mount_devices_into_container: false + ports: [] + category: null + variables: + - name: API_KEY + description: API Key for the cloud-based LLM service diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml index 6dbe38e4..0a710c5f 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-audio-classifier-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/dbstorage_tsstore/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/dbstorage_tsstore/brick_compose.yaml similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/dbstorage_tsstore/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/dbstorage_tsstore/brick_compose.yaml diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml index d8207271..fe20b37e 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-classification-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml index b4dd7963..4340871e 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-keyword-spot-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml index ef7fc730..abc10e77 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-motion-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml index 9d418913..99871411 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-obj-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml index aca4e2a2..e07c2890 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-anomaly-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml index 7e054acc..3dd8139a 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-video-classification-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml similarity index 86% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml index dbca6363..804bc638 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-video-obj-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: @@ -13,7 +13,7 @@ services: volumes: - "${CUSTOM_MODEL_PATH:-/home/arduino/.arduino-bricks/ei-models/}:${CUSTOM_MODEL_PATH:-/home/arduino/.arduino-bricks/ei-models/}" - "/run/udev:/run/udev" - command: ["--model-file", "${EI_OBJ_DETECTION_MODEL:-/models/ootb/ei/yolo-x-nano.eim}", "--dont-print-predictions", "--mode", "streaming", "--force-target", "--preview-original-resolution", "--camera", "${VIDEO_DEVICE:-/dev/video1}"] + command: ["--model-file", "${EI_OBJ_DETECTION_MODEL:-/models/ootb/ei/yolo-x-nano.eim}", "--dont-print-predictions", "--mode", "streaming", "--preview-original-resolution", "--camera", "${VIDEO_DEVICE:-/dev/video1}"] healthcheck: test: [ "CMD-SHELL", "wget -q --spider http://ei-video-obj-detection-runner:4912 || exit 1" ] interval: 2s diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml index 0e71d75a..ced99fcb 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-obj-video-anomalies-det-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/arduino_cloud/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/arduino_cloud/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/arduino_cloud/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/arduino_cloud/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/audio_classification/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/audio_classification/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/audio_classification/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/audio_classification/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/camera_code_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/camera_code_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/camera_code_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/camera_code_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/cloud_llm/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/cloud_llm/README.md new file mode 100644 index 00000000..add84514 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/cloud_llm/README.md @@ -0,0 +1,109 @@ +# Cloud LLM Brick + +The Cloud LLM Brick provides a seamless interface to interact with cloud-based Large Language Models (LLMs) such as OpenAI's GPT, Anthropic's Claude, and Google's Gemini. It abstracts the complexity of REST APIs, enabling you to send prompts, receive responses, and maintain conversational context within your Arduino projects. + +## Overview + +This Brick acts as a gateway to powerful AI models hosted in the cloud. It is designed to handle the nuances of network communication, authentication, and session management. Whether you need a simple one-off answer or a continuous conversation with memory, the Cloud LLM Brick provides a unified API for different providers. + +## Features + +- **Multi-Provider Support**: Compatible with major LLM providers including Anthropic (Claude), OpenAI (GPT), and Google (Gemini). +- **Conversational Memory**: Built-in support for windowed history, allowing the AI to remember context from previous exchanges. +- **Streaming Responses**: Receive text chunks in real-time as they are generated, ideal for responsive user interfaces. +- **Configurable Behavior**: Customize system prompts, temperature (creativity), and request timeouts. +- **Simple API**: Unified `chat` and `chat_stream` methods regardless of the underlying model provider. + +## Prerequisites + +- **Internet Connection**: The board must be connected to the internet to reach the LLM provider's API. +- **API Key**: A valid API key for the chosen service (e.g., OpenAI API Key, Anthropic API Key). +- **Python Dependencies**: The Brick relies on LangChain integration packages (`langchain-anthropic`, `langchain-openai`, `langchain-google-genai`). + +## Code Example and Usage + +### Basic Conversation + +This example initializes the Brick with an OpenAI model and performs a simple chat interaction. + +**Note:** The API key is not hardcoded. It is retrieved automatically from the **Brick Configuration** in App Lab. + +```python +import os +from arduino.app_bricks.cloud_llm import CloudLLM, CloudModel +from arduino.app_utils import App + +# Initialize the Brick (API key is loaded from configuration) +llm = CloudLLM( + model=CloudModel.OPENAI_GPT, + system_prompt="You are a helpful assistant for an IoT device." +) + +def simple_chat(): + # Send a prompt and print the response + response = llm.chat("What is the capital of Italy?") + print(f"AI: {response}") + +# Run the application +App.run(simple_chat) +``` + +### Streaming with Memory + +This example demonstrates how to enable conversational memory and process the response as a stream of tokens. + +```python +from arduino.app_bricks.cloud_llm import CloudLLM, CloudModel +from arduino.app_utils import App + +# Initialize with memory enabled (keeps last 10 messages) +# API Key is retrieved automatically from Brick Configuration +llm = CloudLLM( + model=CloudModel.ANTHROPIC_CLAUDE +).with_memory(max_messages=10) + +def chat_loop(): + while True: + user_input = input("You: ") + if user_input.lower() in ["exit", "quit"]: + break + + print("AI: ", end="", flush=True) + + # Stream the response token by token + for token in llm.chat_stream(user_input): + print(token, end="", flush=True) + print() # Newline after response + +App.run(chat_loop) +``` + +## Configuration + +The Brick is initialized with the following parameters: + +| Parameter | Type | Default | Description | +| :-------------- | :-------------------- | :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | +| `api_key` | `str` | `os.getenv("API_KEY")` | The authentication key for the LLM provider. **Recommended:** Set this via the **Brick Configuration** menu in App Lab instead of code. | +| `model` | `str` \| `CloudModel` | `CloudModel.ANTHROPIC_CLAUDE` | The specific model to use. Accepts a `CloudModel` enum or its string value. | +| `system_prompt` | `str` | `""` | A base instruction that defines the AI's behavior and persona. | +| `temperature` | `float` | `0.7` | Controls randomness. `0.0` is deterministic, `1.0` is creative. | +| `timeout` | `int` | `30` | Maximum time (in seconds) to wait for a response. | + +### Supported Models + +You can select a model using the `CloudModel` enum or by passing the corresponding raw string identifier. + +| Enum Constant | Raw String ID | Provider Documentation | +| :---------------------------- | :------------------------- | :-------------------------------------------------------------------------- | +| `CloudModel.ANTHROPIC_CLAUDE` | `claude-3-7-sonnet-latest` | [Anthropic Models](https://docs.anthropic.com/en/docs/about-claude/models) | +| `CloudModel.OPENAI_GPT` | `gpt-4o-mini` | [OpenAI Models](https://platform.openai.com/docs/models) | +| `CloudModel.GOOGLE_GEMINI` | `gemini-2.5-flash` | [Google Gemini Models](https://ai.google.dev/gemini-api/docs/models/gemini) | + +## Methods + +- **`chat(message)`**: Sends a message and returns the complete response string. Blocks until generation is finished. +- **`chat_stream(message)`**: Returns a generator yielding response tokens as they arrive. +- **`stop_stream()`**: Interrupts an active streaming generation. +- **`with_memory(max_messages)`**: Enables history tracking. `max_messages` defines the context window size. +- **`clear_memory()`**: Resets the conversation history. \ No newline at end of file diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md index 704a9e62..53a837d0 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md @@ -35,7 +35,7 @@ db = SQLStore("example.db") # ... Do work # Close database -db.close() +db.stop() ``` To create a new table: @@ -65,4 +65,4 @@ db.store("users", data) The SQLStore automatically creates a directory structure for database storage, placing files in `data/dbstorage_sqlstore/` within your application directory. The brick supports automatic type inference when creating tables, mapping Python types (*int*, *float*, *str*, *bytes*) to corresponding SQLite column types (*INTEGER*, *REAL*, *TEXT*, *BLOB*). -The `store()` method can automatically create tables if they don't exist by analyzing the data types of the provided values. This makes it easy to get started without defining schemas upfront, while still allowing explicit table creation for more control over column definitions and constraints. \ No newline at end of file +The `store()` method can automatically create tables if they don't exist by analyzing the data types of the provided values. This makes it easy to get started without defining schemas upfront, while still allowing explicit table creation for more control over column definitions and constraints. diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/dbstorage_tsstore/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/dbstorage_tsstore/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/dbstorage_tsstore/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/dbstorage_tsstore/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/image_classification/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/image_classification/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/image_classification/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/image_classification/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/keyword_spotting/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/keyword_spotting/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/keyword_spotting/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/keyword_spotting/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/mood_detector/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/mood_detector/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/mood_detector/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/mood_detector/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/motion_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/motion_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/motion_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/motion_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/object_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/object_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/object_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/object_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/streamlit_ui/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/streamlit_ui/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/streamlit_ui/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/streamlit_ui/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/vibration_anomaly_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/vibration_anomaly_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/vibration_anomaly_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/vibration_anomaly_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/video_image_classification/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/video_image_classification/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/video_image_classification/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/video_image_classification/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/video_object_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/video_object_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/video_object_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/video_object_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/visual_anomaly_detection/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/visual_anomaly_detection/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/visual_anomaly_detection/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/visual_anomaly_detection/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/wave_generator/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/wave_generator/README.md new file mode 100644 index 00000000..23a1f9f8 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/wave_generator/README.md @@ -0,0 +1,119 @@ +# Wave Generator brick + +This brick provides continuous wave generation for real-time audio synthesis with multiple waveform types and smooth transitions. + +## Overview + +The Wave Generator brick allows you to: + +- Generate continuous audio waveforms in real-time +- Select between different waveform types (sine, square, sawtooth, triangle) +- Control frequency and amplitude dynamically during playback +- Configure smooth transitions with attack, release, and glide (portamento) parameters +- Stream audio to USB speakers with minimal latency + +It runs continuously in a background thread, producing audio blocks at a steady rate with configurable envelope parameters for professional-sounding synthesis. + +## Features + +- Four waveform types: sine, square, sawtooth, and triangle +- Real-time frequency and amplitude control with smooth transitions +- Configurable envelope parameters (attack, release, glide) +- Hardware volume control support +- Thread-safe operation for concurrent access +- Efficient audio generation using NumPy vectorization +- Custom speaker configuration support + +## Prerequisites + +Before using the Wave Generator brick, ensure you have the following: + +- USB-C® Hub with external power supply (5V, 3A) +- USB audio device (USB speaker or USB-C → 3.5mm adapter) +- Arduino UNO Q running in Network Mode or SBC Mode (USB-C port needed for the hub) + +## Code example and usage + +Here is a basic example for generating a 440 Hz sine wave tone: + +```python +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator() + +App.start_brick(wave_gen) + +# Set frequency to A4 note (440 Hz) +wave_gen.set_frequency(440.0) + +# Set amplitude to 80% +wave_gen.set_amplitude(0.8) + +App.run() +``` + +You can customize the waveform type and envelope parameters: + +```python +wave_gen = WaveGenerator( + wave_type="square", + attack=0.01, + release=0.03, + glide=0.02 +) + +App.start_brick(wave_gen) + +# Change waveform during playback +wave_gen.set_wave_type("triangle") + +# Adjust envelope parameters +wave_gen.set_envelope_params(attack=0.05, release=0.1, glide=0.05) + +App.run() +``` + +For specific hardware configurations, you can provide a custom Speaker instance: + +```python +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_peripherals.speaker import Speaker +from arduino.app_utils import App + +# Create Speaker with optimal real-time configuration +speaker = Speaker( + device=Speaker.USB_SPEAKER_2, + sample_rate=16000, + channels=1, + format="FLOAT_LE", + periodsize=480, # 16000 Hz × 0.03s = 480 frames (eliminates buffer mismatch) + queue_maxsize=10 # Low latency configuration +) + +# Start external Speaker manually (WaveGenerator won't manage its lifecycle) +speaker.start() + +wave_gen = WaveGenerator(sample_rate=16000, speaker=speaker) + +App.start_brick(wave_gen) +wave_gen.set_frequency(440.0) +wave_gen.set_amplitude(0.7) + +App.run() + +# Stop external Speaker manually +speaker.stop() +``` + +**Note:** When providing an external Speaker, you manage its lifecycle (start/stop). WaveGenerator only validates configuration and uses it for playback. + +## Understanding Wave Generation + +The Wave Generator brick produces audio through continuous waveform synthesis. + +The `frequency` parameter controls the pitch of the output sound, measured in Hertz (Hz), where typical audible frequencies range from 20 Hz to 8000 Hz. + +The `amplitude` parameter controls the volume as a value between 0.0 (silent) and 1.0 (maximum), with smooth transitions handled by the attack and release envelope parameters. + +The `glide` parameter (also known as portamento) smoothly transitions between frequencies over time, creating sliding pitch effects similar to a theremin or synthesizer. Setting glide to 0 disables this effect but may cause audible clicks during fast frequency changes. diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/weather_forecast/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/weather_forecast/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/weather_forecast/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/weather_forecast/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/web_ui/README.md b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/web_ui/README.md similarity index 100% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/web_ui/README.md rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/docs/arduino/web_ui/README.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py similarity index 90% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py index 58cd9470..3a9df8ca 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py similarity index 88% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py index 40371db7..1fce305b 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py similarity index 92% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py index 5e730ea9..4b8c5bf9 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py similarity index 84% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py index 36b2be12..1eed6c3a 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py similarity index 60% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py index 68bdd710..237aaba1 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 @@ -6,7 +6,5 @@ # EXAMPLE_REQUIRES = "Requires an audio file with the glass breaking sound." from arduino.app_bricks.audio_classification import AudioClassification -classifier = AudioClassification() - -classification = classifier.classify_from_file("glass_breaking.wav") +classification = AudioClassification.classify_from_file("glass_breaking.wav") print("Result:", classification) diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py similarity index 89% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py index 6dfdb41a..1facd326 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py similarity index 90% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py index 6288d571..7d63bb46 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py similarity index 91% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py index 8a672470..d128cd96 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py new file mode 100644 index 00000000..7c325de8 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Chat with an LLM" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + print(llm.chat(prompt)) + print() + + +App.run(ask_prompt) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py new file mode 100644 index 00000000..9538cbda --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Streaming responses from an LLM" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + for token in llm.chat_stream(prompt): + print(token, end="", flush=True) + print() + + +App.run(ask_prompt) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py new file mode 100644 index 00000000..f30419bf --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Conversation with memory" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) +llm.with_memory(0) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + print(llm.chat(prompt)) + + +App.run(ask_prompt) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py similarity index 85% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py index e3e31edb..54d070cd 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py similarity index 84% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py index 9b4185d6..42c19b90 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py similarity index 93% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py index 2adee9d9..21ee99a2 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py similarity index 90% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py index 7dd28c57..7597172e 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py similarity index 82% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py index b5687f86..346cf45d 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py similarity index 91% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py index f2ca3b9f..166f5b7c 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py similarity index 91% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py index 5dc0d2cc..42a8864e 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py new file mode 100644 index 00000000..5acd492f --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Basic Wave Generator Example + +Generates a simple 440Hz sine wave (A4 note) and demonstrates +basic frequency and amplitude control. +""" + +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +# Create wave generator with default settings +wave_gen = WaveGenerator( + sample_rate=16000, + wave_type="sine", + glide=0.02, # 20ms smooth frequency transitions +) + +# Start the generator +App.start_brick(wave_gen) + +# Set initial frequency and amplitude +wave_gen.set_frequency(440.0) # A4 note (440 Hz) +wave_gen.set_amplitude(0.7) # 70% amplitude +wave_gen.set_volume(80) # 80% hardware volume + +print("Playing 440Hz sine wave (A4 note)") +print("Press Ctrl+C to stop") + +# Keep the application running +App.run() diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py new file mode 100644 index 00000000..320757c3 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Waveform Comparison Example + +Cycles through different waveform types to hear the difference +between sine, square, sawtooth, and triangle waves. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator(sample_rate=16000, glide=0.02) +App.start_brick(wave_gen) + +# Set constant frequency and amplitude +wave_gen.set_frequency(440.0) +wave_gen.set_amplitude(0.6) + +waveforms = ["sine", "square", "sawtooth", "triangle"] + + +def cycle_waveforms(): + """Cycle through different waveform types.""" + for wave_type in waveforms: + print(f"Playing {wave_type} wave...") + wave_gen.set_wave_type(wave_type) + time.sleep(3) + # Silence + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Cycling through waveforms:") +print("sine → square → sawtooth → triangle") +print("Press Ctrl+C to stop") + +App.run(user_loop=cycle_waveforms) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py new file mode 100644 index 00000000..614d9962 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Frequency Sweep Example + +Demonstrates smooth frequency transitions (glide/portamento effect) +by sweeping through different frequency ranges. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator( + wave_type="sine", + glide=0.05, # 50ms glide for noticeable portamento +) + +App.start_brick(wave_gen) +wave_gen.set_amplitude(0.7) + + +def frequency_sweep(): + """Sweep through frequency ranges.""" + + # Low to high sweep + print("Sweeping low to high (220Hz → 880Hz)...") + for freq in range(220, 881, 20): + wave_gen.set_frequency(float(freq)) + time.sleep(0.1) + + time.sleep(0.5) + + # High to low sweep + print("Sweeping high to low (880Hz → 220Hz)...") + for freq in range(880, 219, -20): + wave_gen.set_frequency(float(freq)) + time.sleep(0.1) + # Fade out + print("Fading out...") + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Frequency sweep demonstration") +print("Listen for smooth glide between frequencies") +print("Press Ctrl+C to stop") + +App.run(user_loop=frequency_sweep) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py new file mode 100644 index 00000000..395099fb --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Envelope Control Example + +Demonstrates amplitude envelope control with different +attack and release times for various sonic effects. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator(wave_type="sine") +App.start_brick(wave_gen) + +wave_gen.set_frequency(440.0) +wave_gen.set_volume(80) + + +def envelope_demo(): + """Demonstrate different envelope settings.""" + + # Fast attack, fast release (percussive) + print("1. Percussive (fast attack/release)...") + wave_gen.set_envelope_params(attack=0.001, release=0.01, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.5) + wave_gen.set_amplitude(0.0) + time.sleep(1) + + # Slow attack, fast release (pad-like) + print("2. Pad-like (slow attack, fast release)...") + wave_gen.set_envelope_params(attack=0.2, release=0.05, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(1) + wave_gen.set_amplitude(0.0) + time.sleep(1) + + # Fast attack, slow release (sustained) + print("3. Sustained (fast attack, slow release)...") + wave_gen.set_envelope_params(attack=0.01, release=0.3, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.5) + wave_gen.set_amplitude(0.0) + time.sleep(1.5) + + # Medium attack and release (balanced) + print("4. Balanced (medium attack/release)...") + wave_gen.set_envelope_params(attack=0.05, release=0.05, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.8) + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Envelope Control Demonstration") +print("Listen to different attack/release characteristics") +print("Press Ctrl+C to stop") + +App.run(user_loop=envelope_demo) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py new file mode 100644 index 00000000..715e9cc3 --- /dev/null +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Custom Speaker Configuration Example + +Demonstrates how to use a pre-configured Speaker instance with WaveGenerator. +Use this approach when you need: +- Specific USB speaker selection (USB_SPEAKER_2, etc.) +- Different audio format (S16_LE, etc.) +- Explicit device name ("plughw:CARD=Device,DEV=0") +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_peripherals.speaker import Speaker +from arduino.app_utils import App + +# List available USB speakers +available_speakers = Speaker.list_usb_devices() +print(f"Available USB speakers: {available_speakers}") + +# Create and configure a Speaker with specific parameters +# For optimal real-time synthesis, align periodsize with WaveGenerator block_duration +block_duration = 0.03 # Default WaveGenerator block duration +sample_rate = 16000 +periodsize = int(sample_rate * block_duration) # 480 frames @ 16kHz + +speaker = Speaker( + device=Speaker.USB_SPEAKER_1, # or explicit device like "plughw:CARD=Device" + sample_rate=sample_rate, + channels=1, + format="FLOAT_LE", + periodsize=periodsize, # Align with WaveGenerator blocks (eliminates glitches) + queue_maxsize=10, # Low latency for real-time audio +) + +# Start the external Speaker manually +# WaveGenerator won't manage its lifecycle (ownership pattern) +speaker.start() + +# Create WaveGenerator with the external speaker +wave_gen = WaveGenerator( + sample_rate=sample_rate, + speaker=speaker, # Pass pre-configured speaker + wave_type="sine", + glide=0.02, +) + +# Start the WaveGenerator (speaker already started above) +App.start_brick(wave_gen) + + +def play_sequence(): + """Play a simple frequency sequence.""" + frequencies = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25] # C4 to C5 + + for freq in frequencies: + print(f"Playing {freq:.2f} Hz") + wave_gen.set_frequency(freq) + wave_gen.set_amplitude(0.7) + time.sleep(0.5) + + # Fade out + wave_gen.set_amplitude(0.0) + time.sleep(1) + + +print("Playing musical scale with external speaker...") +print("Press Ctrl+C to stop") + +App.run(user_loop=play_sequence) + +# Stop external Speaker manually (WaveGenerator doesn't manage external lifecycle) +speaker.stop() +print("Done") diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py similarity index 81% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py index 44241a76..cb9a1081 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py similarity index 81% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py index 740740a3..11b8ca9d 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py similarity index 80% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py index 55fb6ca7..4d8768aa 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py similarity index 79% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py index ff1c7cc0..19afb676 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py similarity index 81% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py index 0a98cd99..74906149 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/4_on_message.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/4_on_message.py similarity index 80% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/4_on_message.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/4_on_message.py index cfec4c7c..7eb1316f 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/4_on_message.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/4_on_message.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/5_send_message.py b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/5_send_message.py similarity index 80% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/5_send_message.py rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/5_send_message.py index 9bb52450..00e19bc7 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/5_send_message.py +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/examples/arduino/web_ui/5_send_message.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/models-list.yaml b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/models-list.yaml similarity index 94% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/models-list.yaml rename to debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/models-list.yaml index 7c511011..b4109df2 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/models-list.yaml +++ b/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.6.1/models-list.yaml @@ -18,7 +18,7 @@ models: - yolox-object-detection: runner: brick name : "General purpose object detection - YoloX" - description: "General purpose object detection model based on YoloX Nano. This model is trained on the COCO dataset and can detect 80 different object classes." + description: "General purpose object detection model based on YoloX-Nano. This model is trained on the COCO dataset and can detect 80 different object classes." model_configuration: "EI_OBJ_DETECTION_MODEL": "/models/ootb/ei/yolo-x-nano.eim" model_labels: @@ -105,6 +105,7 @@ models: metadata: source: "edgeimpulse" ei-project-id: 717280 + ei-model-url: "https://studio.edgeimpulse.com/public/717280/live" source-model-id: "YOLOX-Nano" source-model-url: "https://github.com/Megvii-BaseDetection/YOLOX" bricks: @@ -1071,6 +1072,7 @@ models: metadata: source: "edgeimpulse" ei-project-id: 708500 + ei-model-url: "https://studio.edgeimpulse.com/public/708500/live" ei-gpu-mode: true source-model-id: "MobileNetV2" source-model-url: "https://www.tensorflow.org/api_docs/python/tf/keras/applications/MobileNetV2" @@ -1089,9 +1091,10 @@ models: metadata: source: "edgeimpulse" ei-project-id: 755016 + ei-model-url: "https://studio.edgeimpulse.com/public/755016/live" ei-gpu-mode: true source-model-id: "person-classification-wakevision" - source-model-url: "https://studio.edgeimpulse.com/studio/755016" + source-model-url: "https://studio.edgeimpulse.com/public/755016/live" bricks: - arduino:image_classification - arduino:video_image_classification @@ -1103,15 +1106,16 @@ models: "EI_V_ANOMALY_DETECTION_MODEL": "/models/ootb/ei/concrete-crack-anomaly-detection.eim" metadata: source: "edgeimpulse" - ei-project-id: 288658 + ei-project-id: 800941 + ei-model-url: "https://studio.edgeimpulse.com/public/800941/live" source-model-id: "concrete-crack-anomaly-detection" - source-model-url: "https://studio.edgeimpulse.com/public/288658" + source-model-url: "https://studio.edgeimpulse.com/public/800941/live" bricks: - arduino:visual_anomaly_detection - keyword-spotting-hey-arduino: runner: brick name : "Keyword spotting - Hey Arduino!" - description: "A keyword-spotting model to detect the 'Hey Arduino!' in audio recordings" + description: "A keyword-spotting model to detect the 'Hey Arduino!' in audio streams." model_configuration: "EI_KEYWORD_SPOTTING_MODEL": "/models/ootb/ei/keyword-spotting-hey-arduino.eim" model_labels: @@ -1120,12 +1124,14 @@ models: - "other" metadata: source: "edgeimpulse" - ei-project-id: 757509 + ei-project-id: 757509 + ei-model-url: "https://studio.edgeimpulse.com/studio/757509/live" ei-impulse-id: 30 source-model-id: "hey-arduino" - source-model-url: "https://studio.edgeimpulse.com/studio/757509" + source-model-url: "https://studio.edgeimpulse.com/studio/757509/live" + private: true bricks: - - arduino:keyword_spotter + - arduino:keyword_spotting - updown-wave-motion-detection: runner: brick name : "Continuous motion detection" @@ -1140,9 +1146,11 @@ models: metadata: source: "edgeimpulse" ei-project-id: 734960 + ei-model-url: "https://studio.edgeimpulse.com/public/734960/live" source-model-id: "continuous-motion-detection" - source-model-url: "https://studio.edgeimpulse.com/studio/734960" - brick: arduino:motion_detection + source-model-url: "https://studio.edgeimpulse.com/public/734960/live" + bricks: + - arduino:motion_detection - fan-anomaly-detection: runner: brick name : "Fan anomaly detection" @@ -1152,8 +1160,9 @@ models: metadata: source: "edgeimpulse" ei-project-id: 774707 + ei-model-url: "https://studio.edgeimpulse.com/public/774707/live" source-model-id: "fan-anomaly-detection" - source-model-url: "https://studio.edgeimpulse.com/studio/774707" + source-model-url: "https://studio.edgeimpulse.com/public/774707/live" bricks: - arduino:vibration_anomaly_detection - glass-breaking: @@ -1168,7 +1177,9 @@ models: metadata: source: "edgeimpulse" ei-project-id: 749446 + ei-model-url: "https://studio.edgeimpulse.com/public/749446/live" source-model-id: "glass-breaking" - source-model-url: "https://studio.edgeimpulse.com/studio/749446" + source-model-url: "https://studio.edgeimpulse.com/public/749446/live" + private: true bricks: - - arduino:audio_classifier + - arduino:audio_classification diff --git a/internal/api/docs/openapi.yaml b/internal/api/docs/openapi.yaml index 77721c82..fdecc22d 100644 --- a/internal/api/docs/openapi.yaml +++ b/internal/api/docs/openapi.yaml @@ -45,12 +45,6 @@ paths: description: Creates a new app in the default app location. operationId: createApp parameters: - - description: If true, the app will not be created with the python part. - in: query - name: skip-python - schema: - description: If true, the app will not be created with the python part. - type: boolean - description: If true, the app will not be created with the sketch part. in: query name: skip-sketch @@ -1326,6 +1320,11 @@ components: $ref: '#/components/schemas/AIModel' nullable: true type: array + config_variables: + items: + $ref: '#/components/schemas/BrickConfigVariable' + nullable: true + type: array description: type: string id: @@ -1346,6 +1345,9 @@ components: variables: additionalProperties: $ref: '#/components/schemas/BrickVariable' + description: 'Deprecated: use config_variables instead. This field is kept + for backward compatibility.' + nullable: true type: object type: object BrickInstance: diff --git a/internal/api/handlers/app_create.go b/internal/api/handlers/app_create.go index ed26ee61..9e757bfe 100644 --- a/internal/api/handlers/app_create.go +++ b/internal/api/handlers/app_create.go @@ -44,17 +44,9 @@ func HandleAppCreate( defer r.Body.Close() queryParams := r.URL.Query() - skipPythonStr := queryParams.Get("skip-python") skipSketchStr := queryParams.Get("skip-sketch") - - skipPython := queryParamsValidator(skipPythonStr) skipSketch := queryParamsValidator(skipSketchStr) - if skipPython && skipSketch { - render.EncodeResponse(w, http.StatusBadRequest, models.ErrorResponse{Details: "cannot skip both python and sketch"}) - return - } - var req CreateAppRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { slog.Error("unable to decode app create request", slog.String("error", err.Error())) @@ -68,7 +60,6 @@ func HandleAppCreate( Name: req.Name, Icon: req.Icon, Description: req.Description, - SkipPython: skipPython, SkipSketch: skipSketch, }, idProvider, diff --git a/internal/e2e/client/client.gen.go b/internal/e2e/client/client.gen.go index 25472727..eb1a7971 100644 --- a/internal/e2e/client/client.gen.go +++ b/internal/e2e/client/client.gen.go @@ -143,19 +143,22 @@ type BrickCreateUpdateRequest struct { // BrickDetailsResult defines model for BrickDetailsResult. type BrickDetailsResult struct { - ApiDocsPath *string `json:"api_docs_path,omitempty"` - Author *string `json:"author,omitempty"` - Category *string `json:"category,omitempty"` - CodeExamples *[]CodeExample `json:"code_examples"` - CompatibleModels *[]AIModel `json:"compatible_models"` - Description *string `json:"description,omitempty"` - Id *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Readme *string `json:"readme,omitempty"` - RequireModel *bool `json:"require_model,omitempty"` - Status *string `json:"status,omitempty"` - UsedByApps *[]AppReference `json:"used_by_apps"` - Variables *map[string]BrickVariable `json:"variables,omitempty"` + ApiDocsPath *string `json:"api_docs_path,omitempty"` + Author *string `json:"author,omitempty"` + Category *string `json:"category,omitempty"` + CodeExamples *[]CodeExample `json:"code_examples"` + CompatibleModels *[]AIModel `json:"compatible_models"` + ConfigVariables *[]BrickConfigVariable `json:"config_variables"` + Description *string `json:"description,omitempty"` + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Readme *string `json:"readme,omitempty"` + RequireModel *bool `json:"require_model,omitempty"` + Status *string `json:"status,omitempty"` + UsedByApps *[]AppReference `json:"used_by_apps"` + + // Variables Deprecated: use config_variables instead. This field is kept for backward compatibility. + Variables *map[string]BrickVariable `json:"variables"` } // BrickInstance defines model for BrickInstance. @@ -423,9 +426,6 @@ type GetAppsParams struct { // CreateAppParams defines parameters for CreateApp. type CreateAppParams struct { - // SkipPython If true, the app will not be created with the python part. - SkipPython *bool `form:"skip-python,omitempty" json:"skip-python,omitempty"` - // SkipSketch If true, the app will not be created with the sketch part. SkipSketch *bool `form:"skip-sketch,omitempty" json:"skip-sketch,omitempty"` } @@ -1287,22 +1287,6 @@ func NewCreateAppRequestWithBody(server string, params *CreateAppParams, content if params != nil { queryValues := queryURL.Query() - if params.SkipPython != nil { - - if queryFrag, err := runtime.StyleParamWithLocation("form", true, "skip-python", runtime.ParamLocationQuery, *params.SkipPython); err != nil { - return nil, err - } else if parsed, err := url.ParseQuery(queryFrag); err != nil { - return nil, err - } else { - for k, v := range parsed { - for _, v2 := range v { - queryValues.Add(k, v2) - } - } - } - - } - if params.SkipSketch != nil { if queryFrag, err := runtime.StyleParamWithLocation("form", true, "skip-sketch", runtime.ParamLocationQuery, *params.SkipSketch); err != nil { diff --git a/internal/e2e/daemon/app_test.go b/internal/e2e/daemon/app_test.go index b62b882b..86479fc9 100644 --- a/internal/e2e/daemon/app_test.go +++ b/internal/e2e/daemon/app_test.go @@ -93,7 +93,6 @@ func TestCreateApp(t *testing.T) { { name: "should return 400 bad request when icon is not a single emoji", parameters: client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, body: client.CreateAppRequest{ @@ -107,7 +106,6 @@ func TestCreateApp(t *testing.T) { { name: "should create app successfully when icon is empty", parameters: client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, body: client.CreateAppRequest{ @@ -121,7 +119,6 @@ func TestCreateApp(t *testing.T) { { name: "should return 201 Created on first successful creation", parameters: client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, body: defaultRequestBody, @@ -130,30 +127,15 @@ func TestCreateApp(t *testing.T) { { name: "should return 409 Conflict when creating a duplicate app", parameters: client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, body: defaultRequestBody, expectedStatusCode: http.StatusConflict, expectedErrorDetails: f.Ptr("app already exists"), }, - { - name: "should return 201 Created on successful creation with skip_python", - parameters: client.CreateAppParams{ - SkipPython: f.Ptr(true), - SkipSketch: f.Ptr(false), - }, - body: client.CreateAppRequest{ - Icon: f.Ptr("🌎"), - Name: "HelloWorld_2", - Description: f.Ptr("My HelloWorld_2 description"), - }, - expectedStatusCode: http.StatusCreated, - }, { name: "should return 201 Created on successful creation with skip_sketch", parameters: client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(true), }, body: client.CreateAppRequest{ @@ -163,16 +145,6 @@ func TestCreateApp(t *testing.T) { }, expectedStatusCode: http.StatusCreated, }, - { - name: "should return 400 Bad Request when creating an app with both filters set to true", - parameters: client.CreateAppParams{ - SkipPython: f.Ptr(true), - SkipSketch: f.Ptr(true), - }, - body: defaultRequestBody, - expectedStatusCode: http.StatusBadRequest, - expectedErrorDetails: f.Ptr("cannot skip both python and sketch"), - }, } for _, tc := range testCases { @@ -985,7 +957,6 @@ func TestAppList(t *testing.T) { expectedAppNumber := 5 for i := 0; i < expectedAppNumber; i++ { r, err := httpClient.CreateApp(t.Context(), &client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, client.CreateAppRequest{ Icon: f.Ptr("🌎"), @@ -1003,7 +974,6 @@ func TestAppList(t *testing.T) { t.Run("AppListDefault_success", func(t *testing.T) { r, err := httpClient.CreateApp(t.Context(), &client.CreateAppParams{ - SkipPython: f.Ptr(false), SkipSketch: f.Ptr(false), }, client.CreateAppRequest{ Icon: f.Ptr("🌎"), diff --git a/internal/e2e/daemon/brick_test.go b/internal/e2e/daemon/brick_test.go index 5d709bb3..c0a13390 100644 --- a/internal/e2e/daemon/brick_test.go +++ b/internal/e2e/daemon/brick_test.go @@ -127,6 +127,21 @@ func TestBricksDetails(t *testing.T) { Name: f.Ptr("Person classification"), Description: f.Ptr("Person classification model based on WakeVision dataset. This model is trained to classify images into two categories: person and not-person."), }} + expectConfigVariables := []client.BrickConfigVariable{ + { + Name: f.Ptr("CUSTOM_MODEL_PATH"), + Value: f.Ptr("/home/arduino/.arduino-bricks/ei-models"), + Description: f.Ptr("path to the custom model directory"), + Required: f.Ptr(false), + }, + { + Name: f.Ptr("EI_CLASSIFICATION_MODEL"), + Value: f.Ptr("/models/ootb/ei/mobilenet-v2-224px.eim"), + Description: f.Ptr("path to the model file"), + Required: f.Ptr(false), + }, + } + response, err := httpClient.GetBrickDetailsWithResponse(t.Context(), validBrickID, func(ctx context.Context, req *http.Request) error { return nil }) require.NoError(t, err) require.Equal(t, http.StatusOK, response.StatusCode(), "status code should be 200 ok") @@ -147,5 +162,7 @@ func TestBricksDetails(t *testing.T) { require.Equal(t, expectedUsedByApps, *(response.JSON200.UsedByApps)) require.NotNil(t, response.JSON200.CompatibleModels, "Models should not be nil") require.Equal(t, expectedModelLiteInfo, *(response.JSON200.CompatibleModels)) + require.NotNil(t, response.JSON200.ConfigVariables, "ConfigVariables should not be nil") + require.Equal(t, expectConfigVariables, *(response.JSON200.ConfigVariables)) }) } diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md b/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md deleted file mode 100644 index ba9da420..00000000 --- a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/cloud_llm/API.md +++ /dev/null @@ -1,107 +0,0 @@ -# cloud_llm API Reference - -## Index - -- Class `CloudLLM` -- Class `CloudModel` - ---- - -## `CloudLLM` class - -```python -class CloudLLM(api_key: str, model: Union[str, CloudModel], system_prompt: str, temperature: Optional[float], timeout: int) -``` - -A simplified, opinionated wrapper for common LangChain conversational patterns. - -This class provides a single interface to manage stateless chat and chat with memory. - -### Parameters - -- **api_key**: The API key for the LLM service. -- **model**: The model identifier as per LangChain specification (e.g., "anthropic:claude-3-sonnet-20240229") -or by using a CloudModels enum (e.g. CloudModels.OPENAI_GPT). Defaults to CloudModel.ANTHROPIC_CLAUDE. -- **system_prompt**: The global system-level instruction for the AI. -- **temperature**, default=0.7: The sampling temperature for response generation. Defaults to 0.7. -- **timeout**, default=30 seconds: The maximum time to wait for a response from the LLM service, in seconds. Defaults to 30 seconds. - -### Raises - -- **ValueError**: If the API key is missing. - -### Methods - -#### `with_memory(max_messages: int)` - -Enables conversational memory for this instance. - -This allows the chatbot to remember previous user and AI messages. -Calling this modifies the instance to be stateful. - -##### Parameters - -- **max_messages**: The total number of past messages (user + AI) to -keep in the conversation window. Set to 0 to disable memory. - -##### Returns - -- (*self*): The current CloudLLM instance for method chaining. - -#### `chat(message: str)` - -Sends a single message to the AI and gets a complete response synchronously. - -This is the primary way to interact. It automatically handles memory -based on how the instance was configured. - -##### Parameters - -- **message**: The user's message. - -##### Returns - --: The AI's complete response as a string. - -##### Raises - -- **RuntimeError**: If the chat model is not initialized or if text generation fails. - -#### `chat_stream(message: str)` - -Sends a single message to the AI and streams the response as a synchronous generator. - -Use this to get tokens as they are generated, perfect for a streaming UI. - -##### Parameters - -- **message**: The user's message. - -##### Returns - -- (*str*): Chunks of the AI's response as they become available. - -##### Raises - -- **RuntimeError**: If the chat model is not initialized or if text generation fails. -- **AlreadyGenerating**: If the chat model is already streaming a response. - -#### `stop_stream()` - -Signals the LLM to stop generating a response. - -#### `clear_memory()` - -Clears the conversational memory. - -This only has an effect if with_memory() has been called. - - ---- - -## `CloudModel` class - -```python -class CloudModel() -``` - diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/air_quality_monitoring/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/air_quality_monitoring/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/air_quality_monitoring/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/air_quality_monitoring/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/arduino_cloud/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/arduino_cloud/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/arduino_cloud/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/arduino_cloud/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md similarity index 91% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md index 87a5213e..7573beee 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/audio_classification/API.md +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/audio_classification/API.md @@ -67,7 +67,7 @@ Stop real-time audio classification. Terminates audio capture and releases any associated resources. -#### `classify_from_file(audio_path: str, confidence: int)` +#### `classify_from_file(audio_path: str, confidence: float)` Classify audio content from a WAV file. @@ -80,9 +80,8 @@ Supported sample widths: ##### Parameters - **audio_path** (*str*): Path to the `.wav` audio file to classify. -- **confidence** (*int*) (optional): Confidence threshold (0–1). If None, -the default confidence level specified during initialization -will be applied. +- **confidence** (*float*) (optional): Minimum confidence threshold (0.0–1.0) required +for a detection to be considered valid. Defaults to 0.8 (80%). ##### Returns diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/camera_code_detection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/camera_code_detection/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/camera_code_detection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/camera_code_detection/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md new file mode 100644 index 00000000..d2dd5903 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/cloud_llm/API.md @@ -0,0 +1,120 @@ +# cloud_llm API Reference + +## Index + +- Class `CloudLLM` +- Class `CloudModel` + +--- + +## `CloudLLM` class + +```python +class CloudLLM(api_key: str, model: Union[str, CloudModel], system_prompt: str, temperature: Optional[float], timeout: int) +``` + +A Brick for interacting with cloud-based Large Language Models (LLMs). + +This class wraps LangChain functionality to provide a simplified, unified interface +for chatting with models like Claude, GPT, and Gemini. It supports both synchronous +'one-shot' responses and streaming output, with optional conversational memory. + +### Parameters + +- **api_key** (*str*): The API access key for the target LLM service. Defaults to the +'API_KEY' environment variable. +- **model** (*Union[str, CloudModel]*): The model identifier. Accepts a `CloudModel` +enum member (e.g., `CloudModel.OPENAI_GPT`) or its corresponding raw string +value (e.g., `'gpt-4o-mini'`). Defaults to `CloudModel.ANTHROPIC_CLAUDE`. +- **system_prompt** (*str*): A system-level instruction that defines the AI's persona +and constraints (e.g., "You are a helpful assistant"). Defaults to empty. +- **temperature** (*Optional[float]*): The sampling temperature between 0.0 and 1.0. +Higher values make output more random/creative; lower values make it more +deterministic. Defaults to 0.7. +- **timeout** (*int*): The maximum duration in seconds to wait for a response before +timing out. Defaults to 30. + +### Raises + +- **ValueError**: If `api_key` is not provided (empty string). + +### Methods + +#### `with_memory(max_messages: int)` + +Enables conversational memory for this instance. + +Configures the Brick to retain a window of previous messages, allowing the +AI to maintain context across multiple interactions. + +##### Parameters + +- **max_messages** (*int*): The maximum number of messages (user + AI) to keep +in history. Older messages are discarded. Set to 0 to disable memory. +Defaults to 10. + +##### Returns + +- (*CloudLLM*): The current instance, allowing for method chaining. + +#### `chat(message: str)` + +Sends a message to the AI and blocks until the complete response is received. + +This method automatically manages conversation history if memory is enabled. + +##### Parameters + +- **message** (*str*): The input text prompt from the user. + +##### Returns + +- (*str*): The complete text response generated by the AI. + +##### Raises + +- **RuntimeError**: If the internal chain is not initialized or if the API request fails. + +#### `chat_stream(message: str)` + +Sends a message to the AI and yields response tokens as they are generated. + +This allows for processing or displaying the response in real-time (streaming). +The generation can be interrupted by calling `stop_stream()`. + +##### Parameters + +- **message** (*str*): The input text prompt from the user. + +##### Returns + +- (*str*): Chunks of text (tokens) from the AI response. + +##### Raises + +- **RuntimeError**: If the internal chain is not initialized or if the API request fails. +- **AlreadyGenerating**: If a streaming session is already active. + +#### `stop_stream()` + +Signals the active streaming generation to stop. + +This sets an internal flag that causes the `chat_stream` iterator to break +early. It has no effect if no stream is currently running. + +#### `clear_memory()` + +Clears the conversational memory history. + +Resets the stored context. This is useful for starting a new conversation +topic without previous context interfering. Only applies if memory is enabled. + + +--- + +## `CloudModel` class + +```python +class CloudModel() +``` + diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_sqlstore/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/dbstorage_tsstore/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/image_classification/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/image_classification/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/image_classification/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/image_classification/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/keyword_spotting/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/keyword_spotting/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/keyword_spotting/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/keyword_spotting/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/mood_detector/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/mood_detector/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/mood_detector/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/mood_detector/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/motion_detection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/motion_detection/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/motion_detection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/motion_detection/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/mqtt/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/mqtt/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/mqtt/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/mqtt/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md similarity index 90% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md index c8c84812..bf58415c 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/object_detection/API.md +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/object_detection/API.md @@ -19,6 +19,14 @@ This module processes an input image and returns: - Corresponding class labels - Confidence scores for each detection +### Parameters + +- **confidence** (*float*): Minimum confidence threshold for detections. Default is 0.3 (30%). + +### Raises + +- **ValueError**: If model information cannot be retrieved. + ### Methods #### `detect_from_file(image_path: str, confidence: float)` @@ -60,7 +68,7 @@ Draw bounding boxes on an image enclosing detected objects using PIL. ##### Returns -: Image with bounding boxes and key points drawn. -None if no detection or invalid image. +None if input image or detections are invalid. #### `process(item)` diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/streamlit_ui/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/streamlit_ui/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/streamlit_ui/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/streamlit_ui/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/vibration_anomaly_detection/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/video_imageclassification/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/video_imageclassification/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/video_imageclassification/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/video_imageclassification/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/video_objectdetection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/video_objectdetection/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/video_objectdetection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/video_objectdetection/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/visual_anomaly_detection/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md new file mode 100644 index 00000000..f8977727 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/wave_generator/API.md @@ -0,0 +1,151 @@ +# wave_generator API Reference + +## Index + +- Class `WaveGenerator` + +--- + +## `WaveGenerator` class + +```python +class WaveGenerator(sample_rate: int, wave_type: WaveType, block_duration: float, attack: float, release: float, glide: float, speaker: Speaker) +``` + +Continuous wave generator brick for audio synthesis. + +This brick generates continuous audio waveforms (sine, square, sawtooth, triangle) +and streams them to a USB speaker in real-time. It provides smooth transitions +between frequency and amplitude changes using configurable envelope parameters. + +The generator runs continuously in a background thread, producing audio blocks +at a steady rate with minimal latency. + +### Parameters + +- **sample_rate** (*int*): Audio sample rate in Hz (default: 16000). +- **wave_type** (*WaveType*): Initial waveform type (default: "sine"). +- **block_duration** (*float*): Duration of each audio block in seconds (default: 0.01). +- **attack** (*float*): Attack time for amplitude envelope in seconds (default: 0.01). +- **release** (*float*): Release time for amplitude envelope in seconds (default: 0.03). +- **glide** (*float*): Frequency glide time (portamento) in seconds (default: 0.02). +- **speaker** (*Speaker*) (optional): Pre-configured Speaker instance. If None, WaveGenerator +will create an internal Speaker optimized for real-time synthesis with: +- periodsize aligned to block_duration (eliminates buffer mismatch) +- queue_maxsize=8 (low latency: ~80ms max buffer) +- format=FLOAT_LE, channels=1 + +If providing an external Speaker, ensure: +- sample_rate matches WaveGenerator's sample_rate +- periodsize = int(sample_rate × block_duration) for optimal alignment +- Speaker is started/stopped manually (WaveGenerator won't manage its lifecycle) + +Example external Speaker configuration: + speaker = Speaker( + device="plughw:CARD=UH34", + sample_rate=16000, + format="FLOAT_LE", + periodsize=160, # 16000 × 0.01 = 160 frames + queue_maxsize=8 + ) + +### Raises + +- **SpeakerException**: If no USB speaker is found or device is busy. + +### Attributes + +- **sample_rate** (*int*): Audio sample rate in Hz (default: 16000). +- **wave_type** (*WaveType*): Type of waveform to generate. +- **frequency** (*float*): Current output frequency in Hz. +- **amplitude** (*float*): Current output amplitude (0.0-1.0). + +### Methods + +#### `start()` + +Start the wave generator and audio output. + +This starts the speaker device (if internally owned) and launches the producer thread +that continuously generates and streams audio blocks. + +#### `stop()` + +Stop the wave generator and audio output. + +This stops the producer thread and closes the speaker device (if internally owned). + +#### `set_frequency(frequency: float)` + +Set the target output frequency. + +The frequency will smoothly transition to the new value over the +configured glide time. + +##### Parameters + +- **frequency** (*float*): Target frequency in Hz (typically 20-8000 Hz). + +#### `set_amplitude(amplitude: float)` + +Set the target output amplitude. + +The amplitude will smoothly transition to the new value over the +configured attack/release time. + +##### Parameters + +- **amplitude** (*float*): Target amplitude in range [0.0, 1.0]. + +#### `set_wave_type(wave_type: WaveType)` + +Change the waveform type. + +##### Parameters + +- **wave_type** (*WaveType*): One of "sine", "square", "sawtooth", "triangle". + +##### Raises + +- **ValueError**: If wave_type is not valid. + +#### `set_volume(volume: int)` + +Set the speaker volume level. + +This is a wrapper that controls the hardware volume of the USB speaker device. + +##### Parameters + +- **volume** (*int*): Hardware volume level (0-100). + +##### Raises + +- **SpeakerException**: If the mixer is not available or if volume cannot be set. + +#### `get_volume()` + +Get the current speaker volume level. + +##### Returns + +- (*int*): Current hardware volume level (0-100). + +#### `set_envelope_params(attack: float, release: float, glide: float)` + +Update envelope parameters. + +##### Parameters + +- **attack** (*float*) (optional): Attack time in seconds. +- **release** (*float*) (optional): Release time in seconds. +- **glide** (*float*) (optional): Frequency glide time in seconds. + +#### `get_state()` + +Get current generator state. + +##### Returns + +- (*dict*): Dictionary containing current frequency, amplitude, wave type, etc. + diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/weather_forecast/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/weather_forecast/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_bricks/weather_forecast/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/weather_forecast/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md similarity index 76% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md index 4619aed5..ec08afdb 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_bricks/web_ui/API.md +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_bricks/web_ui/API.md @@ -9,7 +9,7 @@ ## `WebUI` class ```python -class WebUI(addr: str, port: int, ui_path_prefix: str, api_path_prefix: str, assets_dir_path: str, certs_dir_path: str, use_ssl: bool) +class WebUI(addr: str, port: int, ui_path_prefix: str, api_path_prefix: str, assets_dir_path: str, certs_dir_path: str, use_tls: bool, use_ssl: bool | None) ``` Module for deploying a web server that can host a web application and expose APIs to its clients. @@ -24,21 +24,38 @@ and support real-time communication between the client and the server. - **ui_path_prefix** (*str*) (optional), default="" (root): URL prefix for UI routes. Defaults to "" (root). - **api_path_prefix** (*str*) (optional), default="" (root): URL prefix for API routes. Defaults to "" (root). - **assets_dir_path** (*str*) (optional), default="/app/assets": Path to static assets directory. Defaults to "/app/assets". -- **certs_dir_path** (*str*) (optional), default="/app/certs": Path to SSL certificates directory. Defaults to "/app/certs". -- **use_ssl** (*bool*) (optional), default=False: Enable SSL/HTTPS. Defaults to False. +- **certs_dir_path** (*str*) (optional), default="/app/certs": Path to TLS certificates directory. Defaults to "/app/certs". +- **use_tls** (*bool*) (optional), default=False: Enable TLS/HTTPS. Defaults to False. +- **use_ssl** (*bool*) (optional), default=None: Deprecated. Use use_tls instead. Defaults to None. ### Methods +#### `local_url()` + +Get the locally addressable URL of the web server. + +##### Returns + +- (*str*): The server's URL (including protocol, address, and port). + +#### `url()` + +Get the externally addressable URL of the web server. + +##### Returns + +- (*str*): The server's URL (including protocol, address, and port). + #### `start()` Start the web server asynchronously. -This sets up static file routing and WebSocket event handlers, configures SSL if enabled, and launches the server using Uvicorn. +This sets up static file routing and WebSocket event handlers, configures TLS if enabled, and launches the server using Uvicorn. ##### Raises - **RuntimeError**: If 'index.html' is missing in the static assets directory. -- **RuntimeError**: If SSL is enabled but certificates are missing or fail to generate. +- **RuntimeError**: If TLS is enabled but certificates fail to generate. - **RuntimeWarning**: If the server is already running. #### `stop()` @@ -47,7 +64,7 @@ Stop the web server gracefully. Waits up to 5 seconds for current requests to finish before terminating. -#### `expose_api(method: str, path: str, function: callable)` +#### `expose_api(method: str, path: str, function: Callable)` Register a route with the specified HTTP method and path. @@ -57,7 +74,7 @@ The path will be prefixed with the api_path_prefix configured during initializat - **method** (*str*): HTTP method to use (e.g., "GET", "POST"). - **path** (*str*): URL path for the API endpoint (without the prefix). -- **function** (*callable*): Function to execute when the route is accessed. +- **function** (*Callable*): Function to execute when the route is accessed. #### `on_connect(callback: Callable[[str], None])` @@ -79,7 +96,7 @@ The callback should accept a single argument: the session ID (sid) of the discon - **callback** (*Callable[[str], None]*): Function to call when a client disconnects. Receives the session ID (sid) as its only argument. -#### `on_message(message_type: str, callback: Callable[[str, any], any])` +#### `on_message(message_type: str, callback: Callable[[str, Any], Any])` Register a callback function for a specific WebSocket message type received by clients. @@ -91,10 +108,10 @@ with a message type suffix "_response". ##### Parameters - **message_type** (*str*): The message type name to listen for. -- **callback** (*Callable[[str, any], any]*): Function to handle the message. Receives two arguments: +- **callback** (*Callable[[str, Any], Any]*): Function to handle the message. Receives two arguments: the session ID (sid) and the incoming message data. -#### `send_message(message_type: str, message: dict | str, room: str)` +#### `send_message(message_type: str, message: dict | str, room: str | None)` Send a message to connected WebSocket clients. diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/microphone/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/microphone/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/microphone/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/microphone/API.md diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md similarity index 79% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md index 3cddad0f..94c64118 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/api-docs/arduino/app_peripherals/speaker/API.md +++ b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/speaker/API.md @@ -21,7 +21,7 @@ Custom exception for Speaker errors. ## `Speaker` class ```python -class Speaker(device: str, sample_rate: int, channels: int, format: str) +class Speaker(device: str, sample_rate: int, channels: int, format: str, periodsize: int, queue_maxsize: int) ``` Speaker class for reproducing audio using ALSA PCM interface. @@ -32,6 +32,12 @@ Speaker class for reproducing audio using ALSA PCM interface. - **sample_rate** (*int*): Sample rate in Hz (default: 16000). - **channels** (*int*): Number of audio channels (default: 1). - **format** (*str*): Audio format (default: "S16_LE"). +- **periodsize** (*int*): ALSA period size in frames (default: None = use hardware default). +For real-time synthesis, set to match generation block size. +For streaming/file playback, leave as None for hardware-optimal value. +- **queue_maxsize** (*int*): Maximum application queue depth in blocks (default: 100). +Lower values (5-20) reduce latency for interactive audio. +Higher values (50-200) provide stability for streaming. ### Raises diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/usb_camera/API.md b/internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/usb_camera/API.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/api-docs/arduino/app_peripherals/usb_camera/API.md rename to internal/e2e/daemon/testdata/assets/0.6.1/api-docs/arduino/app_peripherals/usb_camera/API.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/bricks-list.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/bricks-list.yaml similarity index 93% rename from internal/e2e/daemon/testdata/assets/0.5.0/bricks-list.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/bricks-list.yaml index a4747e86..8d79e540 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/bricks-list.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/bricks-list.yaml @@ -5,7 +5,6 @@ bricks: local database. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: storage @@ -17,7 +16,6 @@ bricks: \ or with custom object detection models trained on Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -38,7 +36,6 @@ bricks: ' require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: text @@ -47,7 +44,6 @@ bricks: description: Scans a camera for barcodes and QR codes require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -64,7 +60,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: audio @@ -81,7 +76,6 @@ bricks: description: Connects to Arduino Cloud require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -90,6 +84,17 @@ bricks: description: Arduino Cloud Device ID - name: ARDUINO_SECRET description: Arduino Cloud Secret +- id: arduino:wave_generator + name: Wave Generator + description: Continuous wave generator for audio synthesis. Generates sine, square, + sawtooth, and triangle waveforms with smooth frequency and amplitude transitions. + require_container: false + require_model: false + mount_devices_into_container: false + ports: [] + category: audio + required_devices: + - speaker - id: arduino:image_classification name: Image Classification description: "Brick for image classification using a pre-trained model. It processes\ @@ -98,7 +103,6 @@ bricks: \ image classification models trained on Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: video @@ -115,7 +119,6 @@ bricks: description: A simplified user interface based on Streamlit and Python. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: - 7000 @@ -135,7 +138,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -155,7 +157,6 @@ bricks: APIs and a WebSocket exposed by a web server. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: - 7000 @@ -172,7 +173,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: audio @@ -202,7 +202,6 @@ bricks: ' require_container: true require_model: true - require_devices: true mount_devices_into_container: true ports: [] category: video @@ -224,7 +223,6 @@ bricks: and weather APIs. Requires an internet connection. require_container: false require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: miscellaneous @@ -241,7 +239,6 @@ bricks: ' require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: null @@ -259,7 +256,6 @@ bricks: built on top of InfluxDB. require_container: true require_model: false - require_devices: false mount_devices_into_container: false ports: [] category: storage @@ -283,7 +279,6 @@ bricks: \ detection models trained on the Edge Impulse platform. \n" require_container: true require_model: true - require_devices: false mount_devices_into_container: false ports: [] category: image @@ -312,7 +307,6 @@ bricks: ' require_container: true require_model: true - require_devices: true mount_devices_into_container: true ports: [] category: null @@ -328,3 +322,15 @@ bricks: description: path to the model file - name: VIDEO_DEVICE default_value: /dev/video1 +- id: arduino:cloud_llm + name: Cloud LLM + description: Cloud LLM Brick enables seamless integration with cloud-based Large + Language Models (LLMs) for advanced AI capabilities in your Arduino projects. + require_container: false + require_model: false + mount_devices_into_container: false + ports: [] + category: null + variables: + - name: API_KEY + description: API Key for the cloud-based LLM service diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml index 6dbe38e4..0a710c5f 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/audio_classification/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/audio_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-audio-classifier-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/dbstorage_tsstore/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/dbstorage_tsstore/brick_compose.yaml similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/dbstorage_tsstore/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/dbstorage_tsstore/brick_compose.yaml diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml index d8207271..fe20b37e 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/image_classification/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/image_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-classification-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml index b4dd7963..4340871e 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/keyword_spotting/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/keyword_spotting/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-keyword-spot-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml index ef7fc730..abc10e77 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/motion_detection/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/motion_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-motion-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml index 9d418913..99871411 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/object_detection/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/object_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-obj-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml index aca4e2a2..e07c2890 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/vibration_anomaly_detection/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/vibration_anomaly_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-anomaly-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml similarity index 97% rename from internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml index 7e054acc..3dd8139a 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/compose/arduino/video_image_classification/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_image_classification/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-video-classification-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml similarity index 86% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml index dbca6363..804bc638 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/video_object_detection/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/video_object_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-video-obj-detection-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: @@ -13,7 +13,7 @@ services: volumes: - "${CUSTOM_MODEL_PATH:-/home/arduino/.arduino-bricks/ei-models/}:${CUSTOM_MODEL_PATH:-/home/arduino/.arduino-bricks/ei-models/}" - "/run/udev:/run/udev" - command: ["--model-file", "${EI_OBJ_DETECTION_MODEL:-/models/ootb/ei/yolo-x-nano.eim}", "--dont-print-predictions", "--mode", "streaming", "--force-target", "--preview-original-resolution", "--camera", "${VIDEO_DEVICE:-/dev/video1}"] + command: ["--model-file", "${EI_OBJ_DETECTION_MODEL:-/models/ootb/ei/yolo-x-nano.eim}", "--dont-print-predictions", "--mode", "streaming", "--preview-original-resolution", "--camera", "${VIDEO_DEVICE:-/dev/video1}"] healthcheck: test: [ "CMD-SHELL", "wget -q --spider http://ei-video-obj-detection-runner:4912 || exit 1" ] interval: 2s diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml index 0e71d75a..ced99fcb 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/compose/arduino/visual_anomaly_detection/brick_compose.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/compose/arduino/visual_anomaly_detection/brick_compose.yaml @@ -2,7 +2,7 @@ # CUSTOM_MODEL_PATH = path to the custom model directory services: ei-obj-video-anomalies-det-runner: - image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.5.0 + image: ${DOCKER_REGISTRY_BASE:-ghcr.io/arduino/}app-bricks/ei-models-runner:0.6.0 logging: driver: "json-file" options: diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/arduino_cloud/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/arduino_cloud/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/arduino_cloud/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/arduino_cloud/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/audio_classification/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/audio_classification/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/audio_classification/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/audio_classification/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/camera_code_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/camera_code_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/camera_code_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/camera_code_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/cloud_llm/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/cloud_llm/README.md new file mode 100644 index 00000000..add84514 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/cloud_llm/README.md @@ -0,0 +1,109 @@ +# Cloud LLM Brick + +The Cloud LLM Brick provides a seamless interface to interact with cloud-based Large Language Models (LLMs) such as OpenAI's GPT, Anthropic's Claude, and Google's Gemini. It abstracts the complexity of REST APIs, enabling you to send prompts, receive responses, and maintain conversational context within your Arduino projects. + +## Overview + +This Brick acts as a gateway to powerful AI models hosted in the cloud. It is designed to handle the nuances of network communication, authentication, and session management. Whether you need a simple one-off answer or a continuous conversation with memory, the Cloud LLM Brick provides a unified API for different providers. + +## Features + +- **Multi-Provider Support**: Compatible with major LLM providers including Anthropic (Claude), OpenAI (GPT), and Google (Gemini). +- **Conversational Memory**: Built-in support for windowed history, allowing the AI to remember context from previous exchanges. +- **Streaming Responses**: Receive text chunks in real-time as they are generated, ideal for responsive user interfaces. +- **Configurable Behavior**: Customize system prompts, temperature (creativity), and request timeouts. +- **Simple API**: Unified `chat` and `chat_stream` methods regardless of the underlying model provider. + +## Prerequisites + +- **Internet Connection**: The board must be connected to the internet to reach the LLM provider's API. +- **API Key**: A valid API key for the chosen service (e.g., OpenAI API Key, Anthropic API Key). +- **Python Dependencies**: The Brick relies on LangChain integration packages (`langchain-anthropic`, `langchain-openai`, `langchain-google-genai`). + +## Code Example and Usage + +### Basic Conversation + +This example initializes the Brick with an OpenAI model and performs a simple chat interaction. + +**Note:** The API key is not hardcoded. It is retrieved automatically from the **Brick Configuration** in App Lab. + +```python +import os +from arduino.app_bricks.cloud_llm import CloudLLM, CloudModel +from arduino.app_utils import App + +# Initialize the Brick (API key is loaded from configuration) +llm = CloudLLM( + model=CloudModel.OPENAI_GPT, + system_prompt="You are a helpful assistant for an IoT device." +) + +def simple_chat(): + # Send a prompt and print the response + response = llm.chat("What is the capital of Italy?") + print(f"AI: {response}") + +# Run the application +App.run(simple_chat) +``` + +### Streaming with Memory + +This example demonstrates how to enable conversational memory and process the response as a stream of tokens. + +```python +from arduino.app_bricks.cloud_llm import CloudLLM, CloudModel +from arduino.app_utils import App + +# Initialize with memory enabled (keeps last 10 messages) +# API Key is retrieved automatically from Brick Configuration +llm = CloudLLM( + model=CloudModel.ANTHROPIC_CLAUDE +).with_memory(max_messages=10) + +def chat_loop(): + while True: + user_input = input("You: ") + if user_input.lower() in ["exit", "quit"]: + break + + print("AI: ", end="", flush=True) + + # Stream the response token by token + for token in llm.chat_stream(user_input): + print(token, end="", flush=True) + print() # Newline after response + +App.run(chat_loop) +``` + +## Configuration + +The Brick is initialized with the following parameters: + +| Parameter | Type | Default | Description | +| :-------------- | :-------------------- | :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | +| `api_key` | `str` | `os.getenv("API_KEY")` | The authentication key for the LLM provider. **Recommended:** Set this via the **Brick Configuration** menu in App Lab instead of code. | +| `model` | `str` \| `CloudModel` | `CloudModel.ANTHROPIC_CLAUDE` | The specific model to use. Accepts a `CloudModel` enum or its string value. | +| `system_prompt` | `str` | `""` | A base instruction that defines the AI's behavior and persona. | +| `temperature` | `float` | `0.7` | Controls randomness. `0.0` is deterministic, `1.0` is creative. | +| `timeout` | `int` | `30` | Maximum time (in seconds) to wait for a response. | + +### Supported Models + +You can select a model using the `CloudModel` enum or by passing the corresponding raw string identifier. + +| Enum Constant | Raw String ID | Provider Documentation | +| :---------------------------- | :------------------------- | :-------------------------------------------------------------------------- | +| `CloudModel.ANTHROPIC_CLAUDE` | `claude-3-7-sonnet-latest` | [Anthropic Models](https://docs.anthropic.com/en/docs/about-claude/models) | +| `CloudModel.OPENAI_GPT` | `gpt-4o-mini` | [OpenAI Models](https://platform.openai.com/docs/models) | +| `CloudModel.GOOGLE_GEMINI` | `gemini-2.5-flash` | [Google Gemini Models](https://ai.google.dev/gemini-api/docs/models/gemini) | + +## Methods + +- **`chat(message)`**: Sends a message and returns the complete response string. Blocks until generation is finished. +- **`chat_stream(message)`**: Returns a generator yielding response tokens as they arrive. +- **`stop_stream()`**: Interrupts an active streaming generation. +- **`with_memory(max_messages)`**: Enables history tracking. `max_messages` defines the context window size. +- **`clear_memory()`**: Resets the conversation history. \ No newline at end of file diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md similarity index 97% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md index 704a9e62..53a837d0 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/docs/arduino/dbstorage_sqlstore/README.md +++ b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/dbstorage_sqlstore/README.md @@ -35,7 +35,7 @@ db = SQLStore("example.db") # ... Do work # Close database -db.close() +db.stop() ``` To create a new table: @@ -65,4 +65,4 @@ db.store("users", data) The SQLStore automatically creates a directory structure for database storage, placing files in `data/dbstorage_sqlstore/` within your application directory. The brick supports automatic type inference when creating tables, mapping Python types (*int*, *float*, *str*, *bytes*) to corresponding SQLite column types (*INTEGER*, *REAL*, *TEXT*, *BLOB*). -The `store()` method can automatically create tables if they don't exist by analyzing the data types of the provided values. This makes it easy to get started without defining schemas upfront, while still allowing explicit table creation for more control over column definitions and constraints. \ No newline at end of file +The `store()` method can automatically create tables if they don't exist by analyzing the data types of the provided values. This makes it easy to get started without defining schemas upfront, while still allowing explicit table creation for more control over column definitions and constraints. diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/dbstorage_tsstore/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/dbstorage_tsstore/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/dbstorage_tsstore/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/dbstorage_tsstore/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/image_classification/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/image_classification/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/image_classification/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/image_classification/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/keyword_spotting/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/keyword_spotting/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/keyword_spotting/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/keyword_spotting/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/mood_detector/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/mood_detector/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/mood_detector/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/mood_detector/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/motion_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/motion_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/motion_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/motion_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/object_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/object_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/object_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/object_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/streamlit_ui/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/streamlit_ui/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/streamlit_ui/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/streamlit_ui/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/vibration_anomaly_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/vibration_anomaly_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/vibration_anomaly_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/vibration_anomaly_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/video_image_classification/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/video_image_classification/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/video_image_classification/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/video_image_classification/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/video_object_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/video_object_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/video_object_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/video_object_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/visual_anomaly_detection/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/visual_anomaly_detection/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/visual_anomaly_detection/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/visual_anomaly_detection/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/wave_generator/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/wave_generator/README.md new file mode 100644 index 00000000..23a1f9f8 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/wave_generator/README.md @@ -0,0 +1,119 @@ +# Wave Generator brick + +This brick provides continuous wave generation for real-time audio synthesis with multiple waveform types and smooth transitions. + +## Overview + +The Wave Generator brick allows you to: + +- Generate continuous audio waveforms in real-time +- Select between different waveform types (sine, square, sawtooth, triangle) +- Control frequency and amplitude dynamically during playback +- Configure smooth transitions with attack, release, and glide (portamento) parameters +- Stream audio to USB speakers with minimal latency + +It runs continuously in a background thread, producing audio blocks at a steady rate with configurable envelope parameters for professional-sounding synthesis. + +## Features + +- Four waveform types: sine, square, sawtooth, and triangle +- Real-time frequency and amplitude control with smooth transitions +- Configurable envelope parameters (attack, release, glide) +- Hardware volume control support +- Thread-safe operation for concurrent access +- Efficient audio generation using NumPy vectorization +- Custom speaker configuration support + +## Prerequisites + +Before using the Wave Generator brick, ensure you have the following: + +- USB-C® Hub with external power supply (5V, 3A) +- USB audio device (USB speaker or USB-C → 3.5mm adapter) +- Arduino UNO Q running in Network Mode or SBC Mode (USB-C port needed for the hub) + +## Code example and usage + +Here is a basic example for generating a 440 Hz sine wave tone: + +```python +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator() + +App.start_brick(wave_gen) + +# Set frequency to A4 note (440 Hz) +wave_gen.set_frequency(440.0) + +# Set amplitude to 80% +wave_gen.set_amplitude(0.8) + +App.run() +``` + +You can customize the waveform type and envelope parameters: + +```python +wave_gen = WaveGenerator( + wave_type="square", + attack=0.01, + release=0.03, + glide=0.02 +) + +App.start_brick(wave_gen) + +# Change waveform during playback +wave_gen.set_wave_type("triangle") + +# Adjust envelope parameters +wave_gen.set_envelope_params(attack=0.05, release=0.1, glide=0.05) + +App.run() +``` + +For specific hardware configurations, you can provide a custom Speaker instance: + +```python +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_peripherals.speaker import Speaker +from arduino.app_utils import App + +# Create Speaker with optimal real-time configuration +speaker = Speaker( + device=Speaker.USB_SPEAKER_2, + sample_rate=16000, + channels=1, + format="FLOAT_LE", + periodsize=480, # 16000 Hz × 0.03s = 480 frames (eliminates buffer mismatch) + queue_maxsize=10 # Low latency configuration +) + +# Start external Speaker manually (WaveGenerator won't manage its lifecycle) +speaker.start() + +wave_gen = WaveGenerator(sample_rate=16000, speaker=speaker) + +App.start_brick(wave_gen) +wave_gen.set_frequency(440.0) +wave_gen.set_amplitude(0.7) + +App.run() + +# Stop external Speaker manually +speaker.stop() +``` + +**Note:** When providing an external Speaker, you manage its lifecycle (start/stop). WaveGenerator only validates configuration and uses it for playback. + +## Understanding Wave Generation + +The Wave Generator brick produces audio through continuous waveform synthesis. + +The `frequency` parameter controls the pitch of the output sound, measured in Hertz (Hz), where typical audible frequencies range from 20 Hz to 8000 Hz. + +The `amplitude` parameter controls the volume as a value between 0.0 (silent) and 1.0 (maximum), with smooth transitions handled by the attack and release envelope parameters. + +The `glide` parameter (also known as portamento) smoothly transitions between frequencies over time, creating sliding pitch effects similar to a theremin or synthesizer. Setting glide to 0 disables this effect but may cause audible clicks during fast frequency changes. diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/weather_forecast/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/weather_forecast/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/weather_forecast/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/weather_forecast/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/web_ui/README.md b/internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/web_ui/README.md similarity index 100% rename from internal/e2e/daemon/testdata/assets/0.5.0/docs/arduino/web_ui/README.md rename to internal/e2e/daemon/testdata/assets/0.6.1/docs/arduino/web_ui/README.md diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py similarity index 90% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py index 58cd9470..3a9df8ca 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/arduino_cloud/1_led_blink.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/1_led_blink.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py similarity index 88% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py index 40371db7..1fce305b 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/2_light_with_colors_monitor.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py similarity index 92% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py index 5e730ea9..4b8c5bf9 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/arduino_cloud/3_light_with_colors_command.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/arduino_cloud/3_light_with_colors_command.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py similarity index 84% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py index 36b2be12..1eed6c3a 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/1_glass_breaking_from_mic.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/1_glass_breaking_from_mic.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py similarity index 60% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py index 68bdd710..237aaba1 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/audio_classification/2_glass_breaking_from_file.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/audio_classification/2_glass_breaking_from_file.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 @@ -6,7 +6,5 @@ # EXAMPLE_REQUIRES = "Requires an audio file with the glass breaking sound." from arduino.app_bricks.audio_classification import AudioClassification -classifier = AudioClassification() - -classification = classifier.classify_from_file("glass_breaking.wav") +classification = AudioClassification.classify_from_file("glass_breaking.wav") print("Result:", classification) diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py similarity index 89% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py index 6dfdb41a..1facd326 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/1_detection.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/1_detection.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py similarity index 90% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py index 6288d571..7d63bb46 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/2_detection_list.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/2_detection_list.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py similarity index 91% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py index 8a672470..d128cd96 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/camera_code_detection/3_detection_with_overrides.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/camera_code_detection/3_detection_with_overrides.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py new file mode 100644 index 00000000..7c325de8 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/1_simple_prompt.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Chat with an LLM" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + print(llm.chat(prompt)) + print() + + +App.run(ask_prompt) diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py new file mode 100644 index 00000000..9538cbda --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/2_streaming_responses.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Streaming responses from an LLM" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + for token in llm.chat_stream(prompt): + print(token, end="", flush=True) + print() + + +App.run(ask_prompt) diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py new file mode 100644 index 00000000..f30419bf --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/cloud_llm/3_no_memory.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +# EXAMPLE_NAME = "Conversation with memory" +# EXAMPLE_REQUIRES = "Requires a valid API key to a cloud LLM service." + +from arduino.app_bricks.cloud_llm import CloudLLM +from arduino.app_utils import App + +llm = CloudLLM( + api_key="YOUR_API_KEY", # Replace with your actual API key +) +llm.with_memory(0) + + +def ask_prompt(): + prompt = input("Enter your prompt (or type 'exit' to quit): ") + if prompt.lower() == "exit": + raise StopIteration() + print(llm.chat(prompt)) + + +App.run(ask_prompt) diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py similarity index 85% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py index e3e31edb..54d070cd 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_sqlstore/store_and_read_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_sqlstore/store_and_read_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py similarity index 84% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py index 9b4185d6..42c19b90 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/1_write_read.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/1_write_read.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py similarity index 93% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py index 2adee9d9..21ee99a2 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/dbstorage_tsstore/2_read_all_samples.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/dbstorage_tsstore/2_read_all_samples.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py similarity index 90% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py index 7dd28c57..7597172e 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/image_classification/image_classification_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/image_classification/image_classification_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py similarity index 82% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py index b5687f86..346cf45d 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/keyword_spotting/1_hello_world.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/keyword_spotting/1_hello_world.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py similarity index 91% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py index f2ca3b9f..166f5b7c 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/object_detection/object_detection_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/object_detection/object_detection_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py similarity index 91% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py index 5dc0d2cc..42a8864e 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/visual_anomaly_detection/object_detection_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/visual_anomaly_detection/object_detection_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py new file mode 100644 index 00000000..5acd492f --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/01_basic_tone.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Basic Wave Generator Example + +Generates a simple 440Hz sine wave (A4 note) and demonstrates +basic frequency and amplitude control. +""" + +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +# Create wave generator with default settings +wave_gen = WaveGenerator( + sample_rate=16000, + wave_type="sine", + glide=0.02, # 20ms smooth frequency transitions +) + +# Start the generator +App.start_brick(wave_gen) + +# Set initial frequency and amplitude +wave_gen.set_frequency(440.0) # A4 note (440 Hz) +wave_gen.set_amplitude(0.7) # 70% amplitude +wave_gen.set_volume(80) # 80% hardware volume + +print("Playing 440Hz sine wave (A4 note)") +print("Press Ctrl+C to stop") + +# Keep the application running +App.run() diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py new file mode 100644 index 00000000..320757c3 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/02_waveform_types.py @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Waveform Comparison Example + +Cycles through different waveform types to hear the difference +between sine, square, sawtooth, and triangle waves. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator(sample_rate=16000, glide=0.02) +App.start_brick(wave_gen) + +# Set constant frequency and amplitude +wave_gen.set_frequency(440.0) +wave_gen.set_amplitude(0.6) + +waveforms = ["sine", "square", "sawtooth", "triangle"] + + +def cycle_waveforms(): + """Cycle through different waveform types.""" + for wave_type in waveforms: + print(f"Playing {wave_type} wave...") + wave_gen.set_wave_type(wave_type) + time.sleep(3) + # Silence + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Cycling through waveforms:") +print("sine → square → sawtooth → triangle") +print("Press Ctrl+C to stop") + +App.run(user_loop=cycle_waveforms) diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py new file mode 100644 index 00000000..614d9962 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/03_frequency_sweep.py @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Frequency Sweep Example + +Demonstrates smooth frequency transitions (glide/portamento effect) +by sweeping through different frequency ranges. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator( + wave_type="sine", + glide=0.05, # 50ms glide for noticeable portamento +) + +App.start_brick(wave_gen) +wave_gen.set_amplitude(0.7) + + +def frequency_sweep(): + """Sweep through frequency ranges.""" + + # Low to high sweep + print("Sweeping low to high (220Hz → 880Hz)...") + for freq in range(220, 881, 20): + wave_gen.set_frequency(float(freq)) + time.sleep(0.1) + + time.sleep(0.5) + + # High to low sweep + print("Sweeping high to low (880Hz → 220Hz)...") + for freq in range(880, 219, -20): + wave_gen.set_frequency(float(freq)) + time.sleep(0.1) + # Fade out + print("Fading out...") + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Frequency sweep demonstration") +print("Listen for smooth glide between frequencies") +print("Press Ctrl+C to stop") + +App.run(user_loop=frequency_sweep) diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py new file mode 100644 index 00000000..395099fb --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/04_envelope_control.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Envelope Control Example + +Demonstrates amplitude envelope control with different +attack and release times for various sonic effects. +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_utils import App + +wave_gen = WaveGenerator(wave_type="sine") +App.start_brick(wave_gen) + +wave_gen.set_frequency(440.0) +wave_gen.set_volume(80) + + +def envelope_demo(): + """Demonstrate different envelope settings.""" + + # Fast attack, fast release (percussive) + print("1. Percussive (fast attack/release)...") + wave_gen.set_envelope_params(attack=0.001, release=0.01, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.5) + wave_gen.set_amplitude(0.0) + time.sleep(1) + + # Slow attack, fast release (pad-like) + print("2. Pad-like (slow attack, fast release)...") + wave_gen.set_envelope_params(attack=0.2, release=0.05, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(1) + wave_gen.set_amplitude(0.0) + time.sleep(1) + + # Fast attack, slow release (sustained) + print("3. Sustained (fast attack, slow release)...") + wave_gen.set_envelope_params(attack=0.01, release=0.3, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.5) + wave_gen.set_amplitude(0.0) + time.sleep(1.5) + + # Medium attack and release (balanced) + print("4. Balanced (medium attack/release)...") + wave_gen.set_envelope_params(attack=0.05, release=0.05, glide=0.0) + wave_gen.set_amplitude(0.8) + time.sleep(0.8) + wave_gen.set_amplitude(0.0) + time.sleep(2) + + +print("Envelope Control Demonstration") +print("Listen to different attack/release characteristics") +print("Press Ctrl+C to stop") + +App.run(user_loop=envelope_demo) diff --git a/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py new file mode 100644 index 00000000..715e9cc3 --- /dev/null +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/wave_generator/05_external_speaker.py @@ -0,0 +1,77 @@ +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) +# +# SPDX-License-Identifier: MPL-2.0 + +""" +Custom Speaker Configuration Example + +Demonstrates how to use a pre-configured Speaker instance with WaveGenerator. +Use this approach when you need: +- Specific USB speaker selection (USB_SPEAKER_2, etc.) +- Different audio format (S16_LE, etc.) +- Explicit device name ("plughw:CARD=Device,DEV=0") +""" + +import time +from arduino.app_bricks.wave_generator import WaveGenerator +from arduino.app_peripherals.speaker import Speaker +from arduino.app_utils import App + +# List available USB speakers +available_speakers = Speaker.list_usb_devices() +print(f"Available USB speakers: {available_speakers}") + +# Create and configure a Speaker with specific parameters +# For optimal real-time synthesis, align periodsize with WaveGenerator block_duration +block_duration = 0.03 # Default WaveGenerator block duration +sample_rate = 16000 +periodsize = int(sample_rate * block_duration) # 480 frames @ 16kHz + +speaker = Speaker( + device=Speaker.USB_SPEAKER_1, # or explicit device like "plughw:CARD=Device" + sample_rate=sample_rate, + channels=1, + format="FLOAT_LE", + periodsize=periodsize, # Align with WaveGenerator blocks (eliminates glitches) + queue_maxsize=10, # Low latency for real-time audio +) + +# Start the external Speaker manually +# WaveGenerator won't manage its lifecycle (ownership pattern) +speaker.start() + +# Create WaveGenerator with the external speaker +wave_gen = WaveGenerator( + sample_rate=sample_rate, + speaker=speaker, # Pass pre-configured speaker + wave_type="sine", + glide=0.02, +) + +# Start the WaveGenerator (speaker already started above) +App.start_brick(wave_gen) + + +def play_sequence(): + """Play a simple frequency sequence.""" + frequencies = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25] # C4 to C5 + + for freq in frequencies: + print(f"Playing {freq:.2f} Hz") + wave_gen.set_frequency(freq) + wave_gen.set_amplitude(0.7) + time.sleep(0.5) + + # Fade out + wave_gen.set_amplitude(0.0) + time.sleep(1) + + +print("Playing musical scale with external speaker...") +print("Press Ctrl+C to stop") + +App.run(user_loop=play_sequence) + +# Stop external Speaker manually (WaveGenerator doesn't manage external lifecycle) +speaker.stop() +print("Done") diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py similarity index 81% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py index 44241a76..cb9a1081 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_city_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_city_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py similarity index 81% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py index 740740a3..11b8ca9d 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/weather_forecast/weather_forecast_by_coords_example.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py similarity index 80% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py index 55fb6ca7..4d8768aa 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/1_serve_webapp.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/1_serve_webapp.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py similarity index 79% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py index ff1c7cc0..19afb676 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/2_serve_webapp_and_api.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/2_serve_webapp_and_api.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py similarity index 81% rename from internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py index 0a98cd99..74906149 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/examples/arduino/web_ui/3_connect_disconnect.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/3_connect_disconnect.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/4_on_message.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/4_on_message.py similarity index 80% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/4_on_message.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/4_on_message.py index cfec4c7c..7eb1316f 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/4_on_message.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/4_on_message.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/5_send_message.py b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/5_send_message.py similarity index 80% rename from debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/5_send_message.py rename to internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/5_send_message.py index 9bb52450..00e19bc7 100644 --- a/debian/arduino-app-cli/home/arduino/.local/share/arduino-app-cli/assets/0.5.0/examples/arduino/web_ui/5_send_message.py +++ b/internal/e2e/daemon/testdata/assets/0.6.1/examples/arduino/web_ui/5_send_message.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (C) 2025 ARDUINO SA +# SPDX-FileCopyrightText: Copyright (C) ARDUINO SRL (http://www.arduino.cc) # # SPDX-License-Identifier: MPL-2.0 diff --git a/internal/e2e/daemon/testdata/assets/0.5.0/models-list.yaml b/internal/e2e/daemon/testdata/assets/0.6.1/models-list.yaml similarity index 94% rename from internal/e2e/daemon/testdata/assets/0.5.0/models-list.yaml rename to internal/e2e/daemon/testdata/assets/0.6.1/models-list.yaml index 7c511011..b4109df2 100644 --- a/internal/e2e/daemon/testdata/assets/0.5.0/models-list.yaml +++ b/internal/e2e/daemon/testdata/assets/0.6.1/models-list.yaml @@ -18,7 +18,7 @@ models: - yolox-object-detection: runner: brick name : "General purpose object detection - YoloX" - description: "General purpose object detection model based on YoloX Nano. This model is trained on the COCO dataset and can detect 80 different object classes." + description: "General purpose object detection model based on YoloX-Nano. This model is trained on the COCO dataset and can detect 80 different object classes." model_configuration: "EI_OBJ_DETECTION_MODEL": "/models/ootb/ei/yolo-x-nano.eim" model_labels: @@ -105,6 +105,7 @@ models: metadata: source: "edgeimpulse" ei-project-id: 717280 + ei-model-url: "https://studio.edgeimpulse.com/public/717280/live" source-model-id: "YOLOX-Nano" source-model-url: "https://github.com/Megvii-BaseDetection/YOLOX" bricks: @@ -1071,6 +1072,7 @@ models: metadata: source: "edgeimpulse" ei-project-id: 708500 + ei-model-url: "https://studio.edgeimpulse.com/public/708500/live" ei-gpu-mode: true source-model-id: "MobileNetV2" source-model-url: "https://www.tensorflow.org/api_docs/python/tf/keras/applications/MobileNetV2" @@ -1089,9 +1091,10 @@ models: metadata: source: "edgeimpulse" ei-project-id: 755016 + ei-model-url: "https://studio.edgeimpulse.com/public/755016/live" ei-gpu-mode: true source-model-id: "person-classification-wakevision" - source-model-url: "https://studio.edgeimpulse.com/studio/755016" + source-model-url: "https://studio.edgeimpulse.com/public/755016/live" bricks: - arduino:image_classification - arduino:video_image_classification @@ -1103,15 +1106,16 @@ models: "EI_V_ANOMALY_DETECTION_MODEL": "/models/ootb/ei/concrete-crack-anomaly-detection.eim" metadata: source: "edgeimpulse" - ei-project-id: 288658 + ei-project-id: 800941 + ei-model-url: "https://studio.edgeimpulse.com/public/800941/live" source-model-id: "concrete-crack-anomaly-detection" - source-model-url: "https://studio.edgeimpulse.com/public/288658" + source-model-url: "https://studio.edgeimpulse.com/public/800941/live" bricks: - arduino:visual_anomaly_detection - keyword-spotting-hey-arduino: runner: brick name : "Keyword spotting - Hey Arduino!" - description: "A keyword-spotting model to detect the 'Hey Arduino!' in audio recordings" + description: "A keyword-spotting model to detect the 'Hey Arduino!' in audio streams." model_configuration: "EI_KEYWORD_SPOTTING_MODEL": "/models/ootb/ei/keyword-spotting-hey-arduino.eim" model_labels: @@ -1120,12 +1124,14 @@ models: - "other" metadata: source: "edgeimpulse" - ei-project-id: 757509 + ei-project-id: 757509 + ei-model-url: "https://studio.edgeimpulse.com/studio/757509/live" ei-impulse-id: 30 source-model-id: "hey-arduino" - source-model-url: "https://studio.edgeimpulse.com/studio/757509" + source-model-url: "https://studio.edgeimpulse.com/studio/757509/live" + private: true bricks: - - arduino:keyword_spotter + - arduino:keyword_spotting - updown-wave-motion-detection: runner: brick name : "Continuous motion detection" @@ -1140,9 +1146,11 @@ models: metadata: source: "edgeimpulse" ei-project-id: 734960 + ei-model-url: "https://studio.edgeimpulse.com/public/734960/live" source-model-id: "continuous-motion-detection" - source-model-url: "https://studio.edgeimpulse.com/studio/734960" - brick: arduino:motion_detection + source-model-url: "https://studio.edgeimpulse.com/public/734960/live" + bricks: + - arduino:motion_detection - fan-anomaly-detection: runner: brick name : "Fan anomaly detection" @@ -1152,8 +1160,9 @@ models: metadata: source: "edgeimpulse" ei-project-id: 774707 + ei-model-url: "https://studio.edgeimpulse.com/public/774707/live" source-model-id: "fan-anomaly-detection" - source-model-url: "https://studio.edgeimpulse.com/studio/774707" + source-model-url: "https://studio.edgeimpulse.com/public/774707/live" bricks: - arduino:vibration_anomaly_detection - glass-breaking: @@ -1168,7 +1177,9 @@ models: metadata: source: "edgeimpulse" ei-project-id: 749446 + ei-model-url: "https://studio.edgeimpulse.com/public/749446/live" source-model-id: "glass-breaking" - source-model-url: "https://studio.edgeimpulse.com/studio/749446" + source-model-url: "https://studio.edgeimpulse.com/public/749446/live" + private: true bricks: - - arduino:audio_classifier + - arduino:audio_classification diff --git a/internal/orchestrator/app/app.go b/internal/orchestrator/app/app.go index 813ca64c..dff16ed3 100644 --- a/internal/orchestrator/app/app.go +++ b/internal/orchestrator/app/app.go @@ -30,7 +30,7 @@ import ( type ArduinoApp struct { Name string MainPythonFile *paths.Path - MainSketchPath *paths.Path + mainSketchPath *paths.Path FullPath *paths.Path // FullPath is the path to the App folder Descriptor AppDescriptor } @@ -76,10 +76,10 @@ func Load(appPath *paths.Path) (ArduinoApp, error) { if appPath.Join("sketch", "sketch.ino").Exist() { // TODO: check sketch casing? - app.MainSketchPath = appPath.Join("sketch") + app.mainSketchPath = appPath.Join("sketch") } - if app.MainPythonFile == nil && app.MainSketchPath == nil { + if app.MainPythonFile == nil && app.mainSketchPath == nil { return ArduinoApp{}, errors.New("main python file and sketch file missing from app") } @@ -91,6 +91,13 @@ func Load(appPath *paths.Path) (ArduinoApp, error) { return app, nil } +func (a *ArduinoApp) GetSketchPath() (*paths.Path, bool) { + if a == nil || a.mainSketchPath == nil { + return nil, false + } + return a.mainSketchPath, true +} + // GetDescriptorPath returns the path to the app descriptor file (app.yaml or app.yml) func (a *ArduinoApp) GetDescriptorPath() *paths.Path { descriptorFile := a.FullPath.Join("app.yaml") diff --git a/internal/orchestrator/app/app_test.go b/internal/orchestrator/app/app_test.go index db9cc048..d8b36eef 100644 --- a/internal/orchestrator/app/app_test.go +++ b/internal/orchestrator/app/app_test.go @@ -58,9 +58,22 @@ func TestLoad(t *testing.T) { assert.NotNil(t, app.MainPythonFile) assert.Equal(t, f.Must(filepath.Abs("testdata/AppSimple/python/main.py")), app.MainPythonFile.String()) + sketchPath, ok := app.GetSketchPath() + assert.True(t, ok) + assert.NotNil(t, sketchPath) + assert.Equal(t, f.Must(filepath.Abs("testdata/AppSimple/sketch")), sketchPath.String()) + }) + + t.Run("it loads an app with misssing sketch folder", func(t *testing.T) { + app, err := Load(paths.New("testdata/MissingSketch")) + assert.NoError(t, err) + assert.NotEmpty(t, app) + + assert.NotNil(t, app.MainPythonFile) - assert.NotNil(t, app.MainSketchPath) - assert.Equal(t, f.Must(filepath.Abs("testdata/AppSimple/sketch")), app.MainSketchPath.String()) + sketchPath, ok := app.GetSketchPath() + assert.False(t, ok) + assert.Nil(t, sketchPath) }) } diff --git a/internal/orchestrator/app/generator/app_generator.go b/internal/orchestrator/app/generator/app_generator.go index 0eec26ae..e77a48f7 100644 --- a/internal/orchestrator/app/generator/app_generator.go +++ b/internal/orchestrator/app/generator/app_generator.go @@ -33,35 +33,22 @@ import ( const templateRoot = "app_template" -type Opts int - -const ( - None Opts = 0 - SkipSketch Opts = 1 << iota - SkipPython -) - //go:embed all:app_template var fsApp embed.FS -func GenerateApp(basePath *paths.Path, app app.AppDescriptor, options Opts) error { +func GenerateApp(basePath *paths.Path, app app.AppDescriptor, skipSketch bool) error { if err := basePath.MkdirAll(); err != nil { return fmt.Errorf("failed to create app directory: %w", err) } - isSkipSketchSet := options&SkipSketch != 0 - isSkipPythonSet := options&SkipPython != 0 - - if !isSkipSketchSet { + if !skipSketch { if err := generateSketch(basePath); err != nil { return fmt.Errorf("failed to create sketch: %w", err) } } - if !isSkipPythonSet { - if err := generatePython(basePath); err != nil { - return fmt.Errorf("failed to create python: %w", err) - } - } + if err := generatePython(basePath); err != nil { + return fmt.Errorf("failed to create python: %w", err) + } if err := generateApp(basePath, app); err != nil { return fmt.Errorf("failed to create app.yaml: %w", err) } diff --git a/internal/orchestrator/app/generator/app_generator_test.go b/internal/orchestrator/app/generator/app_generator_test.go index 5763d386..729ce950 100644 --- a/internal/orchestrator/app/generator/app_generator_test.go +++ b/internal/orchestrator/app/generator/app_generator_test.go @@ -40,31 +40,25 @@ func TestGenerateApp(t *testing.T) { testCases := []struct { name string - options Opts + skipSketch bool goldenPath string }{ { name: "generate complete app", - options: None, goldenPath: "testdata/app-all.golden", }, { name: "skip sketch", - options: SkipSketch, + skipSketch: true, goldenPath: "testdata/app-no-sketch.golden", }, - { - name: "skip python", - options: SkipPython, - goldenPath: "testdata/app-no-python.golden", - }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { tempDir := t.TempDir() - err := GenerateApp(paths.New(tempDir), baseApp, tc.options) + err := GenerateApp(paths.New(tempDir), baseApp, tc.skipSketch) require.NoError(t, err) if os.Getenv("UPDATE_GOLDEN") == "true" { diff --git a/internal/orchestrator/app/generator/testdata/app-no-python.golden/.gitignore b/internal/orchestrator/app/generator/testdata/app-no-python.golden/.gitignore deleted file mode 100644 index 90ae0403..00000000 --- a/internal/orchestrator/app/generator/testdata/app-no-python.golden/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# ignore app cache folder -.cache/ diff --git a/internal/orchestrator/app/generator/testdata/app-no-python.golden/README.md b/internal/orchestrator/app/generator/testdata/app-no-python.golden/README.md deleted file mode 100644 index d1bf5cce..00000000 --- a/internal/orchestrator/app/generator/testdata/app-no-python.golden/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# 🚀 test app all - -### Description - -test description. - -Available application ports: 8080, 9000, 90 diff --git a/internal/orchestrator/app/generator/testdata/app-no-python.golden/app.yaml b/internal/orchestrator/app/generator/testdata/app-no-python.golden/app.yaml deleted file mode 100644 index 7d1f9868..00000000 --- a/internal/orchestrator/app/generator/testdata/app-no-python.golden/app.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# app.yaml: The main configuration file for your Arduino App. -# This file describes the application's metadata and properties. - -# The user-visible name of the application. -name: test app all - -# A brief description of what the application does. -description: "test description." - -# The icon for the application, can be an emoji or a short string. -icon: 🚀 - -# A list of network ports that the application exposes. -# Example: [80, 443] -ports: [8080, 9000, 90] - -# A list of bricks used by this application. -bricks: [] diff --git a/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.ino b/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.ino deleted file mode 100644 index 95c2b6eb..00000000 --- a/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.ino +++ /dev/null @@ -1,9 +0,0 @@ -void setup() { - // put your setup code here, to run once: - -} - -void loop() { - // put your main code here, to run repeatedly: - -} diff --git a/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.yaml b/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.yaml deleted file mode 100644 index d9fe917e..00000000 --- a/internal/orchestrator/app/generator/testdata/app-no-python.golden/sketch/sketch.yaml +++ /dev/null @@ -1,11 +0,0 @@ -profiles: - default: - fqbn: arduino:zephyr:unoq - platforms: - - platform: arduino:zephyr - libraries: - - MsgPack (0.4.2) - - DebugLog (0.8.4) - - ArxContainer (0.7.0) - - ArxTypeTraits (0.3.1) -default_profile: default diff --git a/internal/orchestrator/app/testdata/MissingSketch/app.yaml b/internal/orchestrator/app/testdata/MissingSketch/app.yaml new file mode 100644 index 00000000..adabfa89 --- /dev/null +++ b/internal/orchestrator/app/testdata/MissingSketch/app.yaml @@ -0,0 +1,2 @@ +name: "An app with only python" +description: "An app with only python" diff --git a/internal/orchestrator/app/testdata/MissingSketch/python/main.py b/internal/orchestrator/app/testdata/MissingSketch/python/main.py new file mode 100644 index 00000000..f353b145 --- /dev/null +++ b/internal/orchestrator/app/testdata/MissingSketch/python/main.py @@ -0,0 +1,2 @@ + +print("Hello world!") \ No newline at end of file diff --git a/internal/orchestrator/bricks/bricks.go b/internal/orchestrator/bricks/bricks.go index 85e6e601..b9e0da7d 100644 --- a/internal/orchestrator/bricks/bricks.go +++ b/internal/orchestrator/bricks/bricks.go @@ -78,7 +78,7 @@ func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesRes return AppBrickInstancesResult{}, fmt.Errorf("brick not found with id %s", brickInstance.ID) } - variablesMap, configVariables := getBrickConfigDetails(brick, brickInstance.Variables) + variablesMap, configVariables := getInstanceBrickConfigVariableDetails(brick, brickInstance.Variables) res.BrickInstances[i] = BrickInstanceListItem{ ID: brick.ID, @@ -107,7 +107,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br return BrickInstance{}, fmt.Errorf("brick %s not added in the app", brickID) } - variables, configVariables := getBrickConfigDetails(brick, a.Descriptor.Bricks[brickIndex].Variables) + variables, configVariables := getInstanceBrickConfigVariableDetails(brick, a.Descriptor.Bricks[brickIndex].Variables) modelID := a.Descriptor.Bricks[brickIndex].Model if modelID == "" { @@ -134,7 +134,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br }, nil } -func getBrickConfigDetails( +func getInstanceBrickConfigVariableDetails( brick *bricksindex.Brick, userVariables map[string]string, ) (map[string]string, []BrickConfigVariable) { variablesMap := make(map[string]string, len(brick.Variables)) @@ -167,15 +167,6 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider, return BrickDetailsResult{}, ErrBrickNotFound } - variables := make(map[string]BrickVariable, len(brick.Variables)) - for _, v := range brick.Variables { - variables[v.Name] = BrickVariable{ - DefaultValue: v.DefaultValue, - Description: v.Description, - Required: v.IsRequired(), - } - } - readme, err := s.staticStore.GetBrickReadmeFromID(brick.ID) if err != nil { return BrickDetailsResult{}, fmt.Errorf("cannot open docs for brick %s: %w", id, err) @@ -200,6 +191,9 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider, if err != nil { return BrickDetailsResult{}, fmt.Errorf("unable to get used by apps: %w", err) } + + variables, configVariables := getBrickConfigVariableDetails(brick) + return BrickDetailsResult{ ID: id, Name: brick.Name, @@ -220,9 +214,33 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider, Description: m.ModuleDescription, } }), + ConfigVariables: configVariables, }, nil } +func getBrickConfigVariableDetails( + brick *bricksindex.Brick) (map[string]BrickVariable, []BrickConfigVariable) { + variablesMap := make(map[string]BrickVariable, len(brick.Variables)) + variableDetails := make([]BrickConfigVariable, 0, len(brick.Variables)) + + for _, v := range brick.Variables { + variablesMap[v.Name] = BrickVariable{ + DefaultValue: v.DefaultValue, + Description: v.Description, + Required: v.IsRequired(), + } + + variableDetails = append(variableDetails, BrickConfigVariable{ + Name: v.Name, + Value: v.DefaultValue, + Description: v.Description, + Required: v.IsRequired(), + }) + } + + return variablesMap, variableDetails +} + func getUsedByApps( cfg config.Configuration, brickId string, idProvider *app.IDProvider) ([]AppReference, error) { var ( diff --git a/internal/orchestrator/bricks/bricks_test.go b/internal/orchestrator/bricks/bricks_test.go index 266d41ef..ef51fad6 100644 --- a/internal/orchestrator/bricks/bricks_test.go +++ b/internal/orchestrator/bricks/bricks_test.go @@ -317,7 +317,7 @@ func TestGetBrickInstanceVariableDetails(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - actualVariableMap, actualConfigVariables := getBrickConfigDetails(tt.brick, tt.userVariables) + actualVariableMap, actualConfigVariables := getInstanceBrickConfigVariableDetails(tt.brick, tt.userVariables) require.Equal(t, tt.expectedVariableMap, actualVariableMap) require.Equal(t, tt.expectedConfigVariables, actualConfigVariables) }) @@ -402,6 +402,21 @@ func TestBricksDetails(t *testing.T) { }) t.Run("Success - Full Details - multiple models", func(t *testing.T) { + expectConfigVariables := []BrickConfigVariable{ + { + Name: "EI_OBJ_DETECTION_MODEL", + Value: "default_path", + Description: "path to the model file", + Required: false, + }, + { + Name: "CUSTOM_MODEL_PATH", + Value: "/home/arduino/.arduino-bricks/ei-models", + Description: "path to the custom model directory", + Required: false, + }, + } + res, err := svc.BricksDetails("arduino:object_detection", idProvider, cfg) require.NoError(t, err) @@ -425,6 +440,8 @@ func TestBricksDetails(t *testing.T) { require.Equal(t, "face-detection", res.CompatibleModels[1].ID) require.Equal(t, "Lightweight-Face-Detection", res.CompatibleModels[1].Name) require.Equal(t, "", res.CompatibleModels[1].Description) + require.Len(t, res.ConfigVariables, 2) + require.Equal(t, expectConfigVariables, res.ConfigVariables) }) t.Run("Success - Full Details - no models", func(t *testing.T) { @@ -444,6 +461,7 @@ func TestBricksDetails(t *testing.T) { require.Equal(t, "My App", res.UsedByApps[0].Name) require.NotEmpty(t, res.UsedByApps[0].ID) require.Len(t, res.CompatibleModels, 0) + require.Empty(t, res.ConfigVariables) }) t.Run("Success - Full Details - one model", func(t *testing.T) { @@ -456,6 +474,8 @@ func TestBricksDetails(t *testing.T) { require.Equal(t, "face-detection", res.CompatibleModels[0].ID) require.Equal(t, "Lightweight-Face-Detection", res.CompatibleModels[0].Name) require.Equal(t, "", res.CompatibleModels[0].Description) + require.Empty(t, res.ConfigVariables) + require.Empty(t, res.Variables) }) } diff --git a/internal/orchestrator/bricks/types.go b/internal/orchestrator/bricks/types.go index bd63bd57..e4b1b747 100644 --- a/internal/orchestrator/bricks/types.go +++ b/internal/orchestrator/bricks/types.go @@ -91,10 +91,11 @@ type BrickDetailsResult struct { Category string `json:"category"` Status string `json:"status"` RequireModel bool `json:"require_model"` - Variables map[string]BrickVariable `json:"variables,omitempty"` + Variables map[string]BrickVariable `json:"variables,omitempty" description:"Deprecated: use config_variables instead. This field is kept for backward compatibility."` Readme string `json:"readme"` ApiDocsPath string `json:"api_docs_path"` CodeExamples []CodeExample `json:"code_examples"` UsedByApps []AppReference `json:"used_by_apps"` CompatibleModels []AIModel `json:"compatible_models"` + ConfigVariables []BrickConfigVariable `json:"config_variables"` } diff --git a/internal/orchestrator/config/config.go b/internal/orchestrator/config/config.go index 0838f29d..527732c6 100644 --- a/internal/orchestrator/config/config.go +++ b/internal/orchestrator/config/config.go @@ -28,7 +28,7 @@ import ( ) // runnerVersion do not edit, this is generate with `task generate:assets` -var runnerVersion = "0.5.0" +var runnerVersion = "0.6.1" type Configuration struct { appsDir *paths.Path diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 841e31f1..51a808cd 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -154,7 +154,8 @@ func StartApp( if !yield(StreamMessage{progress: &Progress{Name: "preparing", Progress: 0.0}}) { return } - if appToStart.MainSketchPath != nil { + + if _, ok := appToStart.GetSketchPath(); ok { if !yield(StreamMessage{progress: &Progress{Name: "sketch compiling and uploading", Progress: 0.0}}) { return } @@ -175,7 +176,7 @@ func StartApp( return } provisionStartProgress := float32(0.0) - if appToStart.MainSketchPath != nil { + if _, ok := appToStart.GetSketchPath(); ok { provisionStartProgress = 10.0 } @@ -402,7 +403,7 @@ func stopAppWithCmd(ctx context.Context, docker command.Cli, app app.ArduinoApp, } }) - if app.MainSketchPath != nil { + if _, ok := app.GetSketchPath(); ok { // Before stopping the microcontroller we want to make sure that the app was running. appStatus, err := getAppStatus(ctx, docker, app) if err != nil { @@ -748,7 +749,6 @@ type CreateAppRequest struct { Name string Icon string Description string - SkipPython bool SkipSketch bool } @@ -762,9 +762,6 @@ func CreateApp( idProvider *app.IDProvider, cfg config.Configuration, ) (CreateAppResponse, error) { - if req.SkipPython && req.SkipSketch { - return CreateAppResponse{}, fmt.Errorf("cannot skip both python and sketch") - } if req.Name == "" { return CreateAppResponse{}, fmt.Errorf("app name cannot be empty") } @@ -783,16 +780,8 @@ func CreateApp( if err := newApp.IsValid(); err != nil { return CreateAppResponse{}, fmt.Errorf("%w: %v", app.ErrInvalidApp, err) } - var options appgenerator.Opts = 0 - - if req.SkipSketch { - options |= appgenerator.SkipSketch - } - if req.SkipPython { - options |= appgenerator.SkipPython - } - if err := appgenerator.GenerateApp(basePath, newApp, options); err != nil { + if err := appgenerator.GenerateApp(basePath, newApp, req.SkipSketch); err != nil { return CreateAppResponse{}, fmt.Errorf("failed to create app: %w", err) } id, err := idProvider.IDFromPath(basePath) @@ -1162,9 +1151,12 @@ func compileUploadSketch( defer func() { _, _ = srv.Destroy(ctx, &rpc.DestroyRequest{Instance: inst}) }() - sketchPath := arduinoApp.MainSketchPath.String() + sketchPath, ok := arduinoApp.GetSketchPath() + if !ok { + return fmt.Errorf("no sketch path found in the Arduino app") + } buildPath := arduinoApp.SketchBuildPath().String() - sketchResp, err := srv.LoadSketch(ctx, &rpc.LoadSketchRequest{SketchPath: sketchPath}) + sketchResp, err := srv.LoadSketch(ctx, &rpc.LoadSketchRequest{SketchPath: sketchPath.String()}) if err != nil { return err } @@ -1175,7 +1167,7 @@ func compileUploadSketch( } initReq := &rpc.InitRequest{ Instance: inst, - SketchPath: sketchPath, + SketchPath: sketchPath.String(), Profile: profile, } @@ -1215,7 +1207,7 @@ func compileUploadSketch( compileReq := rpc.CompileRequest{ Instance: inst, Fqbn: "arduino:zephyr:unoq", - SketchPath: sketchPath, + SketchPath: sketchPath.String(), BuildPath: buildPath, Jobs: 2, } @@ -1241,12 +1233,12 @@ func compileUploadSketch( slog.Info("Used library " + lib.GetName() + " (" + lib.GetVersion() + ") in " + lib.GetInstallDir()) } - if err := uploadSketchInRam(ctx, w, srv, inst, sketchPath, buildPath); err != nil { + if err := uploadSketchInRam(ctx, w, srv, inst, sketchPath.String(), buildPath); err != nil { slog.Warn("failed to upload in ram mode, trying to configure the board in ram mode, and retry", slog.String("error", err.Error())) if err := configureMicroInRamMode(ctx, w, srv, inst); err != nil { return err } - return uploadSketchInRam(ctx, w, srv, inst, sketchPath, buildPath) + return uploadSketchInRam(ctx, w, srv, inst, sketchPath.String(), buildPath) } return nil } diff --git a/internal/orchestrator/provision.go b/internal/orchestrator/provision.go index c5ab52b6..babac0ce 100644 --- a/internal/orchestrator/provision.go +++ b/internal/orchestrator/provision.go @@ -236,39 +236,39 @@ func generateMainComposeFile( ports[fmt.Sprintf("%s:%s", p, p)] = struct{}{} } + // 2. Collect all the required device classes + if len(idxBrick.RequiredDevices) > 0 { + for _, deviceClass := range idxBrick.RequiredDevices { + requiredDeviceClasses[deviceClass] = true + } + } + // The following code is needed only if the brick requires a container. // In case it doesn't we just skip to the next one. if !idxBrick.RequireContainer { continue } - // 2. Retrieve the brick_compose.yaml file. + // 3. Retrieve the brick_compose.yaml file. composeFilePath, err := staticStore.GetBrickComposeFilePathFromID(brick.ID) if err != nil { slog.Error("brick compose id not valid", slog.String("error", err.Error()), slog.String("brick_id", brick.ID)) continue } - // 3. Retrieve the compose services names. + // 4. Retrieve the compose services names. svcs, err := extractServicesFromComposeFile(composeFilePath) if err != nil { slog.Error("loading brick_compose", slog.String("brick_id", brick.ID), slog.String("path", composeFilePath.String()), slog.Any("error", err)) continue } - // 4. Retrieve the required devices that we have to mount + // 5. Retrieve the required devices that we have to mount slog.Debug("Brick config", slog.Bool("mount_devices_into_container", idxBrick.MountDevicesIntoContainer), slog.Any("ports", ports), slog.Any("required_devices", idxBrick.RequiredDevices)) if idxBrick.MountDevicesIntoContainer { servicesThatRequireDevices = slices.AppendSeq(servicesThatRequireDevices, maps.Keys(svcs)) } - // 5. Collect all the required device classes - if len(idxBrick.RequiredDevices) > 0 { - for _, deviceClass := range idxBrick.RequiredDevices { - requiredDeviceClasses[deviceClass] = true - } - } - composeFiles.Add(composeFilePath) maps.Insert(services, maps.All(svcs)) } @@ -335,6 +335,16 @@ func generateMainComposeFile( }) } } + if devices.hasSoundDevice { + // If we are adding sound devices, mount also /dev/snd/by-id if it exists to allow access to by-id links + if paths.New("/dev/snd/by-id").Exist() { + volumes = append(volumes, volume{ + Type: "bind", + Source: "/dev/snd/by-id", + Target: "/dev/snd/by-id", + }) + } + } volumes = addLedControl(volumes) diff --git a/internal/orchestrator/sketch_libs.go b/internal/orchestrator/sketch_libs.go index 3ef3b7ff..cb058924 100644 --- a/internal/orchestrator/sketch_libs.go +++ b/internal/orchestrator/sketch_libs.go @@ -17,6 +17,7 @@ package orchestrator import ( "context" + "errors" "log/slog" "time" @@ -30,6 +31,11 @@ import ( const indexUpdateInterval = 10 * time.Minute func AddSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef LibraryReleaseID, addDeps bool) ([]LibraryReleaseID, error) { + sketchPath, ok := app.GetSketchPath() + if !ok { + return []LibraryReleaseID{}, errors.New("cannot add a library. Missing sketch folder") + } + srv := commands.NewArduinoCoreServer() var inst *rpc.Instance if res, err := srv.Create(ctx, &rpc.CreateRequest{}); err != nil { @@ -58,7 +64,7 @@ func AddSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef LibraryRel resp, err := srv.ProfileLibAdd(ctx, &rpc.ProfileLibAddRequest{ Instance: inst, - SketchPath: app.MainSketchPath.String(), + SketchPath: sketchPath.String(), Library: &rpc.SketchProfileLibraryReference{ Library: &rpc.SketchProfileLibraryReference_IndexLibrary_{ IndexLibrary: &rpc.SketchProfileLibraryReference_IndexLibrary{ @@ -77,6 +83,10 @@ func AddSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef LibraryRel } func RemoveSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef LibraryReleaseID) (LibraryReleaseID, error) { + sketchPath, ok := app.GetSketchPath() + if !ok { + return LibraryReleaseID{}, errors.New("cannot remove a library. Missing sketch folder") + } srv := commands.NewArduinoCoreServer() var inst *rpc.Instance if res, err := srv.Create(ctx, &rpc.CreateRequest{}); err != nil { @@ -102,7 +112,7 @@ func RemoveSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef Library }, }, }, - SketchPath: app.MainSketchPath.String(), + SketchPath: sketchPath.String(), }) if err != nil { return LibraryReleaseID{}, err @@ -111,10 +121,15 @@ func RemoveSketchLibrary(ctx context.Context, app app.ArduinoApp, libRef Library } func ListSketchLibraries(ctx context.Context, app app.ArduinoApp) ([]LibraryReleaseID, error) { + sketchPath, ok := app.GetSketchPath() + if !ok { + return []LibraryReleaseID{}, errors.New("cannot list libraries. Missing sketch folder") + } + srv := commands.NewArduinoCoreServer() resp, err := srv.ProfileLibList(ctx, &rpc.ProfileLibListRequest{ - SketchPath: app.MainSketchPath.String(), + SketchPath: sketchPath.String(), }) if err != nil { return nil, err diff --git a/internal/orchestrator/sketch_libs_test.go b/internal/orchestrator/sketch_libs_test.go new file mode 100644 index 00000000..d863e60e --- /dev/null +++ b/internal/orchestrator/sketch_libs_test.go @@ -0,0 +1,88 @@ +// This file is part of arduino-app-cli. +// +// Copyright 2025 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-app-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package orchestrator + +import ( + "context" + "testing" + + "github.com/arduino/go-paths-helper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/arduino/arduino-app-cli/internal/orchestrator/app" +) + +func TestListSketchLibraries(t *testing.T) { + t.Run("fail to list libraries if the sketch folder is missing", func(t *testing.T) { + pythonApp, err := app.Load(createTestAppPythonOnly(t)) + require.NoError(t, err) + + libs, err := ListSketchLibraries(context.Background(), pythonApp) + require.Error(t, err) + assert.Contains(t, err.Error(), "cannot list libraries. Missing sketch folder") + assert.Empty(t, libs) + }) + + t.Run("fail to add library if the sketch folder is missing", func(t *testing.T) { + pythonApp, err := app.Load(createTestAppPythonOnly(t)) + require.NoError(t, err) + + libs, err := AddSketchLibrary(context.Background(), pythonApp, LibraryReleaseID{}, false) + require.Error(t, err) + assert.Contains(t, err.Error(), "cannot add a library. Missing sketch folder") + assert.Empty(t, libs) + }) + + t.Run("fail to remove library if the sketch folder is missing", func(t *testing.T) { + pythonApp, err := app.Load(createTestAppPythonOnly(t)) + require.NoError(t, err) + + id, err := RemoveSketchLibrary(context.Background(), pythonApp, LibraryReleaseID{}) + require.Error(t, err) + assert.Contains(t, err.Error(), "cannot remove a library. Missing sketch folder") + assert.Empty(t, id) + }) +} + +// Helper function to create a test app without sketch path (Python-only) +func createTestAppPythonOnly(t *testing.T) *paths.Path { + tempDir := t.TempDir() + + appYaml := paths.New(tempDir, "app.yaml") + require.NoError(t, appYaml.WriteFile([]byte(` +name: test-python-app +version: 1.0.0 +description: Test Python-only app +`))) + + // Create python directory and file + pythonDir := paths.New(tempDir, "python") + require.NoError(t, pythonDir.MkdirAll()) + + pythonFile := pythonDir.Join("main.py") + require.NoError(t, pythonFile.WriteFile([]byte(` +import time + +def main(): + print("Hello from Python!") + time.sleep(1) + +if __name__ == "__main__": + main() +`))) + return paths.New(tempDir) +}