---
title: Vision inspection
slug: solutions/vision-inspection
docTags: 
createdAt: 2026-08-17T14:37:51.331Z
---

A camera inspection cell on a bottling line: fill level read from the frame, per bottle, with the inspection running on the Edge rather than in a cloud. One device and 15 tags, plus the video itself.

| Operator view      | port **4013**          |
| ------------------ | ---------------------- |
| Protocol server    | port **5023**          |
| Devices and tags   | 1 device, 15 tags      |
| Litmus Edge driver | Modbus TCP             |
| Image              | `food-beverage-vision` |

## Scenarios

- **A fill anomaly caught per bottle.** The measurement is made from the picture, bottle by bottle, and published as a tag like any other reading.
- **Filler drift as a forecast.** The interesting number is not the bottle that failed but the trend that says the filler will start failing shortly.
- **Inference on the Edge.** The frames never leave the plant to be measured. What travels north is a number, and the picture only if you ask for it.

## Overview

This is the one solution that uses two data paths, because the picture and the numbers suit different ones.

- **Inspection readings** go to DeviceHub over **Modbus TCP**, like every other solution here. These are the tags the Edge polls.
- **Frames** go to Litmus Edge **DataHub over NATS**, which is built for payloads of that size and shape.

A dropped frame therefore never costs you a measurement, and the tag history is not full of images.

The NATS path is optional. Leave it unconfigured and the inspection still runs and still publishes its readings.

## What it creates on Litmus Edge

One DeviceHub device with 15 tags covering the fill measurement, the inspection verdict and the line state. A Digital Twin instance for the cell. Analytics groups behind the anomaly and drift figures. Frames land in DataHub when NATS is configured.

## Requirements

- Litmus Edge 4.0.x, reachable over HTTPS from the host running the solution
- An API token for that Edge, or a username and password, or a client id and secret
- Docker, and Docker Compose for the compose deployment
- A network path in both directions: the solution reaches the Edge's API, and the Edge reaches this host on the protocol port

## Deploy

The solution ships two ways. Use the registry if the host can reach Google Artifact Registry, and the downloaded archive if it cannot.

### Option 1: pull from the registry

Requires a read-only registry credential, supplied by Litmus separately.

```bash
cat key.json | docker login -u _json_key --password-stdin https://us-docker.pkg.dev
```

Save this as `docker-compose.yml`:

```yaml
services:
  food-beverage-vision:
    image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/food-beverage-vision:0.5.0
    container_name: food-beverage-vision
    restart: unless-stopped
    ports:
      - target: 4013
        published: 4013
        protocol: tcp
      - target: 5023
        published: 5023
        protocol: tcp
    environment:
      # Fill these in.
      EDGE_URL: "${EDGE_URL:-}"
      EDGE_API_TOKEN: "${EDGE_API_TOKEN:-}"
      SIM_HOST: "${SIM_HOST:-auto}"
      APPLY_ON_START: "${APPLY_ON_START:-1}"
      EDGE_VERIFY_TLS: "${EDGE_VERIFY_TLS:-0}"
      HTTP_PORT: "4013"
      MODBUS_PORT: "5023"
      # Optional: frames to DataHub.
      NATS_URL: "${NATS_URL:-}"
      NATS_TOKEN: "${NATS_TOKEN:-}"
      PUB_GROUP: "${PUB_GROUP:-fbvision}"
      PUB_LAYOUT: "${PUB_LAYOUT:-datahub}"
      LOG_LEVEL: "INFO"
```

```javascript
EDGE_URL=https://10.0.0.5
EDGE_API_TOKEN=your-token
SIM_HOST=10.0.0.9
```

```bash
docker compose up -d
```

Open `http://localhost:4013`.

**The page stays on its waiting panel until the Edge carries this solution's devices.** That is deliberate: the simulation does not tick and no value is shown until Litmus Edge is verified to hold the devices and poll them, so nothing on screen can be mistaken for data that never made the trip. With `APPLY_ON_START` at its default of `1` the solution configures the Edge itself on startup, which takes 30 to 60 seconds. If you set it to `0`, or the apply failed, press **Apply to Edge** in the page header.

This is the largest image of the set, about 219 MB, because it carries the vision libraries. The others are around 50 MB.

### Option 2: load the downloaded archive

Download `food-beverage-vision-0.5.0-amd64.tar.gz` from the solution's page on portal.litmus.io. The archive is the container image, not a source bundle, and needs no registry access.

```bash
docker load -i food-beverage-vision-0.5.0-amd64.tar.gz
```

`docker load` prints the image it added:

```javascript
Loaded image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/food-beverage-vision:0.5.0
```

That reference is the one the compose file above already names, so the same `docker-compose.yml` and `.env` now work offline with no `docker login`:

```bash
docker compose up -d
```

To run it without Compose, pass the same three values on the command line:

```bash
docker run -d \
  --name food-beverage-vision \
  --restart unless-stopped \
  -p 4013:4013 \
  -p 5023:5023 \
  -e EDGE_URL=https://10.0.0.5 \
  -e EDGE_API_TOKEN=your-token \
  -e SIM_HOST=10.0.0.9 \
  us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/food-beverage-vision:0.5.0
```

## Configuration

| Variable          | Default    | What it does                                                        |
| ----------------- | ---------- | ------------------------------------------------------------------- |
| `EDGE_URL`        | unset      | Litmus Edge to configure                                            |
| `EDGE_API_TOKEN`  | unset      | token for that Edge. Or a username and password                     |
| `SIM_HOST`        | `auto`     | address the Edge polls to reach this solution                       |
| `APPLY_ON_START`  | `1`        | configure the Edge on startup                                       |
| `EDGE_VERIFY_TLS` | `0`        | `1` checks the Edge's certificate                                   |
| `NATS_URL`        | unset      | Litmus Edge DataHub, for frames. Optional                           |
| `NATS_TOKEN`      | unset      | a DataHub token. Not the same string as the API token above         |
| `PUB_GROUP`       | `fbvision` | topic group frames are published under                              |
| `PUB_LAYOUT`      | `datahub`  | topic layout. `flat` matches the upstream frame streamer convention |
| `LINE_SPEED`      | `4`        | how fast bottles pass the camera                                    |

When running as an application hosted by Litmus Edge, `NATS_URL` is `10.30.50.1`, which is the Edge as seen from a container it hosts. Running beside the Edge, it is the Edge's own address.

## Operator view

The camera view with the inspection overlay, the measured fill level per bottle, and the verdict. Beside it, the trend that the drift forecast is taken from.

Faults let you drift the filler, introduce a fill anomaly, and degrade the image so you can see what the inspection does with a poor frame.

## Apply and remove

```bash
docker compose down
```

Use Clean up in the [Solutions provisioner](#) to remove what it created on the Edge.

## Support

[support@litmus.io](mailto\:support@litmus.io)
