---
title: Rotating equipment reliability
slug: solutions/rotating-equipment-reliability
docTags: 
createdAt: 2026-08-17T14:42:33.186Z
---

Condition monitoring across a fleet of six machines in the balance of plant: boiler feed pumps, a cooling water pump, an induced draft fan, a cooling tower fan and an instrument air compressor. Six machines and 90 tags published over Sparkplug B.

| Operator view      | port **4015**             |
| ------------------ | ------------------------- |
| MQTT broker        | port **5025**             |
| Devices and tags   | 6 machines, 90 tags       |
| Litmus Edge driver | Sparkplug B over MQTT     |
| Image              | `rotating-equipment-demo` |

## Scenarios

- **The impulse before the trend.** Bearing damage shows up first as impulsiveness in the vibration signal, not as a rise in overall level. By the time the trend moves, the decision has already been made for you.
- **Bearing prognosis on the Edge.** The health figure and the estimate of remaining life are produced on the Edge from the stream, not in a cloud from a daily average.
- **One model, any machine.** A single twin model serves pumps, fans and a compressor alike. Adding the seventh machine is configuration rather than engineering, which is the whole argument for condition monitoring as a horizontal.

## Containers

Sparkplug B is publish and subscribe, so it needs a broker, and a Litmus Edge does not broker MQTT: it subscribes as a host application. Mosquitto therefore ships beside the simulator and the Edge's Sparkplug B client connects to it on 5025.

That has one practical consequence. **This solution cannot be started as a single container**, so it is deployed with the compose file below rather than through a `docker run`, and the [Solutions provisioner](#) will decline to start it from a card and say so.

`mosquitto.conf` must sit beside the compose file. Mosquitto 2 binds loopback only and refuses anonymous clients without it, so a missing config file gives you a broker that comes up and rejects every connection.

## What it creates on Litmus Edge

Six DeviceHub devices, one per machine, with 90 tags arriving over Sparkplug B. One shared Digital Twin model with an instance per machine. Analytics groups behind the fleet health, ISO zone and impulsiveness figures.

## 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:
  mosquitto:
    image: eclipse-mosquitto:2
    container_name: rotating-mosquitto
    restart: unless-stopped
    ports:
      - target: 1883
        published: 5025
        protocol: tcp
    volumes:
      - type: bind
        source: ./mosquitto.conf
        target: /mosquitto/config/mosquitto.conf
        read_only: true
    healthcheck:
      test: ["CMD-SHELL", "nc -z 127.0.0.1 1883"]
      interval: 10s
      timeout: 3s
      retries: 5

  rotating-equipment:
    image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/rotating-equipment-demo:0.5.0
    container_name: rotating-equipment-demo
    restart: unless-stopped
    depends_on:
      mosquitto:
        condition: service_healthy
    ports:
      - target: 4015
        published: 4015
        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: "4015"
      MQTT_HOST: "mosquitto"
      MQTT_PORT: "1883"
      MQTT_PUBLIC_PORT: "5025"
      SPARKPLUG_GROUP: "Plant01"
      SPARKPLUG_NODE: "BalanceOfPlant"
      AUTOSTART: "1"
      TICK_SECONDS: "0.1"
      SEED: "11"
      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:4015`.

**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.

### Option 2: load the downloaded archive

Download `rotating-equipment-demo-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 rotating-equipment-demo-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/rotating-equipment-demo: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
```

This solution is two containers, the simulator and an MQTT broker, so it has no single `docker run` form. Use the compose file above after loading the image; the broker image is public and pulls from Docker Hub.

## Configuration

| Variable           | Default          | What it does                                                               |
| ------------------ | ---------------- | -------------------------------------------------------------------------- |
| `EDGE_URL`         | the Docker host  | Litmus Edge to configure                                                   |
| `EDGE_API_TOKEN`   | unset            | token for that Edge. Or a username and password, or a client id and secret |
| `SIM_HOST`         | `auto`           | address the Edge uses to reach the broker                                  |
| `APPLY_ON_START`   | `1`              | configure the Edge on startup                                              |
| `EDGE_VERIFY_TLS`  | `0`              | `1` checks the Edge's certificate                                          |
| `MQTT_HOST`        | `mosquitto`      | how this container reaches the broker: the service name                    |
| `MQTT_PORT`        | `1883`           | the broker's own internal port                                             |
| `MQTT_PUBLIC_PORT` | `5025`           | how the **Edge** reaches the broker                                        |
| `SPARKPLUG_GROUP`  | `Plant01`        | Sparkplug group id                                                         |
| `SPARKPLUG_NODE`   | `BalanceOfPlant` | Sparkplug edge node id                                                     |

`MQTT_HOST` and `MQTT_PUBLIC_PORT` answer different questions and are easy to conflate. The first is how the simulator reaches the broker, on the container network. The second is how Litmus Edge reaches it, and it is the one that goes into the DeviceHub template. Putting the container name in the template gives you devices that come online and never read a value.

## Operator view

Fleet health across the top, then the six machines with their health scores and ISO zone. Click a machine to inspect its signal: the vibration stream the Edge features, with the RMS and the impulsiveness that moves first.

Every value on the page is read back from Litmus Edge rather than from the simulator, and the page says how many reads it has made and how old the newest is. What you are looking at took the full trip through the device.

Faults include a bearing defect developing, lubrication loss, cavitation on a pump and an imbalance.

## 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)
