CURRENT TREND INSIGHT
How to run local embeddings models on Raspberry Pi for smart home automation Illustration

How to run local embeddings models on Raspberry Pi for smart home automation

Direct Summary:

Most smart-home voice commands are handled by Home Assistant's built-in hassil engine, which matches sentences against fixed templates, not embeddings — "turn off the kitchen lights" resolves in a few hundred milliseconds with no model involved. Local embeddings earn their place for the harder case: fuzzy-matching a spoken phrase that doesn't fit any known template to the closest known device or scene name, using a small sentence-transformers model exported to ONNX so it runs efficiently on the Pi's ARM CPU.

"If you can't explain it simply, you don't understand it well enough."

— Albert Einstein

Key Insights

  • Template matching handles most commands: Home Assistant's local intent system (hassil) is pattern-based, not embedding-based — it's already fast and needs no model for the common "turn on/off X" phrasing.
  • Embeddings are a fallback, not the default: Semantic similarity is most useful for the phrases that fall outside your templates — matching loose wording to a fixed list of device/scene names.
  • ONNX is what makes it practical on ARM: Exporting a sentence-transformers model to ONNX, optionally with the arm64 quantization config, is what keeps embedding generation fast enough on a Pi's CPU rather than a GPU.

It's worth being direct about what actually powers most smart-home voice control before reaching for embeddings at all. Home Assistant's Assist pipeline, when set to prefer local intents, resolves phrases like "turn off the kitchen lights" through hassil, a template-matching engine — not a neural network. Sentences are defined as YAML templates (the Home Assistant Intent Language, or HassIL) and matched directly. It's fast, deterministic, and needs no embedding model for the common case.

Where local embeddings actually help

The gap shows up when a spoken command doesn't fit any defined template — a user says "kill the lights in the kitchen" instead of "turn off," or refers to a device by a nickname that was never added to the template list. Rather than failing outright or falling back to a cloud LLM, a small local embeddings model can compare the unmatched phrase against your known device and scene names, and route to whichever is semantically closest — entirely on-device, with no cloud round-trip and no added command latency the user would notice.

Running it on a Pi 5's CPU

1. Pick a small model. A compact sentence-transformers model like all-MiniLM-L6-v2 is a reasonable starting point — it's small enough to run comfortably on CPU.

2. Install the ONNX backend: pip install sentence-transformers[onnx]. Sentence Transformers can load or auto-convert a model to ONNX format, and ONNX shows measurable CPU speedups over the default PyTorch backend, especially on short text like device names.

3. Quantize for ARM. The export_dynamic_quantized_onnx_model() function supports an arm64 quantization config specifically for ARM CPUs like the Pi 5's Cortex-A76 — dynamic int8 quantization needs no calibration dataset and further cuts inference time.

match_device_name.py
# Fallback fuzzy-match for phrases hassil's templates didn't catch,
# running on ONNX so it's fast enough on a Pi 5's CPU
from sentence_transformers import SentenceTransformer
from sentence_transformers.util import cos_sim

model = SentenceTransformer(
    "sentence-transformers/all-MiniLM-L6-v2",
    backend="onnx"
)

known_devices = ["kitchen lights", "living room lamp", "hallway light"]
device_embeddings = model.encode(known_devices)

# Unmatched phrase from hassil's template engine
query = "kill the lights in the kitchen"
query_embedding = model.encode(query)

scores = cos_sim(query_embedding, device_embeddings)[0]
best_match = known_devices[scores.argmax()]
print(f"Routing to: {best_match} (score: {scores.max():.2f})")
Matching Layer How It Works When It's Used
hassil (built-in) Template/pattern matching against defined sentence structures First — handles the large majority of standard phrasing
Local embeddings (ONNX) Cosine similarity between the phrase and known device/scene names Fallback — only for phrases the templates don't match

The honest framing is that embeddings are a narrow, useful patch for the edges of your voice pipeline — not a replacement for the deterministic matching that already handles most traffic reliably. Reach for a local embedding model when you've actually observed unmatched commands failing, not as a default architecture choice.

Practical Challenge

Install sentence-transformers with the ONNX backend on a Raspberry Pi, encode a list of 5 mock device names, and write a script that finds the closest match for 3 differently-phrased test queries.

Concept Check

Why doesn't Home Assistant use embeddings for most local voice commands?
Correct! hassil's template matching resolves standard commands in well under a second with no model inference needed. Embeddings add value specifically for phrases that fall outside those templates.
Incorrect. Try again! Hint: Home Assistant's local intent engine (hassil) is a deterministic template matcher — embeddings are a useful fallback for unmatched phrasing, not the primary mechanism.

Sources & Further Reading

Previous Guide Dashboard Next Guide