# Koios — Full Documentation > Koios is an AI-Ops IoT platform for industrial environments — real-time data ingress and egress from connected devices alongside on-device AI model inference. This is the product help documentation. --- Source: https://ai-ops.com/docs/getting-started/introduction Section: Getting Started # Getting Started Koios (pronounced "KEE-os") is an edge platform for industrial AI. It connects to your devices, collects data in real time, runs pre-trained machine learning models against that data, and lets you build custom logic, all on-premises, without sending data to the cloud. The name comes from Greek mythology. **Koios** (Κοῖος) was the Titan of intellect and inquiry, associated with the celestial axis around which knowledge of the heavens revolved. It felt like a fitting name for a platform built to make sense of industrial data. This page introduces the main things you can do with Koios and links to the detailed guides for each. --- ## Data Collection: Devices and Tags Getting data into Koios starts with two concepts: **devices** and **tags**. A **device** is a connection to an external data source: a PLC, an OPC-UA server, a Modbus controller, a database, or a REST API. It defines _how_ Koios communicates: the protocol, the hostname, the credentials, and the scan rate (how often to poll for new values). Koios supports [several industrial protocols](https://ai-ops.com/docs/protocols/introduction.md) including OPC-UA, Modbus TCP, EtherNet/IP, SOAP, REST, and Microsoft SQL. A **tag** is a single data point _within_ a device: one temperature sensor, one pressure register, one database column. Tags define _what_ to read (or write). Each device can have hundreds or thousands of tags, and each tag produces a live value that updates on every scan cycle. The key difference: **devices handle the connection, tags handle the data**. You create a device to establish communication with a piece of equipment, then add tags to specify which data points you care about. > [!TIP] Not all tags need a device > Koios also supports **expression tags** that compute values from formulas referencing other tags, and **in-memory tags** that historize values produced by AI models and components. These don't require a device connection. See [Tag Source Types](https://ai-ops.com/docs/tags/introduction.md#tag-source-types) for details. For a data source with a backup, you can group redundant devices into a [device set](https://ai-ops.com/docs/devices/device-sets.md) so collection fails over automatically if the active device goes down. **Learn more:** [Device Introduction](https://ai-ops.com/docs/devices/introduction.md) | [Tag Introduction](https://ai-ops.com/docs/tags/introduction.md) | [Creating a Device](https://ai-ops.com/docs/devices/creating-getting-started.md) | [Creating a Tag](https://ai-ops.com/docs/tags/creating-getting-started.md) | [Device Sets](https://ai-ops.com/docs/devices/device-sets.md) --- ## Historization Once tags are collecting data, Koios automatically records every value to its time-series database. This historization is what makes trends, AI inference, and long-term analysis possible. You get a continuous record of every data point at whatever scan rate you configure. Koios uses **Swinging Door Trending (SDT)** compression by default to keep storage manageable. Values that don't meaningfully change the trend are discarded, while significant changes are always preserved. You can tune compression globally or override it per tag, and configure [retention policies](https://ai-ops.com/docs/system/retention.md) to manage how long data is kept. You can export historical data as CSV, JSON, or Parquet from the [Trends](https://ai-ops.com/docs/trends/introduction.md) page, useful for analysis, reporting, or collecting training datasets for your AI models. **Learn more:** [Data Retention](https://ai-ops.com/docs/system/retention.md) | [Exporting Data](https://ai-ops.com/docs/trends/settings-and-export.md#exporting-data) --- ## AI Models Koios is an **inference engine**: it runs pre-trained models against live data, but it does not train models. You train your models externally using whatever tools and environment suit your workflow (PyTorch, TensorFlow, scikit-learn, Jupyter notebooks, cloud ML platforms), then export the trained model and upload it to Koios. ### Supported Formats Koios accepts models in two formats: | Format | Extension | Exported From | |--------|-----------|---------------| | **ONNX** | `.onnx` | PyTorch, scikit-learn, and most ML frameworks | | **TFLite** | `.tflite` | TensorFlow / TensorFlow Lite | Your model file must follow specific tensor shape conventions. Inputs are shaped as `[1, input_depth, num_inputs]` (a window of historical time steps) and outputs as `[1, num_outputs]`. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md) for the full specification. ### How Inference Works Once uploaded, you connect the model to your data by creating **bindings**: mappings between the model's input/output slots and your tags. On every scan cycle, the model: 1. Reads current and historical values from its input tags 2. Normalizes them to match your training pipeline 3. Runs the model file to produce predictions 4. Writes predictions to output tags This runs continuously at the model's configured scan rate. Models can also run in [on-demand mode](https://ai-ops.com/docs/models/on-demand-inference.md) to synchronize with fresh device reads, or be grouped in a [scan group](https://ai-ops.com/docs/models/scan-groups.md) for batched execution across multiple models. > [!NOTE] Koios can help you collect training data > Even though Koios doesn't train models, it serves as a high-resolution data historian. You can collect data from your devices over time and [export it](https://ai-ops.com/docs/trends/settings-and-export.md#exporting-data) for use in your training pipeline. See [Training a Model](https://ai-ops.com/docs/models/training-a-model.md) for the full workflow. **Learn more:** [Model Introduction](https://ai-ops.com/docs/models/introduction.md) | [Training a Model](https://ai-ops.com/docs/models/training-a-model.md) | [Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md) | [Creating a Model](https://ai-ops.com/docs/models/creating-a-model.md) | [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md) | [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md) --- ## Components The **component system** lets you deploy custom Python logic that runs in real-time inside Koios. Components are useful for things that don't fit neatly into a pre-trained model: PID controllers, data transformations, state machines, alarm logic, custom protocol adapters, and more. ### Libraries Components are packaged into **libraries**: `.kcl` (Koios Component Library) files that you upload to Koios. Each library contains one or more component types. Koios ships with a **Core Library** of common building blocks (math operations, boolean logic, comparisons, signal processing), and you can build and upload your own using the [Koios Component Builder](https://ai-ops.com/docs/components/building-components.md). ### Environments and Instances To run components, you create an **environment**: an execution context with a shared scan rate. Inside the environment, you add **instances** of components from your uploaded libraries onto a visual canvas. Each instance is a running copy of a component type with its own configuration. ### Wiring to Tags Component instances have typed inputs and outputs. You **wire** these to tags (or to other component instances) on the canvas. On every scan cycle, the component engine reads all input values, executes each component in dependency order, and writes the results to output tags. This is how components integrate with the rest of the platform. They read from and write to the same tags that devices collect and AI models use. **Learn more:** [Component Introduction](https://ai-ops.com/docs/components/introduction.md) | [Libraries](https://ai-ops.com/docs/components/libraries.md) | [Environments](https://ai-ops.com/docs/components/environments.md) | [Canvas](https://ai-ops.com/docs/components/canvas.md) | [Building Components](https://ai-ops.com/docs/components/building-components.md) --- ## Trends [Trends](https://ai-ops.com/docs/trends/introduction.md) are multi-tag time-series charts for visualizing both historical and live data. You can add any combination of tags to a trend, configure multiple Y-axes for different scales, and watch values update in real time. Trends are also where you [export data](https://ai-ops.com/docs/trends/settings-and-export.md#exporting-data): select a time range, choose your format (CSV, JSON, or Parquet), and download the raw historical data for any set of tags. **Learn more:** [Trends](https://ai-ops.com/docs/trends/introduction.md) | [Traces & Axes](https://ai-ops.com/docs/trends/traces-and-axes.md) | [Settings & Export](https://ai-ops.com/docs/trends/settings-and-export.md) --- ## Dashboard [Dashboards](https://ai-ops.com/docs/dashboard/introduction.md) are customizable layouts of live widgets for monitoring tags, devices, and AI models in one view. Build a dashboard to keep the values that matter most in front of you as they update in real time. **Learn more:** [Dashboard](https://ai-ops.com/docs/dashboard/introduction.md) --- ## Explorer The [Explorer](https://ai-ops.com/docs/explorer/introduction.md) is a slide-out panel (open it with `Cmd/Ctrl+E`) for organizing your devices, tags, models, and device sets into a folder hierarchy that mirrors your plant. Use it to browse everything on your instance, check live values, and jump to any entity's detail page. **Learn more:** [Explorer](https://ai-ops.com/docs/explorer/introduction.md) --- ## Events The [Events](https://ai-ops.com/docs/events/introduction.md) page is a platform-wide activity log and audit trail. Every device connection, tag alarm, model error, and configuration change records an event that you can filter, acknowledge, and trace back to its cause. **Learn more:** [Events](https://ai-ops.com/docs/events/introduction.md) --- ## System Administration The **System** section provides tools for managing the platform itself: - [Users & Roles](https://ai-ops.com/docs/system/users.md): create accounts, assign permissions, and control access - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): schedule automatic backups and restore from snapshots - [Data Retention](https://ai-ops.com/docs/system/retention.md): configure storage monitoring, compression, and cleanup policies - [Services](https://ai-ops.com/docs/system/services.md): monitor the health and status of all platform services - [System Health](https://ai-ops.com/docs/system/performance.md): track CPU, memory, and disk usage with configurable alarms - [Network Diagnostics](https://ai-ops.com/docs/system/network.md): test connectivity and inspect network interfaces - [Logs](https://ai-ops.com/docs/system/logs.md): stream real-time service logs for troubleshooting - [API Clients](https://ai-ops.com/docs/system/endpoints.md): manage credentials for external system integrations **Learn more:** [System Overview](https://ai-ops.com/docs/system/information.md) | [Licensing](https://ai-ops.com/docs/installation/licensing.md) --- ## Putting It All Together A typical Koios deployment follows this flow: ```text Devices (connections) └── Tags (data points) ├── AI Models (inference on live data) ├── Components (custom real-time logic) └── Trends (visualization and export) ``` 1. **Connect** to your industrial equipment by creating [devices](https://ai-ops.com/docs/devices/introduction.md) 2. **Define** the data points you care about by adding [tags](https://ai-ops.com/docs/tags/introduction.md), and make sure they're historizing 3. **Deploy** pre-trained models for [AI inference](https://ai-ops.com/docs/models/introduction.md), or build [custom components](https://ai-ops.com/docs/components/introduction.md) for control logic and data processing 4. **Monitor** everything through [trends](https://ai-ops.com/docs/trends/introduction.md), [dashboards](https://ai-ops.com/docs/dashboard/introduction.md), and the [system tools](https://ai-ops.com/docs/system/information.md) --- Source: https://ai-ops.com/docs/installation/system-requirements Section: Installation # System Requirements Before installing Koios, verify that your host machine meets the following hardware and software requirements. > [!NOTE] Single Container Architecture > Koios runs all services inside a single Docker container: the configuration database, time-series database, in-memory cache, web proxy, and the application services. The requirements below account for this all-in-one deployment. ## Hardware | Resource | Minimum | Recommended | |----------|---------|-------------| | **CPU** | 2 cores | 4+ cores | | **RAM** | 4 GB | 8+ GB | | **Disk** | 20 GB free | 50+ GB free | Disk usage grows over time with historical time-series data. Plan storage based on the number of tags, scan rates, and data retention settings. ## Operating System | OS | Version | |----|---------| | **Ubuntu Server** | 20.04 LTS, 22.04 LTS, or 24.04 LTS | Ubuntu Server (minimal install) is recommended. A desktop environment is not required. Koios is managed entirely through its web interface. ## Software | Dependency | Version | |------------|---------| | **Docker Engine** | 20.10 or later | Docker is the only software dependency. See [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md) for setup instructions. ## Network | Requirement | Detail | |-------------|--------| | **Docker Hub access** | Required to pull the Koios image (unless using an offline bundle) | | **Ports 443 and 80** | Must be available on the host for HTTPS and HTTP access | | **Device network access** | The host must be able to reach industrial devices (OPC-UA, Modbus, etc.) on their respective ports | > [!TIP] Virtual Machines > If you're running Koios in a VM, use bridged networking so the container can reach devices on the local network. See [Virtual Machine](https://ai-ops.com/docs/installation/virtual-machine.md) for details. ## What's Next - [Time Synchronization](https://ai-ops.com/docs/installation/time-synchronization.md): keep the host clock accurate (strongly recommended) - [Virtual Machine](https://ai-ops.com/docs/installation/virtual-machine.md): guidance for running Koios inside a VM - [Installing Ubuntu](https://ai-ops.com/docs/installation/installing-ubuntu.md): set up the host operating system - [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md): install the Docker runtime --- Source: https://ai-ops.com/docs/installation/virtual-machine Section: Installation # Virtual Machine Koios runs well inside a virtual machine. This page covers hypervisor options and recommended VM settings. ## Supported Hypervisors | Hypervisor | Platform | |------------|----------| | **VMware ESXi / vSphere** | Enterprise | | **Microsoft Hyper-V** | Windows Server / Windows Pro | | **Proxmox VE** | Linux | | **VirtualBox** | Cross-platform (development/testing) | Any hypervisor that supports Ubuntu Server 20.04+ as a guest OS will work. ## Recommended VM Settings | Setting | Value | |---------|-------| | **CPU** | 4 vCPUs (2 minimum) | | **RAM** | 8 GB (4 GB minimum) | | **Disk** | 50 GB thin-provisioned (20 GB minimum) | | **Network adapter** | Bridged mode | | **Guest OS type** | Ubuntu 64-bit | See [System Requirements](https://ai-ops.com/docs/installation/system-requirements.md) for full hardware guidance. ## Networking > [!WARNING] Avoid NAT Networking > If Koios needs to communicate with industrial devices on the local network (OPC-UA servers, Modbus devices, PLCs), do not use NAT networking. NAT places the VM behind a virtual router, preventing direct access to devices on the host network. Use **bridged networking** so the VM receives its own IP address on the physical network. This allows Koios to reach devices directly and allows users to access the Koios web interface from other machines on the same network. > [!TIP] Industrial Device Access > For protocols like OPC-UA and Modbus TCP, ensure the VM's network can reach the device subnet. If devices are on a separate VLAN or network segment, configure the VM's network adapter accordingly or add a second adapter bridged to the device network. ## USB and Serial Pass-Through If you need to connect serial devices (RS-485, RS-232) to Koios, configure USB pass-through in your hypervisor so the VM can access the physical serial adapter. ## What's Next - [Installing Ubuntu](https://ai-ops.com/docs/installation/installing-ubuntu.md): install the guest operating system --- Source: https://ai-ops.com/docs/installation/installing-ubuntu Section: Installation # Installing Ubuntu Koios requires Ubuntu Server as its host operating system. This page covers the key settings to configure during installation. ## Download Download the Ubuntu Server ISO from the official Ubuntu website. Koios supports: - Ubuntu Server 20.04 LTS - Ubuntu Server 22.04 LTS - Ubuntu Server 24.04 LTS (recommended) ## Installation Tips When running through the Ubuntu Server installer, keep these recommendations in mind: - **Minimal installation:** select the minimal server install. Koios does not require a desktop environment or additional packages. - **OpenSSH:** enable the OpenSSH server during installation so you can manage the machine remotely. - **Static IP address:** assign a static IP address (either during installation or afterward via Netplan) so the Koios web interface is always reachable at a known address. - **Disk partitioning:** use the default guided partitioning, or allocate at least 20 GB for the root partition. Docker volumes store their data under `/var/lib/docker/`. > [!NOTE] No Desktop Required > Koios is managed entirely through its web interface. You do not need to install Ubuntu Desktop or any graphical environment. ## After Installation Once Ubuntu is installed, update the system packages: ```bash sudo apt update && sudo apt upgrade -y ``` Then proceed to install Docker Engine. ## What's Next - [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md): install the Docker runtime --- Source: https://ai-ops.com/docs/installation/time-synchronization Section: Installation # Time Synchronization We strongly recommend keeping the host clock synchronized with NTP (Network Time Protocol). Koios timestamps every device read, model prediction, event, and historical sample using the host clock, so a well-synchronized clock keeps your trends, model history, and event timelines aligned with reality. Koios runs fine without it, but accurate time makes the data far more trustworthy and easier to compare against other systems. ## What Synchronized Time Gives You | Area | Benefit | |------|---------| | **On-host accuracy** | Time-series data is written with correct timestamps, so trends, model history, and event timelines line up with reality. | | **UI freshness** | The UI compares its clock against the server clock. Large drift can trigger a warning on the System Overview page and make "live" values look stale or future-dated. | | **Cross-system comparison** | Comparing Koios timestamps against PLC, SCADA, or third-party historians stays reliable when both sides share accurate time. | ## Check and Enable It Ubuntu enables `systemd-timesyncd` automatically on a clean install. Verify it is running and synchronized: ```bash timedatectl status ``` The output should show `System clock synchronized: yes` and `NTP service: active`. If it isn't, enable it: ```bash sudo timedatectl set-ntp true ``` For air-gapped sites, point the host at an internal NTP server by editing `/etc/systemd/timesyncd.conf`: ```ini [Time] NTP=ntp.internal.example.com FallbackNTP=ntp.ubuntu.com ``` Then restart the service: ```bash sudo systemctl restart systemd-timesyncd ``` ## What's Next - [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md): install the Docker runtime on the host --- Source: https://ai-ops.com/docs/installation/installing-docker Section: Installation # Installing Docker Engine Koios runs as a Docker container, so Docker Engine must be installed on the host machine. This page covers the essentials. > [!NOTE] Docker Engine, Not Docker Desktop > Docker Desktop is not required. Docker Engine (the CLI-based runtime) is all you need for a server deployment. ## Install Docker Engine Follow the official Docker documentation to install Docker Engine on Ubuntu: 1. Set up Docker's `apt` repository 2. Install the `docker-ce` package 3. Verify the installation Refer to the official Docker Engine installation guide for Ubuntu for detailed, up-to-date instructions. ## Post-Install: Add Your User to the Docker Group By default, Docker commands require `sudo`. To run Docker as your regular user: ```bash sudo usermod -aG docker $USER ``` Log out and back in for the group change to take effect. ## Verify the Installation ```bash docker --version ``` ```bash docker run hello-world ``` If both commands succeed, Docker is ready. ## What's Next - [Pulling Koios Image](https://ai-ops.com/docs/installation/pulling-koios-image.md): download the Koios Docker image --- Source: https://ai-ops.com/docs/installation/pulling-koios-image Section: Installation # Pulling Koios Image The Koios Docker image is hosted on Docker Hub. Pull it to your server before starting the container. ## Pull the Latest Image ```bash docker pull aiopinc/koios:latest ``` The image is several GB. Download time depends on your internet connection. ## Pull a Specific Version To pin a specific release version: ```bash docker pull aiopinc/koios:v1.1.0 ``` Replace `v1.1.0` with the desired version tag. ## Verify the Image Confirm the image was downloaded successfully: ```bash docker images | grep aiopinc/koios ``` You should see the `aiopinc/koios` image listed with the appropriate tag. > [!NOTE] Offline / Air-Gapped Environments > If your server does not have internet access, contact your Ai-OPs representative for an offline installation bundle. The bundle includes the Koios image as a compressed archive that can be loaded directly with `docker load`. ## What's Next - [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md): recommended for production deployments - [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md): for development or testing --- Source: https://ai-ops.com/docs/installation/running-as-a-service Section: Installation # Running Koios as a Service For production deployments, run Koios as a systemd service. This ensures Koios starts automatically on boot and restarts on failure. Docker Engine must be installed before continuing. See [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md) if you haven't done this yet. ## Create the Service File Create the systemd service file: ```bash sudo nano /etc/systemd/system/docker.koios.service ``` Paste the following content. Toggle options to customize the service, then copy the result: ```ini [Unit] Description=Ai-Ops, Koios Docker Run Service After=docker.service Requires=docker.service [Service] TimeoutStartSec=10 Restart=always ExecStartPre=-/usr/bin/docker stop %n ExecStartPre=-/usr/bin/docker rm %n ExecStart=/usr/bin/docker run --rm --name=%n --network host \ --mount source=koios_data_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_data_influxdb,target=/root/.influxdbv2 \ --mount source=koios_media,target=/var/www/koios/media \ --mount source=koios_logs,target=/var/www/koios/logs \ --mount source=koios_certs,target=/var/www/koios/certs \ --mount source=koios_license,target=/var/www/koios/license \ --mount source=koios_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest ExecStop=/usr/bin/docker stop %n [Install] WantedBy=default.target ``` Optional flags (off by default — add to the command to enable): - Stream logs to stdout: `-e LOG_STDOUT_ENABLED=true` - OpenTelemetry collector: `-e OTEL_COLLECTOR_ENABLED=true` - Disable TLS: `-e ENABLE_TLS=false` For production it is recommended to pin a specific version tag (e.g. `v1.0.0`) so that upgrades are intentional. See [Updating Koios](https://ai-ops.com/docs/updates/general.md). ## Enable and Start the Service ```bash sudo systemctl daemon-reload sudo systemctl enable docker.koios.service sudo systemctl start docker.koios.service ``` The `Restart=always` directive ensures the service restarts automatically if the container exits unexpectedly or the host reboots. ## Check Status ```bash sudo systemctl status docker.koios.service ``` ## View Logs ```bash journalctl -u docker.koios.service -f ``` Press `Ctrl+C` to stop following the log output. ## Firewall The `--network host` flag means the container binds directly to host ports 443 (HTTPS) and 80 (HTTP). If the host has a firewall enabled (e.g. `ufw`), allow those ports: ```bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp ``` If you have customised the ports via `HTTPS_PORT` or `HTTP_PORT` environment variables, open those ports instead. See [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md) for details. ## Alternative: Explicit Port Mapping If you prefer not to use host networking, replace `--network host` with explicit port mappings in the service file. Change the `ExecStart` line to include `-p 443:443 -p 80:80` instead of `--network host`. To run several Koios instances on one host, see [Running Multiple Instances](https://ai-ops.com/docs/installation/running-multiple-instances.md). > [!WARNING] Device Communication > If Koios needs to connect to industrial devices (OPC-UA, Modbus), `--network host` is recommended so the container can reach devices directly on the host network. With explicit port mapping, you may need additional `-p` flags for device communication ports. ## First Access Once the service is running, open a browser and navigate to: ```text https:// ``` Your browser may show a certificate warning for the self-signed SSL certificate. This is expected. Accept the warning to proceed. Log in with the default credentials: - **Username:** `admin` - **Password:** `koios` > [!CAUTION] Change Default Password > Change the default admin password immediately after your first login. ## About Docker Volumes Koios stores all of its data in seven named Docker volumes: the configuration database, time-series database, uploaded files, license, certificates, logs, and secrets. These volumes live on the host and persist independently of the container, so your data survives container restarts, updates, and re-deployments. Docker automatically creates any missing volumes when the container first starts, so no manual setup is required. If you prefer to create them explicitly upfront, you can run: ```bash docker volume create koios_data_postgres docker volume create koios_data_influxdb docker volume create koios_media docker volume create koios_logs docker volume create koios_certs docker volume create koios_license docker volume create koios_secrets ``` See [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md) for a description of what each volume contains. ## What's Next - [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md): activate your Koios license - [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md): customize network ports, TLS, performance, logging, and more - [Updating Koios](https://ai-ops.com/docs/updates/general.md): upgrade to a new version safely --- Source: https://ai-ops.com/docs/installation/environment-variables Section: Installation # Environment Variables Koios is configured through environment variables passed to the Docker container. Most deployments work with the defaults, but you can customize network ports, performance tuning, logging, authentication, and reverse proxy settings. ## Setting Environment Variables Add `-e` flags to the `docker run` command in your systemd service file: ```ini ExecStart=/usr/bin/docker run --rm --name=%n --network host \ -e ENABLE_TLS=true \ -e HTTPS_PORT=8443 \ -e LOG_STDOUT_ENABLED=true \ --mount source=koios_data_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_data_influxdb,target=/root/.influxdbv2 \ --mount source=koios_media,target=/var/www/koios/media \ --mount source=koios_logs,target=/var/www/koios/logs \ --mount source=koios_certs,target=/var/www/koios/certs \ --mount source=koios_license,target=/var/www/koios/license \ --mount source=koios_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest ``` After editing the service file, reload and restart: ```bash sudo systemctl daemon-reload sudo systemctl restart docker.koios.service ``` --- ## Network & TLS Control how Koios handles HTTPS, HTTP, and port assignments. | Variable | Default | Description | |----------|---------|-------------| | `ENABLE_TLS` | `true` | When `true`, Koios serves HTTPS with a self-signed certificate and redirects HTTP to HTTPS. Set to `false` when running behind a load balancer or reverse proxy that handles TLS termination. | | `HTTPS_PORT` | `443` | The port for HTTPS traffic. Only used when `ENABLE_TLS=true`. | | `HTTP_PORT` | `80` | The port for HTTP traffic. In TLS mode, this port redirects to HTTPS. In no-TLS mode, this is the primary listening port. | ### Common Scenarios **Standard deployment (default):** No variables needed. Koios listens on ports 443 (HTTPS) and 80 (HTTP redirect). **Custom ports:** ```ini -e HTTPS_PORT=8443 \ -e HTTP_PORT=8080 \ ``` **Behind a TLS-terminating proxy (e.g., NGINX, HAProxy, AWS ALB):** ```ini -e ENABLE_TLS=false \ -e HTTP_PORT=8080 \ ``` Koios serves plain HTTP on port 8080. The proxy handles HTTPS and forwards traffic to this port. > [!WARNING] Port mapping with host networking > When using `--network host`, the container binds directly to the host's ports. Make sure your chosen ports are not already in use. If using explicit port mapping instead (e.g., `-p 8443:443`), the port variables control the ports *inside* the container. --- ## Performance Tuning Adjust worker threads and timeouts for your deployment size. | Variable | Default | Description | |----------|---------|-------------| | `UVICORN_WORKERS` | CPU count (max 4) | Number of web server worker processes. Increase for deployments with many concurrent API clients. | | `GRAPHQL_REQUEST_TIMEOUT` | `30` | Maximum time (in seconds) for a single API request to complete. Increase if large queries (e.g., bulk exports) are timing out. | | `DC_THREAD_POOL_SIZE` | `8` | Number of worker threads for device polling. Increase for deployments with many devices to improve polling concurrency. | | `PE_THREAD_POOL_SIZE` | `8` | Number of worker threads for AI model inference. Increase for deployments running many models concurrently. | | `PE_GROUP_THREAD_POOL_SIZE` | `32` | Maximum threads for parallel model inference within a scan group. When a scan group fires, all its models can run concurrently up to this limit. | | `EE_THREAD_POOL_SIZE` | `8` | Number of worker threads for expression evaluation. Increase for deployments with many calculated tags (expressions). | | `EE_IN_MEMORY_HEARTBEAT_INTERVAL` | `60` | Safety-net poll interval (in seconds) for in-memory tag sources feeding expression tags and AI models. The Expression Evaluator now reacts to live in-memory updates via push events; this heartbeat is purely a fallback to detect a stale producer. Lower it only if you suspect a producer is silently failing to publish. The legacy `EE_IN_MEMORY_SCAN_RATE` variable is still honored for backward compatibility. | > [!TIP] When to increase thread pools > The default thread pool sizes work well for most deployments (up to ~50 devices, ~50 models, or ~50 expressions). If you have significantly more, increase the corresponding pool size. Monitor CPU usage on the **System > Health** page. If the server has spare capacity but polling, inference, or expression evaluation feels slow, increasing the pool may help. --- ## Authentication Control JWT token lifetimes for user sessions. | Variable | Default | Description | |----------|---------|-------------| | `KOIOS_ACCESS_TOKEN_LIFETIME_SECONDS` | `3600` | How long an access token remains valid (in seconds). Default is 1 hour. Shorter values improve security; longer values reduce re-authentication frequency. | | `KOIOS_REFRESH_TOKEN_LIFETIME_DAYS` | `7` | How long a refresh token remains valid (in days). This determines the maximum session duration before a user must log in again. | --- ## Logging Control log output destination, format, and verbosity. | Variable | Default | Description | |----------|---------|-------------| | `LOG_STDOUT_ENABLED` | `false` | When `true`, streams all service logs to container stdout, making them visible via `docker logs`. When `false`, logs are written to files inside the container's log volume and viewable from the in-app log viewer. | | `KOIOS_DEFAULT_LOG_LEVEL` | `INFO` | Log verbosity for all Koios services. Options: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`. | > [!NOTE] In-app log viewer > Regardless of these settings, service logs are always available in the in-app log viewer at **System > Service Logs**. The `LOG_STDOUT_ENABLED` variable controls whether logs are *also* sent to container stdout. --- ## Log Forwarding (OpenTelemetry) Forward logs, metrics, and traces from Koios to an external observability platform using the built-in OpenTelemetry Collector. | Variable | Default | Description | |----------|---------|-------------| | `OTEL_COLLECTOR_ENABLED` | `false` | When `true`, starts the OpenTelemetry Collector inside the container. | | `OTEL_REMOTE_ENDPOINT` | *(none)* | The remote OTLP HTTP endpoint URL (e.g., `https://your-collector:4318`). Required when the collector is enabled. | | `OTEL_REMOTE_AUTH_TOKEN` | *(none)* | Bearer token for authenticating to the remote endpoint. | ### Example: Forwarding to Grafana Cloud ```ini -e OTEL_COLLECTOR_ENABLED=true \ -e OTEL_REMOTE_ENDPOINT=https://otlp-gateway-prod-us-east-0.grafana.net/otlp \ -e OTEL_REMOTE_AUTH_TOKEN=your-grafana-cloud-token \ ``` --- ## OPC-UA Configuration | Variable | Default | Description | |----------|---------|-------------| | `OPCUA_CERT_HOSTNAME` | System hostname | The hostname embedded in the OPC-UA client's application URI and used when generating client certificates. Override this if the system hostname doesn't match what your OPC-UA servers expect for certificate validation. | --- ## Device Access For the rare case of attaching serial, GPIO, I2C, or SPI hardware directly to the host. Two steps are needed: expose the host device node with `--device`, and give the Koios services membership in the group that owns it, since device nodes are group-owned and the services run as an unprivileged user. | Variable | Default | Description | |----------|---------|-------------| | `KOIOS_EXTRA_GROUPS` | *(none)* | Comma-separated group names and/or numeric group IDs the Koios services should join, so they can reach host device nodes exposed with `--device`. Standard serial (`dialout`) is already included. Group ID `0` is refused; unresolvable entries are skipped. | Standard serial devices (the `dialout` group) work with no extra configuration. For GPIO, I2C, or SPI, whose group IDs vary between hosts, pass the numeric group ID. Find it with `stat -c '%g' /dev/` on the host: ```ini --device /dev/gpiochip0 \ -e KOIOS_EXTRA_GROUPS=998 \ ``` --- ## Reverse Proxy Settings > [!NOTE] Advanced configuration > These settings are only needed when Koios is deployed behind a reverse proxy (NGINX, Apache, HAProxy, AWS ALB, etc.) that handles TLS termination. For standalone deployments with `ENABLE_TLS=true`, the defaults work correctly. When running behind a reverse proxy, you may need to configure CSRF protection and cookie settings so that the proxy's domain and protocol are trusted. ### CSRF Protection | Variable | Default | Description | |----------|---------|-------------| | `DJANGO_CSRF_TRUSTED_ORIGINS` | *(empty)* | Comma-separated list of trusted origins. **Must be set** when behind a proxy to match the browser's Origin header. Example: `https://koios.example.com,https://other.example.com` | | `DJANGO_CSRF_COOKIE_SECURE` | `True` | Set to `False` if serving over plain HTTP (e.g., behind a proxy on a private network). | | `DJANGO_CSRF_COOKIE_HTTPONLY` | `False` | Set to `True` to prevent JavaScript from reading the CSRF cookie. | | `DJANGO_CSRF_COOKIE_DOMAIN` | *(current domain)* | Set to `.example.com` for cross-subdomain CSRF cookie sharing. | | `DJANGO_CSRF_COOKIE_PATH` | `/` | URL path for the CSRF cookie. | | `DJANGO_CSRF_COOKIE_SAMESITE` | *(browser default)* | SameSite attribute: `Lax`, `Strict`, or `None`. | ### Session Cookies | Variable | Default | Description | |----------|---------|-------------| | `DJANGO_SESSION_COOKIE_SECURE` | `True` | Set to `False` if serving over plain HTTP. | | `DJANGO_SESSION_COOKIE_DOMAIN` | *(current domain)* | Domain for the session cookie. | | `DJANGO_SESSION_COOKIE_PATH` | `/` | URL path for the session cookie. | | `DJANGO_SESSION_COOKIE_SAMESITE` | `Lax` | SameSite attribute for the session cookie. | ### Proxy Headers | Variable | Default | Description | |----------|---------|-------------| | `DJANGO_USE_X_FORWARDED_HOST` | `True` | Use the `X-Forwarded-Host` header from the proxy to determine the request host. | | `DJANGO_USE_X_FORWARDED_PORT` | `True` | Use the `X-Forwarded-Port` header from the proxy. | | `DJANGO_SECURE_PROXY_SSL_HEADER` | `HTTP_X_FORWARDED_PROTO,https` | Header and expected value (comma-separated) used to detect HTTPS behind a proxy. | | `DJANGO_SECURE_SSL_REDIRECT` | `False` | When `True`, the application redirects all HTTP requests to HTTPS. Usually `False` when the proxy handles redirection. | ### Example: Behind NGINX with Custom Domain ```ini -e ENABLE_TLS=false \ -e HTTP_PORT=8080 \ -e DJANGO_CSRF_TRUSTED_ORIGINS=https://koios.example.com \ -e DJANGO_CSRF_COOKIE_SECURE=True \ -e DJANGO_SESSION_COOKIE_SECURE=True \ ``` --- ## Debugging These variables are intended for troubleshooting and should not be enabled in normal operation. | Variable | Default | Description | |----------|---------|-------------| | `DJANGO_DEBUG` | `False` | Enables verbose error pages with stack traces. **Never enable in production**. It exposes sensitive information. | | `KOIOS_DB_QUERY_LOG` | *(disabled)* | Database query logging for the data collection and inference services. Set to `summary` for a periodic 60-second summary, or `verbose` for every individual query with timing. Useful for diagnosing slow queries. | --- ## What's Next - [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md): apply these variables in your systemd service file - [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md): pass variables to one-off `docker run` commands - [Updating Koios](https://ai-ops.com/docs/updates/general.md): upgrade to a new version safely --- Source: https://ai-ops.com/docs/installation/manually-starting-koios Section: Installation # Manually Starting Koios Use manual Docker commands for development, testing, or one-off runs. For production deployments, see [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md). ## Start the Container Run Koios with host networking and all volume mounts. Docker automatically creates any named volumes that don't already exist. ```bash docker run -d --name koios --network host \ --mount source=koios_data_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_data_influxdb,target=/root/.influxdbv2 \ --mount source=koios_media,target=/var/www/koios/media \ --mount source=koios_logs,target=/var/www/koios/logs \ --mount source=koios_certs,target=/var/www/koios/certs \ --mount source=koios_license,target=/var/www/koios/license \ --mount source=koios_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest ``` Optional flags (off by default — add to the command to enable): - Stream logs to stdout: `-e LOG_STDOUT_ENABLED=true` - OpenTelemetry collector: `-e OTEL_COLLECTOR_ENABLED=true` - Disable TLS: `-e ENABLE_TLS=false` ## Alternative: Explicit Port Mapping If you prefer not to use host networking, replace `--network host` with explicit port mappings (`-p 443:443 -p 80:80`). > [!WARNING] Device Communication > If Koios needs to connect to industrial devices (OPC-UA, Modbus), `--network host` is recommended so the container can reach devices directly on the host network. ## First Access Open a browser and navigate to: ```text https:// ``` Your browser may show a certificate warning for the self-signed SSL certificate. This is expected. Accept the warning to proceed. Log in with the default credentials: - **Username:** `admin` - **Password:** `koios` > [!CAUTION] Change Default Password > Change the default admin password immediately after your first login. ## Stop and Remove the Container To stop Koios: ```bash docker stop koios ``` To remove the stopped container: ```bash docker rm koios ``` Stopping or removing the container does not affect your data: all databases, media, logs, certificates, and credentials are stored in Docker volumes and will be available when you start a new container. ## View Container Logs If you started the container with **Stream logs to stdout** enabled, follow the output with: ```bash docker logs -f koios ``` Press `Ctrl+C` to stop following the log output. > [!TIP] Log files are always available > Even without stdout streaming, logs are written to files inside the container. You can access them directly with `docker exec -it koios ls /var/www/koios/logs/`. ## What's Next - [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md): activate your Koios license - [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md): customize network ports, TLS, performance, and logging --- Source: https://ai-ops.com/docs/installation/running-multiple-instances Section: Installation # Running Multiple Instances You can run more than one Koios container on a single host, for example to separate lines, sites, or test environments on shared hardware. Each instance keeps its own database, history, certificates, and license in its own set of named volumes, so the instances stay fully isolated. The one thing that has to change from a single-instance install is networking. The recommended `--network host` flag binds the container directly to host ports 443 and 80, so a second instance started the same way would fail to bind. To run several instances side by side, give each one **explicit port mappings** and its **own volume set**. ## Map Each Instance to a Unique Port Replace `--network host` with `-p` mappings and pick a distinct host port for each instance's HTTPS port (443). Give every instance its own container name and its own seven volumes: ```bash # Instance A, reachable at https://:8443 docker run -d --name koios-a \ -p 8443:443 \ --mount source=koios_a_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_a_influxdb,target=/root/.influxdbv2 \ --mount source=koios_a_media,target=/var/www/koios/media \ --mount source=koios_a_logs,target=/var/www/koios/logs \ --mount source=koios_a_certs,target=/var/www/koios/certs \ --mount source=koios_a_license,target=/var/www/koios/license \ --mount source=koios_a_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest # Instance B, reachable at https://:8444 docker run -d --name koios-b \ -p 8444:443 \ --mount source=koios_b_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_b_influxdb,target=/root/.influxdbv2 \ --mount source=koios_b_media,target=/var/www/koios/media \ --mount source=koios_b_logs,target=/var/www/koios/logs \ --mount source=koios_b_certs,target=/var/www/koios/certs \ --mount source=koios_b_license,target=/var/www/koios/license \ --mount source=koios_b_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest ``` Each instance is then reached at `https://:`, for example `https://:8443` and `https://:8444`. Log in to each one separately; every instance has its own `admin` account and its own license. A few rules keep the instances isolated: - **A unique host port per instance.** Only one container can own a given host port. Map the container's 443 to a different host port for each instance. You rarely need to map 80, since you connect to each instance by its HTTPS port directly. - **A unique volume set per instance.** Each container needs its own seven volumes (`koios_a_*`, `koios_b_*`, and so on). Never share a volume between instances, as doing so will corrupt data. - **A unique container name.** Use `--name koios-a`, `koios-b`, and so on, so Docker can tell them apart. > [!WARNING] Device connectivity without host networking > `--network host` lets a container reach industrial devices directly on the host network. Without it, a container only sees the ports you map. If an instance polls devices over OPC-UA, Modbus, or EtherNet/IP, make sure its container can route to them, for example by mapping the relevant device ports or attaching the container to a Docker network that can reach the plant network. ## Run Each Instance as a Service Most deployments run each instance as its own systemd service so it starts on boot and restarts on failure. Give every instance its own unit file, named for the instance (for example `docker.koios-a.service`). Create the unit for the first instance: ```bash sudo nano /etc/systemd/system/docker.koios-a.service ``` Paste a unit that carries the same explicit port and volume set from above: ```ini [Unit] Description=Koios (instance A) After=docker.service Requires=docker.service [Service] Restart=always RestartSec=5 ExecStartPre=-/usr/bin/docker rm -f koios-a ExecStart=/usr/bin/docker run --rm --name koios-a \ -p 8443:443 \ --mount source=koios_a_postgres,target=/var/lib/postgresql/16/main \ --mount source=koios_a_influxdb,target=/root/.influxdbv2 \ --mount source=koios_a_media,target=/var/www/koios/media \ --mount source=koios_a_logs,target=/var/www/koios/logs \ --mount source=koios_a_certs,target=/var/www/koios/certs \ --mount source=koios_a_license,target=/var/www/koios/license \ --mount source=koios_a_secrets,target=/var/www/koios/secrets \ aiopinc/koios:latest ExecStop=/usr/bin/docker stop koios-a [Install] WantedBy=default.target ``` Enable and start it: ```bash sudo systemctl daemon-reload sudo systemctl enable docker.koios-a.service sudo systemctl start docker.koios-a.service ``` Then repeat for each additional instance, changing four things in every copy: the **unit file name** (`docker.koios-b.service`), the **container name** (`koios-b`), the **host port** (`-p 8444:443`), and the **volume set** (`koios_b_*`). Keeping these four distinct is what lets the instances coexist on one host. Check any instance with `systemctl status docker.koios-a.service`, and follow its logs with `docker logs -f koios-a`. See [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md) for the single-instance walkthrough, firewall notes, and version pinning. ## Manage the Fleet from One Place Once several instances are running, the [Koios Admin Console](https://ai-ops.com/docs/admin-console/introduction.md) gives you a single view of their health, service state, and licenses. Connect each instance by its `host:port` from the console's [Instances page](https://ai-ops.com/docs/admin-console/managing-instances.md) and monitor them all without signing into each one. --- Source: https://ai-ops.com/docs/installation/licensing Section: Installation # Licensing Koios Koios requires a valid license to operate. On first login, the application redirects you to a license activation wizard. ## Activation Steps ### Step 1: Enter Your License Key Paste the license key provided by your Ai-OPs representative and click **Download Activation File**. This downloads a `.req` file containing your hardware fingerprint. ### Step 2: Submit to the License Portal Upload the `.req` file at the Ai-OPs license portal: ```text https://ai-op.com/license/ ``` The portal will return a `koios.lic` license file. Download it to your computer. ### Step 3: Upload the License File Back in the Koios activation wizard, drag and drop (or browse to select) the `koios.lic` file. Koios validates the license and, on success, displays a confirmation screen. You now have full access to the application. > [!NOTE] Need a License Key? > Contact your Ai-OPs representative to obtain a license key for your deployment. ## Viewing License Details After activation, license information is available at **System > License**. This page shows: - Product name - License ID - Hardware ID - Expiry date ## Re-Activation If you need to re-activate your license (for example, after moving Koios to a different machine), you can start the activation process again from the **System > License** page. > [!WARNING] Hardware-Tied License > The Koios license is tied to the hardware it was activated on. If you move Koios to a different server or VM, you will need to re-activate using a new activation file. ## What's Next - [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md): customize ports, TLS, performance, and logging - [Updating Koios](https://ai-ops.com/docs/updates/general.md): upgrade to a new version safely - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): set up scheduled backups --- Source: https://ai-ops.com/docs/installation/backup-restore Section: Installation # Backing Up Docker Volumes > [!TIP] Use the In-App Backup First > For nearly all cases, use the in-app backup at **System > Backup**. See [Backup & Restore](https://ai-ops.com/docs/system/backup.md). It runs without stopping Koios, supports scheduled retention, and produces a single archive you can download. > > This page exists for the cases where the in-app backup isn't an option. ## When You'd Use This | Scenario | Why direct volume access | |----------|--------------------------| | Koios won't start or is otherwise unreachable | The in-app UI is unavailable, so the only way to capture state is directly from the volumes | | Migrating to a new host | Lets you move the raw volumes between machines without going through the app | | Host-level disaster-recovery scripts | Volumes can be snapshotted from the host on the same schedule as the rest of your infrastructure | If none of these apply, stop here and use the in-app backup instead. ## Docker Volumes All Koios data lives in seven Docker volumes: | Volume | Contents | Priority | |--------|----------|----------| | `koios_data_postgres` | Configuration database (devices, tags, users, models) | Critical | | `koios_data_influxdb` | Time-series database (historical tag values) | Critical | | `koios_secrets` | Auto-generated credentials (database passwords, Django secret key, time-series database token) | Critical | | `koios_media` | Uploaded files (ML models, component packages) | High | | `koios_license` | License activation file | High | | `koios_certs` | SSL certificates | Medium | | `koios_logs` | Application log files | Low | The three **Critical** volumes are enough to rebuild a working install. The others carry uploads and configuration that are convenient to keep but recoverable from elsewhere. ## Backup > [!WARNING] Stop Koios First > Stop the container before backing up the database volumes. Backing up a live database can produce a corrupt archive. > > ```bash > sudo systemctl stop docker.koios.service # if running as a service > docker stop koios # if running manually > ``` Back up a volume by running a temporary Alpine container that mounts the volume and creates a tar archive in the current directory: **Linux / macOS** ```bash docker run --rm \ -v koios_data_postgres:/data \ -v $(pwd):/backup \ alpine tar czf /backup/koios_data_postgres.tar.gz -C /data . ``` **Windows** ```powershell docker run --rm ` -v koios_data_postgres:/data ` -v ${PWD}:/backup ` alpine tar czf /backup/koios_data_postgres.tar.gz -C /data . ``` Run the same command for each volume you want to back up, swapping the volume name and archive filename. At minimum, back up the three **Critical** volumes (`koios_data_postgres`, `koios_data_influxdb`, `koios_secrets`). Add `koios_media` and `koios_license` if you have uploaded models or an activated license. ## Restore > [!WARNING] Stop Koios Before Restoring > Restoring into a running container will corrupt the databases. Stop Koios, then restore each archive back into its volume. This command deletes the volume's contents before extracting, so the restore is a clean replacement: **Linux / macOS** ```bash docker run --rm \ -v koios_data_postgres:/data \ -v $(pwd):/backup \ alpine sh -c "rm -rf /data/* && tar xzf /backup/koios_data_postgres.tar.gz -C /data" ``` **Windows** ```powershell docker run --rm ` -v koios_data_postgres:/data ` -v ${PWD}:/backup ` alpine sh -c "rm -rf /data/* && tar xzf /backup/koios_data_postgres.tar.gz -C /data" ``` Repeat for every volume you need to restore, then start Koios again. ## What's Next - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): the in-app backup that runs without stopping Koios and supports scheduled retention. --- Source: https://ai-ops.com/docs/protocols/introduction Section: Protocols # Protocols A **protocol** defines how Koios communicates with an external device or data source. When you create a device, you choose a protocol. This determines the connection settings you'll need to provide and the types of tags you can create. > [!WARNING] Protocol cannot be changed after creation > The protocol is locked once a device is created. If you need a different protocol, > create a new device and recreate the tags. ## Supported Protocols | Protocol | Use Case | Configuration Guide | |----------|----------|---------------------| | **OPC-UA** | PLCs, SCADA systems, historians, and modern industrial equipment | [OPC-UA Device](https://ai-ops.com/docs/devices/creating-opc-ua.md) | | **Modbus TCP** | Sensors, meters, and simple controllers using register-based addressing | [Modbus TCP Device](https://ai-ops.com/docs/devices/creating-modbus-tcp.md) | | **EtherNet/IP** | Allen-Bradley Logix controllers and generic CIP-compliant devices | [EtherNet/IP Device](https://ai-ops.com/docs/devices/creating-ethernet-ip.md) | | **SOAP** | RDM HVAC controllers via web services | [SOAP Device](https://ai-ops.com/docs/devices/creating-soap.md) | | **REST** | CAREL BOSS building management systems | [REST Device](https://ai-ops.com/docs/devices/creating-rest.md) | | **Microsoft SQL** | Querying data directly from SQL Server databases via ODBC | [Microsoft SQL Device](https://ai-ops.com/docs/devices/creating-mssql.md) | Protocols are system-defined. You cannot add or delete them. Protocols you don't use can be hidden from the device create flow with the visibility toggle on the Protocols list or detail page. ## Protocol Details ### OPC-UA OPC Unified Architecture (shown as **OPC UA** in the app) is the modern standard for industrial data exchange. It provides a platform-independent, service-oriented architecture for communicating with PLCs, SCADA systems, historians, and other industrial equipment. Koios connects as an OPC-UA client and supports: - **Server discovery**: browse your network for available OPC-UA servers and endpoints - **Security modes**: None, Sign, or Sign & Encrypt - **Security policies**: Basic128Rsa15, Basic256, Basic256Sha256 - **Authentication**: Anonymous or Username/Password - **Node browsing**: explore the server's address space to find and select tags ### Modbus TCP Modbus TCP is a widely-used protocol for communicating with sensors, meters, and simple PLCs over Ethernet. It uses a register-based addressing model where data points are identified by register type and address number. ### EtherNet/IP EtherNet/IP (shown as **Ethernet/IP** in the app) uses the Common Industrial Protocol (CIP) to communicate with industrial devices over standard Ethernet. Koios supports two device types under this protocol: - **Logix Controller**: connects to Allen-Bradley ControlLogix and CompactLogix controllers using tag-based addressing. Includes a tag browser for exploring the controller's tag database. - **Generic CIP**: connects to any CIP-compliant device (variable frequency drives, I/O modules, non-Allen-Bradley equipment) using assembly-based addressing. Supports EDS file upload for structured browsing of device data. ### SOAP The SOAP (Simple Object Access Protocol) implementation in Koios is designed for **RDM** (Resource Data Manager) controllers. RDM devices expose a SOAP-based API for reading and writing HVAC parameters. ### REST The REST protocol currently connects specifically to **CAREL BOSS** building management systems. The device-type selector defaults to BOSS, and no other REST device type is implemented, so request formatting and response parsing are BOSS-specific. Koios sends HTTP requests to the configured BOSS endpoint and parses the response to extract tag values. ### Microsoft SQL Microsoft SQL devices allow Koios to query data from SQL Server databases using ODBC. Each tag on an SQL device executes a SQL query on every scan cycle and stores the result as a live value. This is useful for integrating data from business systems, energy management platforms, or external historians. ## Certificates Some OPC-UA servers require certificate-based trust in addition to (or instead of) username/password authentication. See [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md) for details on managing certificates in Koios. ## What's Next - [Create a Device](https://ai-ops.com/docs/devices/introduction.md): add a device on the protocol you picked - [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md): manage certificate-based trust for OPC-UA servers --- Source: https://ai-ops.com/docs/protocols/opc-ua-certificates Section: Protocols # OPC-UA Certificates When connecting to an OPC-UA server with a security mode other than **None**, Koios uses X.509 certificates to establish trust. The server verifies Koios's client certificate, and in some cases Koios verifies the server's certificate as well. Certificates are only required when the Security Mode is set to **Sign** or **Sign & Encrypt**. If you're connecting with Security Mode **None**, no certificate is needed. Koios manages certificates centrally. You create them once and assign them to any number of OPC-UA devices. ## Managing Certificates The certificate manager is found on the **OPC-UA protocol detail page** under the **Certificates** tab. Navigate to **Protocols** and select **OPC-UA** to access it. The certificates table shows all available client certificates with their name, common name, expiry date, the number of devices using each one, and their current status. ### Certificate Status Each certificate shows one or more status badges: | Badge | Meaning | |-------|---------| | **Valid** | The certificate is within its validity period and ready to use | | **Expired** | The certificate has passed its expiry date and should be regenerated or replaced | | **Missing Files** | The certificate or private key file is not present on disk, so downloads will be unavailable | One certificate is always marked as the **default** (indicated by a star icon). Devices that don't have a specific certificate assigned will use the default certificate automatically. ## Generating a Certificate The simplest way to get started is to let Koios generate a self-signed certificate. 1. On the Certificates tab, click **Generate** 2. Enter a **Name** for the certificate (e.g. "Plant A Certificate") 3. Optionally enter a **Description** 4. Optionally enter a **Hostname**, used in the certificate's Common Name and Application URI. If left blank, Koios uses the system hostname 5. Click **Generate** The new certificate appears in the table immediately and can be assigned to devices. Generated certificates are self-signed. Most OPC-UA servers require you to explicitly trust them before they'll accept a secure connection (see [Establishing Trust](#establishing-trust-with-opc-ua-servers) below). ## Uploading a Certificate If you have an existing certificate and private key (e.g. issued by your organization's CA), you can upload them. 1. On the Certificates tab, click **Upload** 2. Enter a **Name** for the certificate 3. Optionally enter a **Description** 4. Select the **Certificate File**: DER or PEM encoded X.509 certificate (`.der`, `.pem`, `.crt`, or `.cer`) 5. Select the **Private Key File**: PEM encoded private key (`.pem` or `.key`) 6. If that key is passphrase-protected, enter its **Key Passphrase**. Leave it blank for an unencrypted key. 7. Click **Upload** ## Viewing Certificate Details Click any row in the certificates table to open a detail drawer showing: - **Common Name**: the X.509 subject CN - **Organization**: the organization field, if present - **Application URI**: the OPC-UA application URI embedded in the certificate - **Validity**: the "Valid From" and "Valid Until" dates - **Assigned Devices**: how many devices are using this certificate ### Downloading Certificate Files If the certificate files exist on disk, the detail drawer shows download buttons: - **Certificate (.der)**: the public certificate file, which you may need to import into OPC-UA servers for trust - **Private Key (.pem)**: the private key file. Only download this when necessary (e.g. for backup). Anyone with the private key can impersonate Koios to your OPC-UA servers. ## Regenerating a Certificate If a certificate has expired or been compromised, you can regenerate it in place. This creates a new key pair and certificate while keeping the same name and device assignments. 1. Open the certificate's detail drawer 2. Click **Regenerate Certificate** 3. Confirm the action > [!WARNING] Servers must re-trust the new certificate > After regenerating, any OPC-UA server that trusted the previous certificate will reject connections until you add the new certificate to its trust list. Plan regeneration during a maintenance window if possible. ## Deleting a Certificate 1. Open the certificate's detail drawer 2. Click **Delete Certificate** (this button is hidden for the default certificate, which cannot be deleted) 3. Confirm the action Devices that were assigned to the deleted certificate will fall back to the default certificate. ## Assigning Certificates to Devices Certificates are assigned on each OPC-UA device's **Configuration** tab. 1. Navigate to the device's detail page 2. On the Configuration tab, set the **Security Mode** to **Sign** or **Sign & Encrypt**. The certificate selector appears 3. Choose a certificate from the **Client Certificate** dropdown, or leave it blank to use the default 4. You can also click the **+** button next to the dropdown to generate a new certificate without leaving the device page 5. **Save** the configuration ## Establishing Trust with OPC-UA Servers Most OPC-UA servers won't accept a secure connection from an unknown client. After generating or uploading a certificate in Koios, you typically need to: 1. **Download** the Koios client certificate (`.der` file) from the detail drawer 2. **Import** it into the OPC-UA server's trusted certificates folder (the exact location depends on the server software) 3. **Restart** the OPC-UA server if required (some servers pick up new trusted certificates automatically) Some servers support an "accept on first connect" workflow where they automatically move rejected certificates to a pending folder. In that case: 1. Trigger a connection attempt from Koios by either **enabling the device** or clicking **Test** on the device's Configuration tab. The connection will fail with a message like "Certificate rejected by server" — an untrusted or expired certificate is a common reason a device stays on "Failed to Connect", so see [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) to diagnose it 2. On the OPC-UA server, find the rejected certificate and move it to the trusted folder 3. Koios will automatically connect on the next scan cycle if the device is enabled. If you used the Test button, click Test again to verify The exact trust process varies by OPC-UA server software (Kepware, Prosys, Unified Automation, Siemens, etc.). Refer to your server's documentation for details on managing trusted client certificates. ## What's Next - [Creating an OPC-UA Device](https://ai-ops.com/docs/devices/creating-opc-ua.md): configure a device connection that uses one of these certificates - [Protocols](https://ai-ops.com/docs/protocols/introduction.md): back to the protocol overview --- Source: https://ai-ops.com/docs/devices/introduction Section: Devices # Devices A **device** in Koios represents a connection to an external data source: a PLC, an OPC-UA server, a sensor gateway, a database, or an API. Devices handle the communication layer: each device maintains a persistent connection to its data source and scans its tags on a configurable cycle. ## What Devices Do Each device maintains a persistent connection to its data source and performs two core operations on a configurable scan cycle: - **Read**: collect current values from the device's tags (inputs) - **Write**: push computed values back to the device's tags (outputs) The scan cycle repeats at the device's **scan rate** (configurable from 0.1 to 3,600 seconds). Between scans, Koios monitors the connection health and automatically retries on transient failures. ## Supported Protocols Koios supports several industrial and data protocols: OPC-UA, Modbus TCP, EtherNet/IP, SOAP, REST, and Microsoft SQL. Each protocol defines how Koios communicates with the device and what configuration is required. See [Protocols](https://ai-ops.com/docs/protocols/introduction.md) for a full breakdown of each protocol, when to use it, and links to protocol-specific configuration guides. > [!TIP] Not all tags need a device > Only **device tags** belong to a device. **Expression tags** compute values from formulas, and **in-memory tags** historize values from AI models and other services. Neither requires a device connection. See [Tag Source Types](https://ai-ops.com/docs/tags/introduction.md#tag-source-types) for details. ## Device Lifecycle A device moves through a simple lifecycle from creation to active data collection: 1. **Create**: choose a protocol, provide connection details, and set a scan rate 2. **Enable**: activate the device so the data collector begins scanning 3. **Running**: the device connects, reads/writes tags on each scan cycle, and streams live data 4. **Stopped / Failed**: a device stops when disabled, or enters a failed state if it encounters persistent connection errors > [!NOTE] Hot Reload > Configuration changes (scan rate, credentials, connection parameters) take effect > without restarting the data collector service. Koios detects changes and reconnects > automatically. ## Device Status Every device has a real-time status that reflects its current health: | Status | Meaning | |--------|---------| | **Running** | Actively scanning. Connection is healthy, tags are being read/written | | **Stopped** | Not scanning. The device is disabled or the service has not started it | | **Failed** | An error has occurred. The device attempted to connect or scan and encountered a problem | When a device fails, Koios records an **error code**, **error message**, and **error detail** to help you diagnose the issue. The device will automatically retry up to three times before entering a persistent failed state. ## Tags Device tags are the individual data points on a device: a temperature sensor reading, a motor speed setpoint, a database column value. Each device tag belongs to exactly one device and inherits its protocol. Tags have a **usage** that determines how Koios interacts with them: - **Input** tags are read from the device on each scan - **Output** tags are written to the device (e.g. AI model predictions sent back to a PLC) For a deeper look at tags, see the [Tags](https://ai-ops.com/docs/tags/introduction.md) section. ## Device Sets For scenarios requiring **redundancy**, devices can be grouped into a **device set**. A device set contains multiple devices of the same protocol, ordered by priority. If the active device fails, Koios automatically switches to the next device in the set. Tags marked as redundant read from whichever device is currently active in the set, so redundant tags keep reading through a device failure without manual intervention. See [Device Sets](https://ai-ops.com/docs/devices/device-sets.md) for creating a set, ordering members by priority, and managing the active device. ## Key Concepts | Concept | Description | |---------|-------------| | **Scan rate** | How often Koios polls the device for new data (seconds) | | **Heartbeat** | A toggling counter that external systems can monitor to verify Koios is running | | **On-demand scanning** | Allows AI models to trigger an immediate device read outside the normal scan cycle. See [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md) for device settings and [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md) for the full picture | | **Log level** | Per-device log verbosity (Debug, Info, Warning, Error) for troubleshooting | ## What's Next - [Creating a Device](https://ai-ops.com/docs/devices/creating-getting-started.md): step-by-step guide to adding a new device - [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md): configuring freshness and batching for AI model synchronization - [Device Sets](https://ai-ops.com/docs/devices/device-sets.md): group devices for redundancy and automatic failover - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md): diagnosing and resolving device errors --- Source: https://ai-ops.com/docs/devices/creating-getting-started Section: Devices # Creating a Device To create a device, navigate to the **Devices** page and click the `+ Add Device` button in the top-right corner. This opens a form where you configure the basic properties of the device. > [!NOTE] Protocol-specific configuration comes later > The create form only captures the essentials: name, protocol, and scan rate. > Protocol-specific settings (endpoints, credentials, timeouts) are configured on the > device's **Configuration** tab after creation. ## Form Fields ### Name A unique, human-readable identifier for the device. This is how you'll find and reference the device throughout the platform. - **Required** - Must be unique across all devices - Examples: `Chiller-01`, `AHU North Wing`, `Warehouse PLC` ### Description An optional free-text field for notes about the device: its location, purpose, or any context that helps your team identify it. ### Protocol The communication protocol Koios will use to connect to this device. Select from the available protocols in the dropdown. See [Protocols](https://ai-ops.com/docs/protocols/introduction.md) for a full description of each protocol and when to use it. > [!WARNING] Protocol cannot be changed after creation > The protocol is locked once the device is created. If you need to change it, > you'll need to create a new device with the correct protocol and recreate the tags. ### Scan Rate (seconds) How often Koios reads from and writes to the device. The default is **1 second**. - **Required** - Minimum: **0.1 seconds** (100ms) - Step: **0.1 seconds** - Typical ranges: - **0.1–1s** for fast-changing process data (temperatures, pressures) - **5–30s** for slower-moving data (energy meters, environmental sensors) - **60–300s** for infrequently changing data (database queries, batch systems) > [!TIP] Start conservative > A faster scan rate means more network traffic and CPU usage. Start with a moderate > rate (e.g. 5 seconds) and decrease it only if your application needs faster data. ### Heartbeat Scans The number of scan cycles between heartbeat toggles. The create form pre-fills **10 scans** (the stored default when omitted on import is **1 scan**). The heartbeat is a counter that toggles on a regular interval, allowing external systems (like a BMS or SCADA) to verify that Koios is actively scanning. If the heartbeat stops toggling, the external system knows something is wrong. - **Required** - Minimum: **1 scan** - With the default scan rate of 1 second and heartbeat scans of 10, the heartbeat toggles every 10 seconds ## After Creation Once you click **Create Device**, Koios creates the device and navigates you to its **Configuration** tab. From here you'll need to: 1. **Configure protocol settings**: provide the connection details for your protocol (endpoint URL, hostname, credentials, etc.). See the protocol-specific guides: - [Creating an OPC-UA Device](https://ai-ops.com/docs/devices/creating-opc-ua.md) - [Creating a Modbus TCP Device](https://ai-ops.com/docs/devices/creating-modbus-tcp.md) - [Creating an EtherNet/IP Device](https://ai-ops.com/docs/devices/creating-ethernet-ip.md) - [Creating a Microsoft SQL Device](https://ai-ops.com/docs/devices/creating-mssql.md) - [Creating a REST Device](https://ai-ops.com/docs/devices/creating-rest.md) - [Creating a SOAP Device](https://ai-ops.com/docs/devices/creating-soap.md) 2. **Test the connection**: use the **Test Connection** button on the Configuration tab to verify Koios can reach the device before enabling it 3. **Add tags**: create the data points you want to read from or write to the device (see [Creating a Tag](https://ai-ops.com/docs/tags/creating-getting-started.md)) 4. **Enable the device**: flip the enable switch in the device header to start scanning ## Duplicating a Device If you need to create a device similar to an existing one, you can **duplicate** it instead of starting from scratch. Right-click a device in the list and select **Duplicate**, or use the duplicate action on a device's detail page. Duplicating copies: - All protocol-specific configuration (endpoints, credentials, timeouts) - Scan rate and heartbeat settings - Advanced settings (on-demand scanning, log level) It does **not** copy: - Tags: you'll need to add tags to the new device separately - The enabled state: the duplicate is always created disabled You'll be prompted to enter a new **name** and optionally update the **description** before confirming. --- Source: https://ai-ops.com/docs/devices/creating-opc-ua Section: Devices # Creating an OPC-UA Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **OPC-UA** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to communicate with your OPC-UA server. ## Configuration Fields ### Endpoint URL The OPC-UA endpoint address of the server you want to connect to. - **Required** - Format: `opc.tcp://hostname:port` or `opc.tcp://hostname:port/path` - Example: `opc.tcp://192.168.1.100:4840` Instead of typing the endpoint manually, you can use the **Browse** button to discover OPC-UA servers on your network. The browser lists available servers and their endpoints, and you can select one to auto-populate this field along with the security settings. See [Server Discovery](#server-discovery) below. ### Security Mode Controls whether messages between Koios and the OPC-UA server are signed, encrypted, or neither. | Mode | Description | |------|-------------| | **None** | No signing or encryption: fastest, but no message protection | | **Sign** | Messages are signed to detect tampering, but not encrypted | | **Sign & Encrypt** | Messages are both signed and encrypted: most secure | - **Default:** None - When set to **None**, the Security Policy is automatically disabled and locked to None. Change the Security Mode first if you need a specific policy. ### Security Policy The cryptographic algorithm used for signing and encryption. Only available when Security Mode is set to **Sign** or **Sign & Encrypt**. | Policy | Description | |--------|-------------| | **None** | No cryptographic policy (only available with Security Mode: None) | | **Basic128Rsa15** | Legacy policy: use only for older servers that don't support newer options | | **Basic256** | Moderate security: widely supported | | **Basic256Sha256** | Strongest option: recommended when available | - **Default:** None ### Authentication Type How Koios authenticates with the OPC-UA server. | Type | Description | |------|-------------| | **Anonymous** | No credentials required: the server allows unauthenticated access | | **Username/Password** | Authenticate with a username and password | - **Default:** Anonymous When set to **Username/Password**, two additional fields appear: - **Username**: the account to authenticate as - **Password**: the password for the account. Credentials are stored in the Koios database. Ensure your Koios instance is properly secured. ### Timeout (seconds) How long Koios waits for the OPC-UA server to respond before giving up. - **Default:** 30 seconds - **Minimum:** 1 second A higher timeout is useful for servers on slow or unreliable networks. For most connections, the default of 30 seconds provides sufficient margin for servers with large address spaces. ## Server Discovery The OPC-UA configuration includes a built-in **server browser** that helps you discover servers and endpoints on your network without typing URLs manually. ### How to Use the Browser 1. Click the **Browse** button on the Configuration tab 2. Enter the hostname and port (or a direct URL) of the OPC-UA server or Local Discovery Server (LDS) 3. Koios will discover all OPC-UA servers available at that address ### Step 1: Connect Enter the connection details to start discovery: - **Hostname + Port**: enter them separately and Koios builds the URL - **Direct URL**: enter a full `opc.tcp://...` URL if you know it The browser uses the device's configured timeout for discovery requests. ### Step 2: Select a Server The browser lists all OPC-UA servers found at the address. Each server shows: - **Application Name**: the human-readable name of the server application - **Application URI**: the unique identifier for the server - **Application Type**: the type of OPC-UA application (Server, Client, etc.) - **Discovery URLs**: endpoints where the server can be reached - **Product URI**: identifies the software product Select the server you want to connect to. ### Step 3: Select an Endpoint Each server exposes one or more endpoints with different security configurations. The browser shows: - **Endpoint URL**: the connection address - **Security Mode**: None, Sign, or Sign & Encrypt - **Security Policy**: the cryptographic algorithm - **Supported Authentication**: which token types the endpoint accepts (Anonymous, Username/Password) You can filter the endpoint list by security mode or security policy to find the configuration you need. When you select an endpoint, Koios automatically populates: - Endpoint URL - Security Mode - Security Policy - Authentication Type ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Enable the device**: flip the enable switch to start scanning. Koios will attempt to connect on its next scan cycle and report any errors on the device's detail page. You can also click **Test** to perform a one-time connection attempt without enabling. 3. **Add tags**: browse the server's node tree to find and add data points (see [Creating an OPC-UA Tag](https://ai-ops.com/docs/tags/creating-opc-ua.md)) If you're using a security mode other than **None**, the OPC-UA server must trust Koios's client certificate before it will accept a connection. The first connection attempt will fail until the certificate is trusted. See [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md) for details on establishing trust. --- Source: https://ai-ops.com/docs/devices/creating-modbus-tcp Section: Devices # Creating a Modbus TCP Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **Modbus TCP** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to communicate with your Modbus device. > [!NOTE] Register-based protocol > Modbus TCP uses a register-based addressing model. Each data point is identified by a register type (Coil, Discrete Input, Input Register, or Holding Register) and an address number. You'll configure these at the tag level. The device configuration only handles the connection itself. ## Configuration Fields ### Hostname The IP address or hostname of the Modbus TCP device. - **Required** - Example: `192.168.1.100` ### Port The TCP port the Modbus device is listening on. - **Default:** 502 (the standard Modbus TCP port) > [!TIP] Non-standard ports > Most Modbus devices use port 502. Some devices (especially gateways or simulators) may use a different port. Check the device documentation if you're having trouble connecting. ### Unit ID The Modbus unit identifier (also called slave address). This identifies which device on the network to communicate with. - **Default:** 1 - **Range:** 0–255 For a single device connected directly over Ethernet, the Unit ID is typically **1**. When connecting through a Modbus gateway that bridges to serial devices, the Unit ID identifies which downstream device to address. ### Timeout How long Koios waits for the device to respond before giving up, in seconds. - **Default:** 5 seconds - Specified in **seconds** For local network connections, a timeout of 1–3 seconds is usually sufficient. Increase it for devices behind gateways or on slow links. ### Show One-Based Addresses Controls how register addresses are displayed in the UI. - **Default:** Off (0-based addressing) - When **enabled**, register addresses are displayed starting from 1 instead of 0 > [!NOTE] Display only: doesn > This setting only affects how addresses appear in the Koios UI. The underlying Modbus communication always uses 0-based addressing per the protocol specification. Enable this if your device documentation uses 1-based register maps (common with some manufacturers). ### Max Registers Per Read The largest contiguous block of registers Koios will request in a single read. - **Default:** 125 - **Range:** 1–125 The Modbus specification caps a single read at 125 registers, but many devices accept fewer. Gateways that bridge to serial devices are the common case, since the serial side re-imposes its own frame limit. Published limits of 8, 16, 32, and 64 registers are all common. Lower this when reads fail even though each register is individually valid — for example, every tag on the device reporting a read failure while the same registers read correctly one at a time in the register browser. Lowering it splits one oversized request into several smaller ones; the values you get back are unchanged. > [!WARNING] Lower it only as far as the device needs > Each reduction increases the number of requests per scan. A device with 100 > contiguous registers needs one request at 125 but 25 requests at 4, which > lengthens every scan cycle. Start from the limit in the device's > documentation rather than guessing low. ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Test the connection**: click the `Test` button to verify Koios can reach the device 3. **Add tags**: define the registers you want to read or write (see [Creating a Modbus TCP Tag](https://ai-ops.com/docs/tags/creating-modbus-tcp.md)) 4. **Enable the device**: flip the enable switch to start scanning ## Register Scanning Koios provides tools to scan and interpret Modbus registers directly from the device, which is useful for discovering available data points and verifying correct byte/word order before creating tags. ### Scan Registers You can scan a range of registers to see their raw values. Specify: - **Register type**: Coil, Discrete Input, Input Register, or Holding Register - **Start address**: the first register to read - **Count**: how many consecutive registers to read ### Interpret Registers After scanning, you can interpret raw register values using different data types to find the correct interpretation. This helps you determine: - The correct **data type** (Int16, UInt16, Float32, etc.) - Whether **byte swap** or **word swap** is needed - The **bit position** for Boolean values within a register --- Source: https://ai-ops.com/docs/devices/creating-ethernet-ip Section: Devices # Creating an EtherNet/IP Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **EtherNet/IP** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to communicate with your EtherNet/IP device. Koios supports two types of EtherNet/IP devices: | Type | Use Case | |------|----------| | **Logix Controller** | Allen-Bradley ControlLogix and CompactLogix controllers. Tags are accessed by name. | | **Generic CIP** | Any CIP-compliant device (variable frequency drives, I/O modules, non-Allen-Bradley equipment). Data is accessed by assembly instance and byte offset. | ## Common Configuration Fields These fields apply to both Logix and Generic CIP devices. ### Hostname The IP address or hostname of the EtherNet/IP device. - **Required** - Example: `192.168.1.100` ### Device Type Select the type of EtherNet/IP device you're connecting to. This determines which additional fields are shown and how Koios communicates with the device. | Type | Description | |------|-------------| | **Logix Controller** | Allen-Bradley ControlLogix or CompactLogix controllers | | **Generic CIP** | Any CIP-compliant EtherNet/IP device | - **Required** ### Timeout (seconds) How long Koios waits for the device to respond before giving up. - **Default:** 3 seconds - **Minimum:** 1 second - **Maximum:** 300 seconds (5 minutes) EtherNet/IP connections are typically fast on local networks. The default of 3 seconds provides a comfortable margin. Increase it only if the device is behind a slow network link or VPN. ## Logix Controller Configuration These fields appear when the device type is set to **Logix Controller**. ### Controller Slot The slot number of the controller in the chassis. - **Default:** 0 - **Minimum:** 0 - Typically 0-16, depending on chassis size > [!TIP] Finding the controller slot > In most configurations, the controller is in slot **0** (the leftmost slot in the chassis). If your controller is in a different slot, check the chassis configuration in RSLogix 5000 / Studio 5000 or look at the physical slot position. ## Generic CIP Configuration These fields appear when the device type is set to **Generic CIP**. ### EDS File (Optional) Upload an **Electronic Data Sheet (EDS)** file for the device. EDS files describe a device's assemblies and data fields in a standardized format defined by ODVA. When an EDS file is uploaded, the tag browser can display a structured view of the device's assemblies and fields, making it easy to select data points when creating tags. Without an EDS file, you can still create tags manually by entering the assembly instance, byte offset, and data type. > [!TIP] Where to find EDS files > EDS files are typically available from the device manufacturer's website or included with configuration software. They have a `.eds` file extension. ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Test the connection**: click the `Test` button to verify Koios can reach the device 3. **Add tags**: browse the device to find and add data points (see [Creating an EtherNet/IP Tag](https://ai-ops.com/docs/tags/creating-ethernet-ip.md)) 4. **Enable the device**: flip the enable switch to start scanning ## Browsing Device Data Points Both EtherNet/IP device types include a **device browser** for discovering available data points. The browser experience differs based on the device type. ### Logix Tag Browser For Logix controllers, the tag browser reads the controller's tag database directly. Instead of manually entering tag names, you can explore the controller's tags, view their types and values, and select the ones you need. The browser supports: - **Hierarchical navigation**: drill into programs, UDTs (User-Defined Types), structures, and arrays - **Scope selection**: toggle between controller-scoped and program-scoped tags - **Search and filter**: find tags by name or filter by type (Structure, Array, Atomic, Array Item) - **Tag details**: view data type, dimensions, path, and metadata for any tag - **One-click selection**: select a tag to auto-populate the tag configuration form ### Generic CIP EDS Browser For Generic CIP devices with an EDS file uploaded, the browser parses the EDS file and displays a structured view of the device's data layout. The browser shows: - **Assemblies**: each assembly instance with its name and total size in bytes - **Fields**: individual data fields within each assembly, including name, byte offset, data type, and size - **Multi-select**: select multiple fields to create several tags at once - **Field details**: view the exact byte offset, data type, and struct format for each field > [!NOTE] EDS browsing works offline > Unlike the Logix tag browser, the Generic CIP browser reads from the uploaded EDS file. It does not connect to the device. The device does not need to be powered on to browse its EDS. See [Creating an EtherNet/IP Tag](https://ai-ops.com/docs/tags/creating-ethernet-ip.md) for details on configuring tags for both device types. --- Source: https://ai-ops.com/docs/devices/creating-mssql Section: Devices # Creating a Microsoft SQL Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **Microsoft SQL** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to query your SQL Server database. > [!NOTE] SQL devices are for reading data > Microsoft SQL devices allow Koios to query data from SQL Server databases at a regular scan interval. Each tag on an SQL device executes a SQL query and stores the result as a live value. This is useful for pulling data from business systems, historians, or other databases into the Koios platform. ## Configuration Fields ### Database Driver The ODBC driver used to connect to SQL Server. Select the driver that matches what's installed on the Koios server. | Driver | Description | |--------|-------------| | **ODBC Driver 18 for SQL Server** | Latest driver with improved security defaults | - **Required** > [!WARNING] Driver must be installed on the server > The selected driver must be installed on the machine (or container) running the Koios datacollector service. If you're unsure which drivers are available, check with your system administrator. ### Hostname / Server The hostname or IP address of the SQL Server instance. - **Required** - Example: `192.168.1.100` or `sqlserver.local` ### Database Name The name of the database to connect to on the SQL Server instance. - **Required** - Example: `mydb` ### Username The SQL Server login used to authenticate. - **Required** ### Password The password for the SQL Server login. - **Required** ### Timeout (seconds) How long Koios waits for the database to respond before giving up. - **Default:** 10 seconds - **Minimum:** 1 second - **Maximum:** 300 seconds (5 minutes) Database queries may take longer than typical device reads, especially for complex queries or large datasets. The default of 10 seconds is appropriate for most use cases. ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Add tags**: each tag defines a SQL query to execute (see [Creating a Microsoft SQL Tag](https://ai-ops.com/docs/tags/creating-mssql.md)) 3. **Enable the device**: flip the enable switch to start querying > [!TIP] Scan rate for SQL devices > SQL queries consume database resources on every scan cycle. Consider using a longer scan rate (30–300 seconds) for SQL devices unless you need near-real-time data. You can configure the scan rate on the device's general configuration section or when [creating the device](https://ai-ops.com/docs/devices/creating-getting-started.md). --- Source: https://ai-ops.com/docs/devices/creating-rest Section: Devices # Creating a REST Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **REST** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to communicate with the REST API. > [!NOTE] Built for CAREL BOSS > The REST protocol in Koios is designed for connecting to **CAREL BOSS** (Building Operation System Server) devices. BOSS exposes a REST API for reading and writing HVAC variables such as alarms, analog values, digital states, and integer registers. ## Configuration Fields ### REST Type The type of REST service you're connecting to. | Type | Description | |------|-------------| | **Boss** | CAREL BOSS building management system | - **Required** ### URL The base URL of the REST API endpoint. - **Required** - Example: `https://192.168.1.100/api/v1` ### Authentication Type How Koios authenticates with the REST API. | Type | Description | |------|-------------| | **None** | No authentication required | | **Username/Password** | Authenticate with credentials | - **Default:** Username/Password When set to **Username/Password**, two additional fields appear: - **Username**: the account to authenticate as *(required)* - **Password**: the password for the account *(required)* ### Verify SSL Whether Koios verifies the server's SSL certificate when connecting over HTTPS. - **Default:** Disabled (unchecked) > [!WARNING] Disabling SSL verification > Only disable SSL verification for devices using self-signed certificates on trusted networks. Disabling it on untrusted networks exposes the connection to man-in-the-middle attacks. ### Timeout (seconds) How long Koios waits for the API to respond before giving up. - **Default:** 5 seconds - **Minimum:** 1 second - **Maximum:** 300 seconds (5 minutes) ### Max Retries The maximum number of times Koios will retry a failed request before reporting an error. - **Default:** 5 - **Minimum:** 1 - **Maximum:** 10 ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Test the connection**: click the `Test` button to verify Koios can reach the BOSS API 3. **Add tags**: define the BOSS variables you want to read or write (see [Creating a REST Tag](https://ai-ops.com/docs/tags/creating-rest.md)) 4. **Enable the device**: flip the enable switch to start scanning --- Source: https://ai-ops.com/docs/devices/creating-soap Section: Devices # Creating a SOAP Device After [creating a device](https://ai-ops.com/docs/devices/creating-getting-started.md) with the **SOAP** protocol, you'll land on its **Configuration** tab. This is where you provide the connection details Koios needs to communicate with a SOAP web service. > [!NOTE] Built for RDM controllers > The SOAP protocol in Koios is designed for connecting to **RDM** (Resource Data Manager) controllers. RDM devices expose a SOAP-based API for reading and writing HVAC parameters. ## Configuration Fields ### SOAP Type The type of SOAP service you're connecting to. This determines which additional configuration fields are shown. | Type | Description | |------|-------------| | **RDM (Resource Data Manager)** | RDM controller with SOAP API | - **Required** ### Hostname The URL of the SOAP service endpoint. - **Required** - Example: `http://192.168.1.100:8080/soap` ### Timeout (seconds) How long Koios waits for the SOAP service to respond before giving up. - **Default:** 5 seconds - **Minimum:** 1 second - **Maximum:** 300 seconds (5 minutes) ### RDM Username The username for authenticating with the RDM controller. This field appears when the SOAP type is set to **RDM**. - **Required** (when type is RDM) ### RDM Password The password for authenticating with the RDM controller. This field appears when the SOAP type is set to **RDM**. - **Required** (when type is RDM) ### RDM Web Authentication Enable this option if the RDM controller requires web-based authentication in addition to the SOAP credentials. - **Default:** Disabled (unchecked) - This field appears when the SOAP type is set to **RDM** ## After Configuration Once you've filled in the connection settings: 1. **Save** the configuration 2. **Test the connection**: click the `Test` button to verify Koios can reach the SOAP service 3. **Add tags**: define the RDM device and parameter for each data point (see [Creating a SOAP Tag](https://ai-ops.com/docs/tags/creating-soap.md)) 4. **Enable the device**: flip the enable switch to start scanning --- Source: https://ai-ops.com/docs/devices/importing-exporting Section: Devices # Importing & Exporting Devices You can import and export device configurations as CSV files. This is useful for bulk-creating devices across protocols, migrating configurations between Koios instances, or editing device settings in a spreadsheet. ## Exporting Devices ### How to Export There are two ways to export device configurations: 1. **From the device table**: select one or more devices using the checkboxes, then click **Export config** in the bulk actions menu. Only the selected devices are exported. 2. **Export all**: if no devices are selected, the export includes every device in the system. The export downloads a file named `devices.csv` containing one row per device. ### What's Included The CSV contains all configuration fields for each device: general settings and protocol-specific fields. Every column is included regardless of protocol, so columns that don't apply to a particular device's protocol will be empty. > [!NOTE] Config only, not live data > The export contains static configuration from the database. Live status, error states, and connection information are not included. Those come from the live data cache and change every scan cycle. ### CSV Columns The export includes these columns: **Core fields:** | Column | Description | |--------|-------------| | `id` | Database ID (primary key) | | `slug` | UUID identifier | | `name` | Device name (unique) | | `description` | Optional description | | `enabled` | Whether the device is actively scanning | | `protocol` | Protocol ID (foreign key) | | `scan_rate` | Polling interval in seconds (0.1–3600) | | `heartbeat_scans` | Number of scans before heartbeat toggle | | `on_demand_freshness` | Max age of tag data in seconds for on-demand reads | | `on_demand_batch_window` | Time window for batching on-demand requests | | `parent` | Folder ID (if organized in folders) | **Protocol-specific fields:** | Columns | Protocol | |---------|----------| | `opcua_endpoint`, `opcua_security_mode`, `opcua_security_policy`, `opcua_token_type`, `opcua_username`, `opcua_password`, `opcua_timeout`, `opcua_certificate` | OPC-UA | | `modbus_hostname`, `modbus_port`, `modbus_unit_id`, `modbus_timeout`, `modbus_show_one_based` | Modbus TCP | | `ethernet_ip_hostname`, `ethernet_ip_type`, `ethernet_ip_controller_slot`, `ethernet_ip_timeout` | EtherNet/IP (all types) | | `soap_hostname`, `soap_type`, `soap_timeout`, `soap_rdm_username`, `soap_rdm_password`, `soap_rdm_web_authentication` | SOAP (RDM) | | `rest_url`, `rest_type`, `rest_timeout`, `rest_auth_type`, `rest_verify_ssl`, `rest_username`, `rest_password`, `rest_max_retries` | REST (BOSS) | | `sql_driver`, `sql_hostname`, `sql_database_name`, `sql_username`, `sql_password`, `sql_timeout` | Microsoft SQL | **Audit fields (read-only):** | Column | Description | |--------|-------------| | `created_at` | Creation timestamp | | `updated_at` | Last modification timestamp | | `last_modified_by` | User who last modified the device | --- ## Importing Devices ### How to Import 1. Navigate to the **Devices** page 2. Click the **Import** button in the table toolbar 3. Select a CSV file from your computer 4. Review the preview to verify what will change 5. Click **Confirm Import** to apply the changes ### CSV Format The import expects a CSV file with column headers matching the export format. You don't need to include every column, only the fields you want to set. At minimum, new devices require a `name` and `protocol`. > [!TIP] Start from an export > The easiest way to build an import file is to export your existing devices, edit the CSV in a spreadsheet, and re-import it. The column headers will already be correct. **How the import determines what to do with each row:** | Condition | Action | |-----------|--------| | `id` column is empty | **Create** a new device | | `id` matches an existing device and fields differ | **Update** the existing device | | `id` matches an existing device and nothing changed | **Skip** the row | | Row has validation errors | **Error**: row is not imported | ### Example: Creating New OPC-UA Devices To create new devices, leave the `id` column empty. Provide at least a `name` and `protocol` (by ID): ```text id,name,protocol,enabled,scan_rate,opcua_endpoint,opcua_security_mode,opcua_token_type,opcua_timeout ,AHU-1 Controller,1,True,1.0,opc.tcp://192.168.1.10:4840,None,0,5 ,AHU-2 Controller,1,True,1.0,opc.tcp://192.168.1.11:4840,None,0,5 ,Chiller Plant,1,True,2.0,opc.tcp://192.168.1.20:4840,None,0,10 ``` ### Example: Creating Modbus TCP Devices ```text id,name,protocol,enabled,scan_rate,modbus_hostname,modbus_port,modbus_unit_id,modbus_timeout ,Power Meter 1,2,True,1.0,192.168.1.50,502,1,5 ,Power Meter 2,2,True,1.0,192.168.1.51,502,1,5 ,VFD Controller,2,True,0.5,192.168.1.60,502,2,5 ``` ### Example: Updating Existing Devices To update existing devices, include the `id` column with the device's database ID. Only the fields you include will be checked for changes: ```text id,scan_rate,enabled 12,2.0,True 13,2.0,True 14,5.0,False ``` ### Preview Step After selecting a file, Koios performs a **dry run**. It processes the CSV without saving anything and shows you exactly what will happen: - **Summary**: counts of devices that will be created, updated, skipped, or rejected - **Row details**: click any row to see a field-by-field diff of what will change - **Diff table**: click **Show Diff Table** for a full-width view of all changes across all rows, with changed fields highlighted > [!WARNING] Errors block the import > If any row has a validation error, the entire import is blocked. Fix the errors in your CSV and re-upload. Common errors include duplicate names, missing required fields, and referencing protocols that don't exist. ### Validation Rules The import validates each row against the same rules as the create/update forms: | Field | Validation | |-------|------------| | `name` | Required, max 128 characters, must be unique | | `description` | Max 256 characters | | `protocol` | Must reference an existing protocol ID | | `scan_rate` | Number between 0.1 and 3600 | | `enabled` | Boolean value | | Protocol fields | Validated against protocol-specific constraints | **Boolean fields** accept: `True`/`False`, `true`/`false`, `1`/`0`, `yes`/`no`. **Foreign key fields** (`protocol`, `parent`, `opcua_certificate`) expect integer IDs. ### After Import Once you confirm the import: - Devices are created or updated in a single transaction. If anything fails, all changes are rolled back - An audit event is recorded (e.g. "Imported 10 devices") with your username - The device table automatically refreshes to show the updated list - Imported devices begin connecting on the next scan cycle if they are enabled > [!NOTE] Service pickup delay > After import, the datacollector detects new or changed devices within a few seconds. You don't need to restart any services. --- ## Tips - **Bulk-create devices for a new site**: create one device per protocol, export it, duplicate the rows in your spreadsheet, change the names and addresses, clear the `id` column, and import. - **Move devices between Koios instances**: export from one instance, clear the `id` and `slug` columns, verify the `protocol` IDs match the target instance, and import on the target. - **Audit trail**: every import creates an event visible on the **Events** page, grouped under a single parent event so you can see what was imported in one action. - **Read-only columns**: `id`, `slug`, `created_at`, `updated_at`, and `last_modified_by` are ignored on create. You can leave them in the CSV (useful when round-tripping an export) but they won't overwrite system-managed values. - **Sensitive fields**: credentials (`opcua_password`, `soap_rdm_password`, `rest_password`, `sql_password`) are included in exports. Handle exported CSV files carefully if your devices use authenticated connections. --- Source: https://ai-ops.com/docs/devices/on-demand-scanning Section: Devices # On-Demand Scanning On-demand scanning allows AI models to trigger an immediate device read or write outside the normal scan cycle. The device side controls **when cached data is fresh enough to reuse** and **how long to wait before executing** (to batch concurrent requests). > [!NOTE] Two sides of on-demand > This page covers **device-side** settings. For the model-side settings and full on-demand cycle, see [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md). ## Settings Reference Found on the device's **Configuration** tab under **Advanced Configuration**. | Setting | Description | Default | Range | |---------|-------------|---------|-------| | **On-Demand Freshness** | Max age (seconds) of cached data before a fresh read is required | 1s | 0–3,600s | | **On-Demand Batch Window** | Time (seconds) to wait before executing, batching concurrent requests | 0.1s | 0–10s | --- ## On-Demand Freshness When an on-demand read is requested, Koios checks how old the cached data is. If newer than the freshness threshold, the cached data is returned immediately — no device read needed. ```text Freshness = 5s Cache age: 3s → Return cached (fresh enough) Cache age: 8s → Read device (stale) ``` **Setting to 0** means every request triggers a fresh read. This guarantees the freshest data but increases device I/O. > [!TIP] Freshness vs scan rate > If your device has a fast scan rate (e.g. 1s) and freshness is set to 3s, most on-demand requests will be served from cache without extra reads. --- ## On-Demand Batch Window When multiple models request reads from the same device at nearly the same time, the batch window groups them into a **single device read**. ```text Batch window = 0.5s t=0.0s Model A requests read ─┐ t=0.1s Model B requests read ├─→ Single read at t=0.5s t=0.3s Model C requests read ─┘ ``` Increasing the batch window improves efficiency but **adds latency** to every on-demand cycle. The model must wait for the window to close before the device is polled. > [!WARNING] Batch window adds to model timeout > A 2s batch window means the model waits up to 2s before the device is even read. Make sure the model's on-demand timeout accommodates: batch window + device read time. If a binding's on-demand read is timing out, see [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) to diagnose it. **Setting to 0** means every request is executed immediately with no batching. --- ## How It Fits Together ```text Model requests read → Freshness check ├─ Fresh → Return cached data └─ Stale → Batch window → Read device → Return fresh data ↓ Model infers ↓ Model writes ``` Total on-demand latency: **(batch window if not cached) + device read time**. This must be less than the model's on-demand timeout. --- ## Configuration Guidelines | Scenario | Freshness | Batch Window | |----------|-----------|--------------| | Single model, fast control loop | 0s | 0s | | Single model, moderate polling | 3–5s | 0s | | Multiple models, same scan rate | 3–5s | 0.5s | | Multiple models, high device I/O cost | 5–10s | 1–2s | > [!TIP] Start simple > The defaults, 1s freshness and 0.1s batch window, suit most cases. Drop both to 0 for always-fresh, un-batched reads, or raise them later to reduce device I/O. --- Source: https://ai-ops.com/docs/devices/device-parameters Section: Devices # Device Parameters Every device in Koios has a set of parameters that describe its current state, configuration, and protocol-specific connection settings. You can view all parameters on a device's **Parameters** tab, organized into three sections: **Live Data**, **Configuration**, and **Protocol**. ## Live Data Live data parameters are read-only values that update in real time. They reflect the device's current operational state and are useful for monitoring and troubleshooting. | Parameter | Description | |-----------|-------------| | **Status** | The device's current connection state: Running, Stopped, or Failed | | **Error Code** | A numeric code identifying the type of error (see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md)) | | **Error Message** | A short description of the current error, if any | | **Error Detail** | Additional diagnostic information about the error | | **Heartbeat** | A toggling value that increments each scan cycle. External systems can monitor this to confirm Koios is actively scanning | | **Missed Scans (1h)** | The number of times a scan exceeded the configured scan rate in the last hour. Useful for assessing current device health | | **Scan Progress** | The percentage complete for the current scan cycle | | **Last Scan** | The timestamp of the most recent completed scan | > [!TIP] Mapping live data to tags > Any live data parameter can be **mapped** to a tag, allowing you to record its value in the time-series database or use it in expressions and models. Click the map icon next to a parameter to create a mapping. ## Configuration Configuration parameters control how the device behaves. These are set when you create or edit a device. ### Core Settings | Parameter | Description | Default | |-----------|-------------|---------| | **Name** | A unique identifier for the device | — | | **Description** | An optional note describing the device's purpose | — | | **Enabled** | Whether the data collector should actively scan this device | Off | ### Scanning | Parameter | Description | Default | Range | |-----------|-------------|---------|-------| | **Scan Rate** | How often Koios polls the device for new data, in seconds | 1s | 0.1–3,600s | | **On-Demand Freshness** | Maximum age (seconds) of cached tag data before an on-demand request triggers a fresh device read. Lower values ensure fresher data but increase device I/O | 1s | 0–3,600s | | **On-Demand Batch Window** | Time window (seconds) to batch concurrent on-demand requests into a single device read. Reduces I/O when multiple models share a device | 0.1s | 0–10s | | **Heartbeat Scans** | The number of scans the heartbeat counter waits before toggling | 1 | — | > [!NOTE] Scan rate guidance > A scan rate of **1 second** works well for most real-time monitoring. Increase it for devices on slow networks or when polling frequency isn't critical. Decrease it (down to 0.1s) for high-speed control loops, but keep in mind that very fast scan rates increase network and CPU load. For detailed explanations of the on-demand settings (freshness, batch window) and how they affect AI model inference latency, see [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md#on-demand-freshness). ### Diagnostics | Parameter | Description | Default | |-----------|-------------|---------| | **Log Level** | Controls the verbosity of per-device diagnostic logs (Debug, Info, Warning, Error). A runtime override set on the **Logs** tab, not a saved configuration field | Info | | **Tag Count** | The total number of tags assigned to this device (read-only) | — | > [!NOTE] Log Level is a runtime override > Log Level is stored in the live cache, not saved with the device configuration, so it won't appear in exports or config diffs. Setting it to **Debug** applies a temporary override that auto-reverts to the default level after a timer expires. ### Metadata | Parameter | Description | |-----------|-------------| | **ID** | The device's internal database identifier | | **UUID** | A unique identifier used in API calls and exports | | **Created At** | When the device was first created | | **Updated At** | When the device configuration was last modified | --- ## Protocol Parameters In addition to the shared parameters above, each device has protocol-specific settings that define how Koios connects to the external system. These parameters only appear for devices using the corresponding protocol. ### OPC-UA | Parameter | Description | Default | |-----------|-------------|---------| | **Endpoint** | The OPC-UA server address (e.g. `opc.tcp://192.168.1.100:4840`) | — | | **Security Mode** | Message protection level: None, Sign, or Sign & Encrypt | None | | **Security Policy** | Cryptographic algorithm: None, Basic128Rsa15, Basic256, or Basic256Sha256 | None | | **Token Type** | Authentication method: Anonymous or Username/Password | Anonymous | | **Username** | The account to authenticate as (only shown for Username/Password) | — | | **Timeout** | How long to wait for the server to respond, in seconds | 30s | For full setup instructions, see [Creating an OPC-UA Device](https://ai-ops.com/docs/devices/creating-opc-ua.md). ### Modbus TCP | Parameter | Description | Default | |-----------|-------------|---------| | **Hostname** | The IP address or hostname of the Modbus server | — | | **Port** | The network port to connect on | 502 | | **Unit ID** | The Modbus slave ID (0–255) | 1 | | **Timeout** | How long to wait for a response, in seconds | 5s | | **Show One-Based** | When enabled, register numbers are displayed starting from 1 instead of 0 | Off | | **Max Registers Per Read** | The largest contiguous block requested in a single read | 125 | For full setup instructions, see [Creating a Modbus TCP Device](https://ai-ops.com/docs/devices/creating-modbus-tcp.md). ### EtherNet/IP **Common fields (both types):** | Parameter | Description | Default | |-----------|-------------|---------| | **Hostname** | The IP address or hostname of the device | — | | **Device Type** | Logix Controller or Generic CIP | Logix Controller | | **Timeout** | How long to wait for a response, in seconds | 3s | **Logix Controller additional fields:** | Parameter | Description | Default | |-----------|-------------|---------| | **Controller Slot** | The slot number where the controller is located in the rack | 0 | **Generic CIP additional fields:** | Parameter | Description | Default | |-----------|-------------|---------| | **EDS File** | Electronic Data Sheet file for structured tag browsing (optional) | — | For full setup instructions, see [Creating an EtherNet/IP Device](https://ai-ops.com/docs/devices/creating-ethernet-ip.md). ### SOAP (RDM) | Parameter | Description | Default | |-----------|-------------|---------| | **Hostname** | The IP address or hostname of the SOAP device | — | | **Type** | The device type. Currently supports RDM (Resource Data Manager) | RDM | | **Timeout** | How long to wait for a response, in seconds | 5s | | **RDM Username** | The RDM account username. Must have "Installer" access level to write values | — | | **RDM Web Authentication** | Whether the RDM has web authentication enabled. When on, reads also require credentials | Off | For full setup instructions, see [Creating a SOAP Device](https://ai-ops.com/docs/devices/creating-soap.md). ### REST (CAREL BOSS) | Parameter | Description | Default | |-----------|-------------|---------| | **URL** | The base URL of the REST API, including scheme (e.g. `https://192.168.1.50`) | — | | **Type** | The device type. Currently supports CAREL BOSS | BOSS | | **Auth Type** | The authentication method: Username/Password | Username/Password | | **Username** | The account to authenticate as | — | | **Verify SSL** | Whether to verify the server's SSL certificate | Off | | **Timeout** | How long to wait for a response, in seconds | 5s | | **Max Retries** | Number of retry attempts for failed requests (some devices need multiple retries) | 5 | For full setup instructions, see [Creating a REST Device](https://ai-ops.com/docs/devices/creating-rest.md). ### Microsoft SQL | Parameter | Description | Default | |-----------|-------------|---------| | **Driver** | The ODBC driver used to connect | ODBC Driver 18 for SQL Server | | **Hostname** | The SQL Server hostname or IP address | — | | **Database Name** | The database to connect to | — | | **Username** | The database account username | — | | **Timeout** | How long to wait for queries to complete, in seconds | 10s | For full setup instructions, see [Creating a Microsoft SQL Device](https://ai-ops.com/docs/devices/creating-mssql.md). --- ## Parameter Mappings Any device parameter (live or configuration) can be **mapped** to a tag. This lets you: - **Record** parameter values (like status or error codes) into the time-series database for historical analysis - **Use** parameter values in expressions or as inputs to AI models - **Monitor** device health trends over time (e.g. tracking overscan frequency) To create a mapping, click the map icon next to the parameter in the Parameters tab. You'll be prompted to select or create a tag to receive the parameter's value. --- Source: https://ai-ops.com/docs/devices/troubleshooting Section: Devices # Troubleshooting a Device > [!NOTE] This guide has moved > Device troubleshooting now lives in the **Troubleshoot** section. To diagnose a device that won't connect, see [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). To decode a device error code or status, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). Not sure where to start? Begin at [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md). --- Source: https://ai-ops.com/docs/devices/device-sets Section: Devices # Device Sets A **device set** is a priority-ordered group of devices that all share the same protocol and expose the same data. The set provides redundancy: at any moment one member is the **active device**, and Koios reads and writes through it. If the active device stops running, Koios promotes the next healthy member so data collection continues without manual intervention. Device sets are useful when a critical data source has a backup: two OPC-UA servers mirroring the same tags, a primary and standby PLC, or paired gateways on separate network paths. > [!NOTE] One protocol per set > Every device in a set must use the same protocol. When you create a set you choose its protocol, and only protocols that support redundancy are offered. A tag can then read from the set only if the tag's protocol matches the set's. ## Creating a Device Set From the **Devices** area, open **Device Sets**, then select **Add Device Set**. Provide: - **Name**: a unique label for the set. - **Description**: optional context. - **Protocol**: the protocol shared by every member. The list is limited to protocols that support redundancy. The set is created empty. Add devices to it from the set's detail page. ## Adding and Ordering Devices Open the set and use the **Failover Priority** card: 1. Select **Add Device**. The picker lists devices on the set's protocol that are not already members. 2. Add one or more devices. Each becomes a member with a **priority**. Priority is an integer where **1 is the highest**. When Koios needs to choose an active device, it tries members in ascending priority order and picks the first one that is running. Use the up and down arrows on each row to reorder members, which swaps their priority numbers. ## The Active Device The set tracks which member is currently active, that member's priority, and its live status. All redundant tags in the set read and write through the active device. Koios manages failover automatically: - The data collector watches the active device's health. - When the active device is no longer running (it failed, was disabled, or lost its connection), Koios searches the set for the running member with the highest priority and promotes it to active. - Every redundant tag in the set is reassigned to the new active device, so those tags keep updating. - A failover event is recorded noting the previous and new active device. Failover runs reactively the moment a scan fails, backed by a periodic safety-net check. If no member is running, the set keeps its current active device and reports a stopped or failed status until a member recovers. ## Swapping the Active Device Manually To force a specific member active, select the check icon next to it in the Failover Priority card and confirm. All tag activity swaps to that device immediately. Automatic failover still applies afterward. If you make a stopped device active and another member is running, the next health check moves the active device back to the running member. Manual selection holds only while the chosen device stays running. ## Using a Device Set on a Tag A tag opts into a set through its **General** configuration: 1. Open a device tag and turn on **Use Redundant Device**. 2. The single-device selector is replaced by a **Device Set** selector listing sets on the tag's protocol. 3. Choose the set and save. The tag now reads and writes through whichever device is active in the set instead of one fixed device. Only device tags support redundancy. Expression tags and in-memory tags do not connect to a device and cannot use a set. ## Cross-References The set's detail page shows what depends on it: - **Redundant tags** that read through the set. - **Devices** that are members. - **Mapped tags** whose output is bound to the set's active-device fields (active device priority and status). Review cross-references before restructuring or deleting a set so you know what is affected. ## Deleting a Device Set Delete a set from the action menu on its detail page. > [!WARNING] Deleting a set affects its tags > Deleting a device set does not delete the member devices; it only removes their membership. Redundant tags that read from the set are unlinked from it and stop collecting until you point them at another device or set. Tag mappings bound to the set's active-device fields are deleted. Reassign dependent tags before deleting if you want them to keep collecting. ## What's Next - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md): diagnose why a member device failed and triggered a failover. - [Tag Introduction](https://ai-ops.com/docs/tags/introduction.md): how tags read from devices, including redundant device tags. --- Source: https://ai-ops.com/docs/tags/introduction Section: Tags # Tags A **tag** in Koios represents an individual data point: a temperature reading, a motor speed, a pressure setpoint, a database column value, or a calculated result. Tags are where real data enters and leaves the platform: AI models read from input tags and write predictions to output tags, trends chart tag values over time, and events fire when tag states change. Tags can get their value from three different sources: a connected device, a computed expression, or an in-memory write from a service. See [Tag Source Types](#tag-source-types) below for details. ## Input vs Output Every tag has a **usage** that determines how Koios interacts with it: | Usage | Direction | Description | |-------|-----------|-------------| | **Input** | Read from device | Koios reads this tag's value from the device on each scan cycle. This is the default for most tags: sensor readings, status registers, database values. | | **Output** | Read and write | Koios can write values _back_ to the device through this tag. Output tags receive values from AI models, mappings, or components, and push them to the device on the next scan. | > [!NOTE] Output tags still read > Output tags read their current value from the device on every scan, just like input tags. The difference is they can also _receive_ a value to write back. This means you can see both the output value (what Koios wants to write) and the current value (what the device is actually reporting). > [!TIP] Usage is fixed for expression and in-memory tags > Expression tags are always **read-only**: they compute their value from a formula and have no device to write to. In-memory tags are always **read/write**: they receive output values from services (AI models, mappings, components) which write through them. Only device tags let you choose between input and output. ## Tag Lifecycle Tags follow this lifecycle: 1. **Create**: add a tag and configure its settings (device and protocol fields for device tags, an expression for expression tags, or general settings for in-memory tags) 2. **Enable**: activate the tag so it begins collecting or computing values 3. **Live**: the tag's value updates on each scan or evaluation, is recorded to the time-series database, and is available to models, trends, and the rest of the platform 4. **Stopped / Failed**: a tag stops when disabled (or when its parent device stops, for device tags). It enters a failed state if it encounters an error. > [!TIP] Device tags follow their device > A device tag can only collect data when its parent device is enabled and running. If the device is stopped, all of its tags stop too, regardless of each tag's own enabled setting. Expression and in-memory tags have no parent device, so they operate independently. ## Tag Status Like devices, every tag has a real-time status: | Status | Meaning | |--------|---------| | **Running** | The tag is actively producing values: being scanned from a device, evaluated from an expression, or relayed from a service | | **Stopped** | The tag is disabled (or its parent device is disabled, for device tags) | | **Failed** | An error occurred. Check the error code and message for details | When a device tag fails, the parent device may continue scanning its other tags normally. Tag errors are isolated: one bad tag doesn't bring down the whole device. ## What You See on a Tag ### Tag List The tag list table shows all tags across the platform. Key columns include: - **Status**: colored icon showing running, stopped, or failed - **Name**: the tag's unique name - **Source**: device, expression, or in-memory - **Device**: the parent device (device tags only) - **Value**: the current live value - **Units**: engineering units (°C, PSI, RPM, etc.) - **Usage**: input or output icon You can filter by device, protocol, or search by name. Tags can be enabled, disabled, duplicated, or deleted in bulk. ### Tag Detail Clicking a tag opens its detail page with four tabs: - **Overview**: live status, current value with sparkline chart, device info, and recent events - **Configuration**: all editable settings (general, protocol-specific, and advanced) - **Parameters**: read-only table of every tag field, organized into live data, config, and protocol sections - **Cross References**: shows where this tag is used (AI models, mappings, components, etc.) ## Configuration ### General Settings | Setting | Description | Default | |---------|-------------|---------| | **Name** | Unique identifier for the tag | — | | **Description** | Optional note about the tag's purpose | — | | **Enabled** | Whether the tag is actively collecting or computing values | Off | | **Usage** | Input (read-only) or Output (read/write) | Input | | **Units** | Engineering units displayed alongside the value (e.g. °C, PSI) | — | | **Range Min / Max** | Expected value range, used for normalization in AI models and display scaling | 0–100 | | **Use Redundant Device** | For device tags: read from a device set (with automatic failover) instead of a single device | Off | ### Protocol-Specific Settings Device tags have additional configuration that depends on their protocol. These settings tell Koios _where_ to find the data point within the device: | Protocol | Key Settings | |----------|-------------| | **OPC-UA** | Namespace, node identifier, identifier type, data type | | **Modbus TCP** | Register address, register type, data type, byte/word swap | | **EtherNet/IP (Logix)** | Logix tag name, tag type | | **EtherNet/IP (Generic CIP)** | Assembly instance, byte offset, data type, bit number | | **SOAP (RDM)** | RDM device address, RDM parameter | | **REST (BOSS)** | BOSS device address, variable code, variable type | | **Microsoft SQL** | SQL query | See the protocol-specific tag creation guides for details on each. ### Advanced Settings | Setting | Description | Default | |---------|-------------|---------| | **Decimal Places** | How many decimal places to show for numeric values (0–3) | 1 | | **Value Mapping** | Maps raw device values to numeric outputs using ordered match rules | Off | | **Write Always** | For output tags: retry the last output value on every scan, even if no new value has been received | Off | ### History Compression By default, every tag uses the global compression settings configured on the [Data Retention](https://ai-ops.com/docs/system/retention.md#history-compression) page. Global compression uses **Swinging Door Trending (SDT)** to discard values that don't meaningfully change the trend, reducing storage consumption while preserving the shape of the data. If a specific tag needs different compression behavior, the **History Compression** section on the Configuration tab provides an **Override global compression settings** toggle. When enabled, three tag-specific settings appear: | Setting | Description | Default | |---------|-------------|---------| | **Compression Enabled** | Whether to compress this tag's history | On | | **Compression Deviation** | Maximum deviation from the trend line, as a percentage of the tag's range | 0.1% | | **Maximum Time Between Samples** | Force a sample after this many seconds regardless of compression | 60s | When the override is off, the tag follows whatever the global settings are. A link on the Configuration tab takes you directly to the Retention page to view or change them. > [!TIP] When to use per-tag overrides > Most tags work well with the global defaults. Use per-tag overrides when a tag has specific fidelity requirements. For example, a critical control signal that must record every change, or a slow-moving temperature sensor that can tolerate aggressive compression. Overrides are fully independent: changes to the global settings have no effect on overridden tags. > [!WARNING] Range affects compression > SDT calculates the tolerance band as a percentage of the tag's **Range Min / Max**. If the range is left at the default 0–100 but the tag's actual values span a much narrower band (e.g. 0–1 or 4–20 mA), the tolerance band will be wider than the signal and almost nothing gets recorded. Always set each tag's range to match the actual expected value range. See [Tag Range and Compression](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression) for details. ## Tag Source Types Every tag has a **source type** that determines where its value comes from. You choose the source type when creating a tag. | Source Type | Description | Has Device? | Usage | |-------------|-------------|-------------|-------| | **Device** | Reads and writes values from a connected industrial device (OPC-UA, Modbus, etc.) | Yes | Input or Output | | **Expression** | Computes its value from a formula that references other tags | No | Read-only | | **In Memory** | Receives its value from a service: the predict engine, mapping service, or component engine | No | Read/Write | ### Device Tags The most common type. A device tag belongs to a device and inherits its protocol. The device handles the connection, and the tag defines _what_ to read or write within that connection: an OPC-UA node, a Modbus register, an EtherNet/IP controller tag, a SQL query, and so on. ### Expression Tags Expression tags compute their value from a formula evaluated by the **Expression Evaluator** service. Expressions can reference: - **Tag values and status**: the live value, status, or error code of any other tag - **Device status**: whether a device connection is running or failed - **Model status**: whether an AI model is running or failed - **Binding values**: the raw prediction value from a model output binding This makes expressions useful for more than simple math. You can build logic that reacts to the health of devices or models, not just their data. Expressions support arithmetic, comparison, and logical operators, plus built-in math and statistical functions. Expressions are evaluated in one of two ways: - **Reactive**: when any referenced tag's value changes, the expression re-evaluates immediately (within milliseconds) - **Timer-based**: if the expression has no reactive tag dependencies, it evaluates once per second See [Expression Tags](https://ai-ops.com/docs/tags/expressions.md) for the full syntax reference. ### In-Memory Tags In-memory tags historize values written by the **predict engine**, **mapping service**, or **component engine**. These services write an `output_value` to the live data cache when they produce a result (e.g. a model prediction or a mapped value). Without an in-memory tag, that output value lives only in the cache and is never recorded. The **Expression Evaluator** service monitors in-memory tags and relays `output_value` to the tag's live `value`, writing each update to the time-series database for historical storage. This relay happens two ways: - **Event-driven**: the producing service publishes a notification after writing, and the relay happens within milliseconds - **Timer fallback**: a periodic check (default 60 seconds) catches any missed notifications In-memory tags also provide: - **Status monitoring**: the tag shows running/stopped/failed status like any other tag - **Stale detection**: if the source service stops writing, the tag surfaces a warning after a configurable timeout (default 24 hours) while staying in a running state. Marking it failed would stop the producing model, so a stale value stays running with a warning showing how long ago the last write occurred - **Waiting state**: before the source service writes for the first time, the tag shows a running status with the warning "No output value — ensure tag is bound to an enabled model, mapping, or component connector" > [!TIP] When to use in-memory tags > Use an in-memory tag when you need to **chart in trends** or **monitor the health** of a value produced by the predict engine, mapping service, or component engine. If you only need the live value in the cache (for example, as an intermediate step in a pipeline), you don't need an in-memory tag. The output value is already available in the live data cache without one. ## Output Conflicts When multiple sources (an AI model, a mapping, and a component) all try to write to the same output tag, Koios flags an **output conflict** on the tag's overview page. This is a warning: only one source's value will be written per scan. Review the tag's cross references to understand what's writing to it and resolve any unintended overlaps. ## Key Concepts | Concept | Description | |---------|-------------| | **Value** | The tag's current reading: from a device, a computed expression, or a service write | | **Quality** | For OPC-UA tags, the server-reported data quality (Good, Bad, Uncertain) | | **Timestamp** | When the value was last updated | | **Range** | The expected min/max values, used by AI models for normalization and compression band calculation | | **Compression override** | Per-tag compression settings that override the global defaults | | **Value mapping** | An ordered list of match rules that convert raw values to numeric outputs | | **Test output** | A mode that writes a fixed value for commissioning output tags | | **Expression** | A formula that computes a tag's value from other tags | | **Cross references** | A view of everything that reads from or writes to a tag | ## What's Next - [Creating a Tag](https://ai-ops.com/docs/tags/creating-getting-started.md): step-by-step guide to adding a new tag - [Expression Tags](https://ai-ops.com/docs/tags/expressions.md): syntax reference for expression formulas - [Value Mapping](https://ai-ops.com/docs/tags/value-mapping.md): mapping raw device values to numeric outputs - [Troubleshooting a Tag](https://ai-ops.com/docs/troubleshoot/tag-values.md): diagnosing errors and testing tag reads --- Source: https://ai-ops.com/docs/tags/creating-getting-started Section: Tags # Creating a Tag To create a tag, navigate to the **Tags** page and click the **+ Add Tag** button. This opens a form where you choose the tag's **source type** (Device, Expression, or In Memory) and configure its settings. This guide covers **device tags**: tags that read from and write to a connected device. For the other source types, see [Expression Tags](https://ai-ops.com/docs/tags/expressions.md) and [In-Memory Tags](https://ai-ops.com/docs/tags/introduction.md#in-memory-tags). > [!NOTE] You can also add tags from a device > When viewing a device's detail page, you can add tags directly to that device. The create form will have the device pre-selected so you can skip straight to naming the tag. ## Form Fields ### Name A unique identifier for the tag. This is how you'll reference the tag throughout the platform: in trends, models, expressions, and exports. - **Required** - Must be unique across all tags - Examples: `Chiller-01/Supply-Temp`, `AHU-3 Damper Position`, `Warehouse Zone 1 Humidity` ### Description An optional free-text field for notes about the tag: what it measures, where the sensor is located, or any context that helps your team. ### Device The device this tag belongs to. Tags inherit their protocol from their device, which determines which protocol-specific fields appear in the form. - **Required** - Devices are grouped by protocol in the dropdown for easy browsing - Cannot be changed after creation. To move a tag to a different device, create a new tag and delete the old one ### Usage Whether this tag is read-only or read/write. | Usage | Description | |-------|-------------| | **Input** | Koios reads this tag's value from the device on each scan (default) | | **Output** | Koios can also write values back to the device through this tag | Choose **Output** when an AI model, mapping, or component needs to push a value to the device. For example, a setpoint that a model adjusts. ### Range Min / Max The expected value range for this tag. Defaults to **0–100**. - Used by AI models for **normalization**. Models expect input values within a known range - Accepts negative values - Set this to match the real-world range of the data point (e.g. -20 to 50 for a temperature sensor in °C, or 0 to 500 for a pressure sensor in PSI) ### Units The engineering units displayed alongside the tag's value (e.g. °C, PSI, RPM, kW). This is a display label only. It doesn't affect the raw value. Select from common units in the dropdown or type a custom unit. ## Protocol-Specific Fields The create form shows additional fields based on the selected device's protocol. These fields tell Koios _where_ to find the data point within the device. You can fill these in during creation, or leave them blank and configure them later on the tag's **Configuration** tab, where you'll also have access to device browsers that can auto-populate these fields for you. | Protocol | Fields on Create Form | |----------|----------------------| | **OPC-UA** | Namespace, identifier type, identifier, data type | | **Modbus TCP** | Register type, register address, data type, byte/word swap, bit number | | **EtherNet/IP (Logix)** | Logix tag name, tag type | | **EtherNet/IP (Generic CIP)** | Assembly instance, byte offset, data type, bit number | | **SOAP (RDM)** | RDM device, RDM parameter | | **REST (BOSS)** | Device address, variable code, variable type | | **Microsoft SQL** | SQL query | For detailed guidance on each protocol's fields, see the protocol-specific tag creation guides: - [Creating an OPC-UA Tag](https://ai-ops.com/docs/tags/creating-opc-ua.md) - [Creating a Modbus TCP Tag](https://ai-ops.com/docs/tags/creating-modbus-tcp.md) - [Creating an EtherNet/IP Tag](https://ai-ops.com/docs/tags/creating-ethernet-ip.md) - [Creating a SOAP Tag](https://ai-ops.com/docs/tags/creating-soap.md) - [Creating a REST Tag](https://ai-ops.com/docs/tags/creating-rest.md) - [Creating a Microsoft SQL Tag](https://ai-ops.com/docs/tags/creating-mssql.md) ## After Creation Once you click **Create Tag**, Koios creates the tag and navigates you to its **Configuration** tab. From here: 1. **Review protocol settings**: if you left protocol fields blank during creation, fill them in now. Use the **Browse** button (available for OPC-UA, Modbus TCP, EtherNet/IP, SOAP, and REST) to discover and select data points directly from the device. 2. **Test the tag**: click the **Test** button to verify Koios can read a value from the device for this tag (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Configure advanced settings**: set up [value mapping](https://ai-ops.com/docs/tags/value-mapping.md), enable test output mode, or configure redundancy if needed 4. **Enable the tag**: flip the enable switch in the tag header > [!TIP] Enable the device first > A tag won't collect data until its parent device is also enabled and running. If this is a new device, make sure you've configured and enabled it before enabling its tags. ## Using Device Browsers For most protocols, you don't need to type protocol settings manually. The **Configuration** tab includes a **Browse** button that connects to the device and lets you discover available data points: - **OPC-UA**: browse the server's node tree, expand folders, and select the node you want. The namespace, identifier, identifier type, and data type are auto-populated. - **Modbus TCP**: browse registers on the device and select one. Register type, address, and data type are auto-populated. - **EtherNet/IP (Logix)**: browse the controller's tag database. Tag name and type are auto-populated. - **EtherNet/IP (Generic CIP)**: browse the device's EDS file to see assemblies and fields. Assembly instance, byte offset, and data type are auto-populated. - **SOAP (RDM)**: browse available RDM devices and parameters. - **REST (BOSS)**: browse available BOSS devices and variables. > [!NOTE] The device must be reachable to browse > Device browsers connect to the device in real time. The device must be powered on and reachable on the network, but it does not need to be enabled in Koios. Browsing uses a one-time connection separate from the scan cycle. ## Duplicating a Tag If you need a tag similar to an existing one, you can **duplicate** it instead of starting from scratch. Right-click a tag in the list and select **Duplicate**, or use the duplicate action on a tag's detail page. Duplicating copies: - All protocol-specific configuration (node ID, register address, expression, etc.) - Range, units, decimal places, and usage - Advanced settings (value mapping, write always, redundancy) It does **not** copy: - The enabled state: the duplicate is always created disabled You'll be prompted to enter a new **name** and optionally update the **description** before confirming. ## Importing Tags For bulk tag creation, you can import tags from a CSV file. On the Tags page, click the import button in the toolbar. The import process has two stages: 1. **Preview**: upload your CSV file and Koios validates it, showing you which tags will be created, updated, or skipped, and flagging any errors. No changes are made yet. 2. **Confirm**: review the preview and click confirm to apply the changes. To get a CSV template with the correct column format, export your existing tags first using the export button. --- Source: https://ai-ops.com/docs/tags/creating-opc-ua Section: Tags # Creating an OPC-UA Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on an OPC-UA device, you need to tell Koios which node in the OPC-UA server this tag represents. You can configure these fields during creation or afterwards on the tag's **Configuration** tab. > [!TIP] Use the node browser instead of typing manually > On the Configuration tab, click **Browse** to connect to the OPC-UA server and navigate its node tree. When you select a node, all four fields below are auto-populated. No manual entry needed. ## Protocol Fields ### Namespace The namespace index that identifies which part of the server's address space the node belongs to. - Namespace **0** is the standard OPC-UA namespace (built-in server nodes) - Namespace **1** is typically the server's own application namespace - Higher namespaces are used by add-ons or companion specifications The browser fills this in automatically. If entering manually, use the numeric namespace index (e.g. `2`). ### Identifier The node's identifier within its namespace. This is the specific address of the data point you want to read or write. - The format depends on the **Identifier Type**. It could be a number, a string path, a GUID, or a byte string - Example (numeric): `1001` - Example (string): `Boiler.Temperature.PV` ### Identifier Type The format of the node's identifier. | Type | Description | Example | |------|-------------|---------| | **Numeric** | An integer node ID, most common for device data points | `1001` | | **String** | A human-readable string path, common in simulation servers and some PLCs | `Boiler.Temperature.PV` | | **GUID** | A globally unique identifier | `72962B91-FA75-4AE6-8D28-B404DC7DAF63` | | **ByteString** | A raw byte string identifier, rare in practice | — | - **Default:** Numeric ### Data Type The expected data type of the node's value. Koios uses this to correctly interpret the raw bytes returned by the server. | Data Type | Description | |-----------|-------------| | **Boolean** | True/false | | **Int16 / UInt16** | 16-bit signed/unsigned integer | | **Int32 / UInt32** | 32-bit signed/unsigned integer | | **Int64 / UInt64** | 64-bit signed/unsigned integer | | **Float** | 32-bit floating point | | **Double** | 64-bit floating point | | **String** | Text value | | **DateTime** | Timestamp | > [!NOTE] Data type must match the server > If the data type doesn't match what the OPC-UA server returns, Koios may misinterpret the value or fail to read it. The node browser auto-detects the correct data type. Use it when possible. ## Using the Node Browser The OPC-UA node browser connects to the server in real time and lets you navigate the address space visually. 1. Open the tag's **Configuration** tab and click **Browse** 2. The browser displays the server's node tree as expandable folders 3. Navigate to the node you want and select it 4. The **Namespace**, **Identifier**, **Identifier Type**, and **Data Type** are all populated automatically 5. Click **Apply** to save the selection > [!NOTE] The device must be reachable to browse > The browser connects directly to the OPC-UA server. The device must be powered on and reachable on the network, but it does not need to be enabled in Koios. ## Timestamp Source By default, Koios records each reading with the time the data collector read the value. Some OPC-UA servers also publish a **source timestamp** (the time the value was actually produced or sampled), which can be earlier than when Koios reads it. This matters for **backdated** signals such as lab results that are reported hours after the sample was taken. | Option | Timestamp recorded | |--------|--------------------| | **Collector Time** | When Koios read the value. The default, and the behavior of every existing tag. | | **Source Timestamp** | The value's OPC-UA source timestamp, its true production or sample time. | With **Source Timestamp**, a value that arrives late but carries an older source time is stored in history at that original time instead of the moment it was read. This keeps late-arriving lab or batch results aligned with the process data they describe. This setting appears only on OPC-UA tags, and if the server does not provide a valid source timestamp for a value, Koios records the collector time for that reading instead. > [!WARNING] Reading backdated values over history > Because a source-timestamped value is stored in the past, anything that reads this tag's history over a short recent window may not see it. For example, a component asking for "the last few minutes." Read history over a window wide enough to cover the longest expected reporting delay. The tag's live value also shows its source time (e.g. "Updated 3 hours ago") even while it is read every scan. This is expected. ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify Koios can read a value from this node (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. --- Source: https://ai-ops.com/docs/tags/creating-modbus-tcp Section: Tags # Creating a Modbus TCP Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on a Modbus TCP device, you need to tell Koios which register to read or write and how to interpret its value. You can configure these fields during creation or afterwards on the tag's **Configuration** tab. > [!TIP] Use the register browser to discover data points > On the Configuration tab, click **Browse** to scan registers on the device. The browser lets you read raw register values and test different data type interpretations before committing to a configuration. ## Protocol Fields ### Register Type The type of Modbus register this tag reads from. | Type | Description | Access | |------|-------------|--------| | **Coil** | Single-bit read/write registers, typically used for on/off controls | Read/Write | | **Discrete Input** | Single-bit read-only registers, typically used for digital sensor states | Read Only | | **Input Register** | 16-bit read-only registers, typically used for analog measurements | Read Only | | **Holding Register** | 16-bit read/write registers, the most common type for configuration and data | Read/Write | - **Required** > [!NOTE] Coil and Discrete Input auto-select Boolean > When you select **Coil** or **Discrete Input**, the data type is automatically set to **Boolean** and locked, since these register types are inherently single-bit. ### Register Address The address of the register on the device. - **Required** - **Range:** 0–65535 - If the device has **one-based addressing** enabled, the display adds 1 to the address for readability, but the underlying communication always uses the 0-based value ### Data Type How Koios interprets the raw register value(s). | Data Type | Registers Used | Description | |-----------|---------------|-------------| | **Boolean** | 1 | Single bit, used with Coil/Discrete or bit extraction from a holding register | | **Int16** | 1 | 16-bit signed integer (-32,768 to 32,767) | | **UInt16** | 1 | 16-bit unsigned integer (0 to 65,535) | | **Int32** | 2 | 32-bit signed integer, reads two consecutive registers | | **UInt32** | 2 | 32-bit unsigned integer, reads two consecutive registers | | **Float32** | 2 | 32-bit floating point, reads two consecutive registers | | **Float64** | 4 | 64-bit floating point, reads four consecutive registers | - **Required** - Multi-register types (Int32, UInt32, Float32, Float64) read consecutive registers starting from the configured address ### Byte Swap Reverses the byte order within each 16-bit register. - **Default:** Off - Enable this when the device stores values in a different byte order than expected (common with some manufacturers) ### Word Swap Reverses the order of registers for multi-register data types (Int32, UInt32, Float32, Float64). - **Default:** Off - Only visible when using a multi-register data type - If a 32-bit value reads as a nonsensical number, try toggling this setting > [!WARNING] Byte order varies between manufacturers > There is no universal standard for byte and word order in Modbus. If your values look wrong (very large numbers, NaN, or values that don't match the device's display), try different combinations of byte swap and word swap until the value is correct. The register browser can help you test this. ### Bit Number When using **Boolean** data type with an **Input Register** or **Holding Register**, this specifies which bit within the 16-bit register to extract. - **Optional**: only shown when data type is Boolean and register type is Input or Holding - **Range:** Bit 0 (least significant) through Bit 15 (most significant) - Leave empty to use the entire register value as a boolean (0 = false, non-zero = true) ## Using the Register Browser The Modbus register browser lets you scan and interpret register values directly from the device. 1. Open the tag's **Configuration** tab and click **Browse** 2. Select the **register type** and enter a **start address** and **count** 3. Click **Scan** to read raw register values from the device 4. Use the **interpretation tools** to test different data types, byte swap, and word swap combinations 5. When you find the correct interpretation, apply it to populate the tag's configuration This is especially useful for unfamiliar devices where the register map isn't well documented. ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify Koios reads the correct value (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. --- Source: https://ai-ops.com/docs/tags/creating-ethernet-ip Section: Tags # Creating an EtherNet/IP Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on an EtherNet/IP device, you need to configure the protocol fields that tell Koios which data point to read or write. The fields you see depend on whether the parent device is a **Logix Controller** or a **Generic CIP** device. You can configure these fields during creation or afterwards on the tag's **Configuration** tab. ## Logix Controller Tags Logix tags are identified by their name in the controller's tag database. Koios reads and writes tags directly using CIP tag-based addressing. > [!TIP] Use the tag browser > On the Configuration tab, click **Browse** to connect to the Logix controller and view its tag database. Select a tag to auto-populate both fields below. ### Logix Tag Name The full name of the tag as it appears in the controller's tag database. - **Required** - Must match the tag name in the controller exactly (case-sensitive) - Supports structured tag paths for accessing members of UDTs (User-Defined Types) and arrays - Examples: `SupplyTemp`, `AHU_3.DamperPosition`, `Temperatures[0]` - Use dot notation for UDT members (e.g. `MyUDT.Temperature`) and bracket notation for arrays (e.g. `Readings[5]`) ### Tag Type The data type of the Logix tag. | Type | Description | |------|-------------| | **Integer** | Whole number values (DINT, INT, SINT in the controller) | | **Real** | Floating-point values (REAL in the controller) | | **Boolean** | True/false values (BOOL in the controller) | | **String** | Text values (STRING in the controller) | - **Required** ### Using the Logix Tag Browser The Logix tag browser connects to the controller and displays its tag database. 1. Open the tag's **Configuration** tab and click **Browse** 2. The browser lists all tags available in the controller 3. Navigate through the tag hierarchy. Programs, UDTs, and arrays are expandable 4. Use the scope toggle to switch between controller-scoped and program-scoped tags 5. Select the tag you want. The **Tag Name** and **Tag Type** are auto-populated 6. Click **Apply** to save the selection The device must be powered on and reachable on the network to browse, but it does not need to be enabled in Koios. ## Generic CIP Tags Generic CIP tags read data from **assembly instances**, blocks of binary data exposed by CIP-compliant devices. Each tag maps to a specific byte offset and data type within an assembly. > [!TIP] Use the EDS browser > If the device has an EDS file uploaded, click **Browse EDS** on the Configuration tab to see a structured view of the device's assemblies and fields. Select a field to auto-populate all four fields below. ### Assembly Instance The CIP assembly instance number that contains the data point. - **Required** - Range: 0 to 65535 - Common values: 100, 101, 106 (varies by device) Assembly instances are defined by the device manufacturer. Refer to the device's documentation or EDS file for the correct instance numbers. ### Byte Offset The byte position within the assembly where this data point starts (zero-indexed). - **Required** - Minimum: 0 The offset depends on the layout of the assembly data. Fields at the beginning of the assembly start at offset 0, and subsequent fields follow based on the size of earlier fields. ### Data Type The data type used to interpret the bytes at the specified offset. | Type | Size | Description | |------|------|-------------| | **INT8** | 1 byte | Signed 8-bit integer (-128 to 127) | | **UINT8** | 1 byte | Unsigned 8-bit integer (0 to 255) | | **INT16** | 2 bytes | Signed 16-bit integer | | **UINT16** | 2 bytes | Unsigned 16-bit integer | | **INT32** | 4 bytes | Signed 32-bit integer | | **UINT32** | 4 bytes | Unsigned 32-bit integer | | **FLOAT32** | 4 bytes | 32-bit floating-point number | | **FLOAT64** | 8 bytes | 64-bit floating-point number | | **BOOL** | 1 bit | Boolean extracted from a byte (requires Bit Number) | - **Required** All multi-byte values use little-endian byte order, which is standard for CIP devices. ### Bit Number When the data type is set to **BOOL**, this field specifies which bit within the byte at the given offset to read. - Range: 0 to 7 (bit 0 is the least significant bit) - **Required** when data type is BOOL ### Using the EDS Browser If the parent device has an EDS file uploaded, you can browse the device's assemblies and fields instead of entering values manually. 1. Open the tag's **Configuration** tab and click **Browse EDS** 2. The browser shows the device's assemblies parsed from the EDS file 3. Expand an assembly to see its individual fields 4. Select a field. The **Assembly Instance**, **Byte Offset**, and **Data Type** are auto-populated 5. Review the values and click **Save** The EDS browser reads from the uploaded file, not from the device. You can browse even when the device is offline. If no EDS file is uploaded, the Browse EDS button won't appear; you can still configure tags manually or upload an EDS file from the [device's Configuration tab](https://ai-ops.com/docs/devices/creating-ethernet-ip.md#generic-cip-configuration). ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify Koios can read a value from the device (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. --- Source: https://ai-ops.com/docs/tags/creating-mssql Section: Tags # Creating a Microsoft SQL Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on a Microsoft SQL device, you need to provide the SQL query that Koios will execute to read this tag's value. You can configure this during creation or afterwards on the tag's **Configuration** tab. > [!NOTE] No device browser available > Unlike other protocols, Microsoft SQL tags don't have a browse function. You'll need to know the database schema and write the query yourself. ## Protocol Fields ### SQL Query The SQL query that Koios executes against the database on each scan to read this tag's value. - **Optional** during creation, but required for the tag to collect data - The query should return a **single numeric value** - Maximum length: 1,024 characters ```sql SELECT TOP 1 temperature FROM sensor_readings WHERE sensor_id = 'AHU-01' ORDER BY timestamp DESC ``` ### Query Guidelines **Return a single value.** Koios reads the first column of the first row of the result set. If your query returns multiple rows or columns, only the first value is used. **Keep queries lightweight.** The query runs on every scan cycle, so avoid expensive joins, full table scans, or complex aggregations that could slow down the database. **Use parameterized values where possible.** If you need the most recent reading, use `TOP 1` with an `ORDER BY` on the timestamp column rather than scanning the entire table. > [!WARNING] Query runs repeatedly at the scan rate > This query executes every time the device scans, typically every few seconds. Make sure it performs well under repeated execution. Add appropriate indexes to the source table if needed. ### Example Queries **Latest sensor reading:** ```sql SELECT TOP 1 value FROM readings WHERE tag_name = 'Supply_Temp' ORDER BY timestamp DESC ``` **Aggregated value:** ```sql SELECT AVG(temperature) FROM hourly_averages WHERE zone = 'Warehouse-1' AND timestamp > DATEADD(HOUR, -1, GETDATE()) ``` **Count of active alarms:** ```sql SELECT COUNT(*) FROM active_alarms WHERE severity >= 3 ``` ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify the query returns a valid value (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. Make sure the SQL device's connection credentials and database are correctly configured. --- Source: https://ai-ops.com/docs/tags/creating-rest Section: Tags # Creating a REST Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on a REST (CAREL BOSS) device, you need to tell Koios which BOSS variable to read or write. You can configure these fields during creation or afterwards on the tag's **Configuration** tab. > [!TIP] Use the BOSS browser to discover variables > On the Configuration tab, click **Browse** to connect to the BOSS controller and explore its devices and variables. Select a variable to auto-populate all three fields below. ## Protocol Fields ### Device Address The address of the device within the BOSS system. BOSS controllers can manage multiple downstream devices, and this field identifies which one to communicate with. - Each device in the BOSS system has a unique address - Example: `1`, `LOC001` ### Variable Code The code that identifies the specific variable (data point) on the BOSS device. - Each variable on a BOSS device has a unique code - Example: `B0`, `A15` ### Variable Type The data type of the BOSS variable. | Type | Description | |------|-------------| | **Analog** | A numeric value: temperatures, pressures, setpoints | | **Digital** | A binary on/off state: relays, switches, alarms | | **Integer** | A whole number value: counters, mode selections | | **Alarm** | An alarm state from the controller's alarm system | ## Using the BOSS Browser The BOSS browser connects to the controller and lets you explore its device and variable hierarchy. 1. Open the tag's **Configuration** tab and click **Browse** 2. The browser lists all devices registered in the BOSS controller 3. Expand a device to see its available variables 4. Select the variable you want. The **Device Address**, **Variable Code**, and **Variable Type** are auto-populated 5. Click **Apply** to save the selection > [!NOTE] The device must be reachable to browse > The browser connects to the BOSS controller via its REST API. The device must be powered on, reachable on the network, and the REST credentials configured on the device must be valid. ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify Koios can read the variable's value (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. --- Source: https://ai-ops.com/docs/tags/creating-soap Section: Tags # Creating a SOAP Tag After [creating a tag](https://ai-ops.com/docs/tags/creating-getting-started.md) on a SOAP (RDM) device, you need to tell Koios which RDM device and parameter to read. You can configure these fields during creation or afterwards on the tag's **Configuration** tab. > [!TIP] Use the RDM browser to discover parameters > On the Configuration tab, click **Browse** to connect to the RDM service and explore its devices and parameters. Select a parameter to auto-populate both fields below. ## Protocol Fields ### RDM Device The identifier of the device within the RDM system. RDM services manage multiple devices, and this field identifies which one to query. - Example: `Device001`, `AHU-3` ### RDM Parameter The name of the parameter to read from the RDM device. Each parameter represents a specific data point: a sensor reading, setpoint, or status value. - Example: `SupplyAirTemp`, `FanSpeed`, `CoolValvePos` ## Using the RDM Browser The RDM browser connects to the SOAP service and lets you explore its device and parameter hierarchy. 1. Open the tag's **Configuration** tab and click **Browse** 2. The browser lists all devices available in the RDM service 3. Expand a device to see its available parameters 4. Select the parameter you want. The **RDM Device** and **RDM Parameter** are auto-populated 5. Click **Apply** to save the selection > [!NOTE] The device must be reachable to browse > The browser connects to the RDM SOAP service. The device must be powered on and reachable on the network, but it does not need to be enabled in Koios. ## After Configuration 1. **Save** the tag configuration 2. **Test the tag**: click `Test` to verify Koios can read the parameter's value (see [Testing a Tag](https://ai-ops.com/docs/troubleshoot/connection.md#testing-a-connection)) 3. **Enable the tag**: flip the enable switch to start collecting data > [!TIP] Enable the device first > Tags only collect data when their parent device is also enabled and running. --- Source: https://ai-ops.com/docs/tags/expressions Section: Tags # Expression Tags Expression tags compute their value from a formula evaluated by the **Expression Evaluator** service. Expressions can reference tags, devices, AI models, and model bindings, use arithmetic and logical operators, and call built-in math and statistical functions. Expressions are evaluated in one of two ways: - **Reactive**: when any referenced tag's value changes, the expression re-evaluates immediately (within milliseconds). This is the default when the expression references at least one tag value. - **Timer-based**: if the expression has no reactive tag dependencies (e.g. it only references device or model status), it evaluates once per second. Common use cases include: - Unit conversions (e.g. Celsius to Fahrenheit) - Scaling raw signals (e.g. 4–20 mA to 0–100%) - Averaging multiple sensors - Smoothing noisy readings with time-aware filters - Computing rate of change for trend detection - Status-based fallback logic (switch to backup sensor if primary fails) - Alarm thresholds with deadband filtering - Health monitoring (react to device or model failures) ## References Type `@` in the expression editor to search and insert a reference. The autocomplete menu shows tags, devices, AI models, and model bindings, each with the fields you can reference. ### Tag References Reference a tag's live value, status, or error code: ```text @[Temperature Sensor:value] → current numeric value @[Temperature Sensor:status] → 1 if running, 0 if stopped/failed @[Temperature Sensor:error_code] → numeric error code (0 = no error) ``` Tag value references are **reactive**. The expression re-evaluates immediately when the referenced tag's value changes. ### Device References Reference a device's connection status or error code: ```text @[OPC-UA Server 1:status] → 1 if running, 0 if stopped/failed @[OPC-UA Server 1:error_code] → numeric error code (0 = no error) ``` Device references are useful for building failover logic. For example, switching to a backup device's tags when the primary device goes down. ### Model References Reference an AI model's status or error code: ```text @[Chiller Model:status] → 1 if running, 0 if stopped/failed @[Chiller Model:error_code] → numeric error code (0 = no error) ``` ### Binding References Reference the raw prediction value from a model output binding: ```text @[Chiller Model / Supply Temp:value] → the binding's output value @[Chiller Model / Supply Temp:status] → 1 if running, 0 if stopped/failed @[Chiller Model / Supply Temp:error_code] → numeric error code (0 = no error) ``` Binding value references give you access to a model's prediction output without needing an in-memory tag to historize it first. > [!TIP] Autocomplete helps avoid typos > Always use the `@` autocomplete menu to insert references rather than typing them manually. This ensures the name and field are spelled correctly and creates a tracked dependency. If an expression does fail to evaluate, see [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) to diagnose it. ## Arithmetic Operations Standard math operators are supported: | Operation | Symbol | Example | Result | |-----------|--------|---------|--------| | Addition | `+` | `5 + 3` | 8 | | Subtraction | `-` | `10 - 4` | 6 | | Multiplication | `*` | `6 * 7` | 42 | | Division | `/` | `20 / 4` | 5.0 | | Power | `**` | `2 ** 3` | 8 | | Modulo | `%` | `10 % 3` | 1 | ## Comparison Operations Comparisons return `True` or `False` and are commonly used inside conditional expressions: | Operation | Symbol | Example | Result | |-----------|--------|---------|--------| | Equal | `==` | `5 == 5` | True | | Not Equal | `!=` | `5 != 3` | True | | Greater Than | `>` | `10 > 5` | True | | Less Than | `<` | `3 < 7` | True | | Greater or Equal | `>=` | `5 >= 5` | True | | Less or Equal | `<=` | `3 <= 5` | True | ## Logical Operations Combine conditions with `and`, `or`, and `not`: ```text True and True → True True or False → True not True → False ``` ## Math Functions Built-in math functions for common calculations: | Function | Description | Example | Result | |----------|-------------|---------|--------| | `sin(x)` | Sine (radians) | `sin(1.5708)` | 1.0 | | `cos(x)` | Cosine (radians) | `cos(3.14159)` | -1.0 | | `tan(x)` | Tangent (radians) | `tan(0.7854)` | 1.0 | | `sqrt(x)` | Square root | `sqrt(16)` | 4.0 | | `exp(x)` | e raised to power x | `exp(1)` | 2.718 | | `log(x)` | Natural logarithm | `log(2.71828)` | 1.0 | | `log10(x)` | Base-10 logarithm | `log10(100)` | 2.0 | | `fabs(x)` | Absolute value | `fabs(-5.5)` | 5.5 | | `ceil(x)` | Round up to integer | `ceil(4.3)` | 5 | | `floor(x)` | Round down to integer | `floor(4.7)` | 4 | | `trunc(x)` | Truncate to integer | `trunc(4.7)` | 4 | | `pow(x, y)` | x raised to power y | `pow(2, 3)` | 8 | | `degrees(x)` | Radians to degrees | `degrees(3.14159)` | 180.0 | | `radians(x)` | Degrees to radians | `radians(180)` | 3.14159 | ## Statistical Functions Functions that operate on lists of values: | Function | Description | Example | Result | |----------|-------------|---------|--------| | `mean(list)` | Average of values | `mean([1, 2, 3, 4, 5])` | 3.0 | | `median(list)` | Middle value | `median([1, 3, 5, 7, 9])` | 5 | | `std(list)` | Population standard deviation | `std([2, 4, 4, 4, 5, 5, 7, 9])` | 2.0 | | `var(list)` | Population variance | `var([2, 4, 4, 4, 5, 5, 7, 9])` | 4.0 | | `min(list)` | Minimum value | `min([5, 2, 8, 1, 9])` | 1 | | `max(list)` | Maximum value | `max([5, 2, 8, 1, 9])` | 9 | | `sum(list)` | Sum of all values | `sum([1, 2, 3, 4, 5])` | 15 | Random helpers are also available for testing and simulation: `random()` (float in 0–1), `randint(a, b)`, `uniform(a, b)`, and `choice(list)`. > [!NOTE] Lists use square brackets > Statistical functions require a list as input. Create lists using square brackets: `[value1, value2, value3]`. You can mix tag references and constants inside a list. ## Filter Functions Filter functions smooth, transform, or gate input signals. They maintain internal state across evaluations, so each call remembers its previous output. ### filter: Exponential Moving Average `filter(value, tau)` applies an exponential moving average. The `tau` parameter is the **time constant in seconds**. It controls how quickly the output tracks the input, regardless of how often the expression evaluates. | Parameter | Description | |-----------|-------------| | `value` | The current input value | | `tau` | Time constant in seconds. Larger values = more smoothing | At each evaluation the filter computes: `alpha = 1 - e^(-dt / tau)`, then `output = alpha x input + (1 - alpha) x previous`. On the first evaluation the output equals the input. | Expression | Description | Use Case | |------------|-------------|----------| | `filter(@[Temperature:value], 5)` | 5-second time constant | Fast-changing signals, light smoothing | | `filter(@[Pressure:value], 30)` | 30-second time constant | Moderate noise reduction | | `filter(@[Level:value], 120)` | 2-minute time constant | Very noisy sensors, stable reading needed | > [!TIP] Time-aware smoothing > The `tau` parameter is specified in real seconds, so the filter behaves identically whether the expression evaluates once per second or once per minute. A `tau` of 30 always means a 30-second time constant. ### moving_avg: Moving Average `moving_avg(value, window)` computes the average of all samples received within the last `window` seconds. | Parameter | Description | |-----------|-------------| | `value` | The current input value | | `window` | Window size in seconds | | Expression | Description | |------------|-------------| | `moving_avg(@[Flow:value], 60)` | Average flow over the last 60 seconds | | `moving_avg(@[Power:value], 300)` | 5-minute rolling average of power consumption | ### rate: Rate of Change `rate(value)` returns the rate of change of the input in **units per second**. It only updates when the input actually changes, so repeated evaluations with a stale value don't distort the result. | Parameter | Description | |-----------|-------------| | `value` | The current input value | | Expression | Description | |------------|-------------| | `rate(@[Temperature:value])` | Degrees per second of temperature change | | `rate(@[Level:value]) * 60` | Level change per minute | ### deadband: Deadband Filter `deadband(value, threshold)` only passes through changes larger than `threshold`. The output holds its last accepted value until the input moves far enough away. | Parameter | Description | |-----------|-------------| | `value` | The current input value | | `threshold` | Minimum change to pass through (must be > 0) | | Expression | Description | |------------|-------------| | `deadband(@[Setpoint:value], 0.5)` | Ignore changes smaller than 0.5 | | `deadband(filter(@[Noisy:value], 10), 1.0)` | Smooth first, then deadband | ## Conditional Expressions Use Python's ternary syntax for if-else logic: ```text value_if_true if condition else value_if_false ``` | Expression | Description | |------------|-------------| | `1 if @[Switch:value] == 1 else 0` | Binary output based on switch state | | `@[Temp:value] * 1.8 + 32 if @[Units:value] == 1 else @[Temp:value]` | Convert to Fahrenheit if units flag is set | | `"High" if @[Level:value] > 80 else "Low"` | Text output based on threshold | | `100 if @[Valve:value] == 1 else 50 if @[Valve:value] == 0.5 else 0` | Multiple conditions (nested) | ## Practical Examples ### Temperature Conversion Celsius to Fahrenheit: ```text @[Temperature C:value] * 1.8 + 32 ``` ### Scaling and Offset Convert a 4–20 mA signal to 0–100%: ```text (@[Current:value] - 4) * 100 / 16 ``` ### Average of Multiple Sensors ```text (@[Sensor1:value] + @[Sensor2:value] + @[Sensor3:value]) / 3 ``` ### Status-Based Fallback Use a backup sensor if the primary tag fails: ```text @[Primary:value] if @[Primary:status] == 1 else @[Backup:value] ``` ### Device Failover Switch to a backup device's sensor when the primary device connection goes down: ```text @[Primary Sensor:value] if @[Primary OPC-UA:status] == 1 else @[Backup Sensor:value] ``` ### Model Health Check Output 1 when the AI model is running, 0 when it's stopped or failed: ```text 1 if @[Chiller Model:status] == 1 else 0 ``` ### Alarm with Deadband High alarm with a 5-unit deadband. Turns on above 95, off below 90, holds previous state in between: ```text 1 if @[Process:value] > 95 else (0 if @[Process:value] < 90 else @[Alarm:value]) ``` ### Smoothed Differential Smoothed pressure differential with a 30-second time constant: ```text filter(@[Pressure In:value] - @[Pressure Out:value], 30) ``` ### Rate of Temperature Change Degrees per minute: ```text rate(@[Supply Temp:value]) * 60 ``` ### Smoothed Deadband Reduce noise first, then gate small changes: ```text deadband(filter(@[Vibration:value], 10), 0.5) ``` --- Source: https://ai-ops.com/docs/tags/importing-exporting Section: Tags # Importing & Exporting Tags You can import and export tag configurations as CSV files. This is useful for bulk-creating tags across devices, migrating configurations between Koios instances, or editing tag settings in a spreadsheet. ## Exporting Tags ### How to Export There are two ways to export tag configurations: 1. **From the tag table**: select one or more tags using the checkboxes, then click **Export config** in the bulk actions menu. Only the selected tags are exported. 2. **Export all**: if no tags are selected, the export includes every tag in the system. The export downloads a file named `tags.csv` containing one row per tag. ### What's Included The CSV contains all configuration fields for each tag: general settings, protocol-specific fields, and advanced options. Every column is included regardless of protocol, so columns that don't apply to a particular tag's protocol will be empty. > [!NOTE] Config only, not live data > The export contains static configuration from the database. Live values, status, timestamps, and error states are not included. Those come from the live data cache and change every scan cycle. ### CSV Columns The export includes these columns: **Core fields:** | Column | Description | |--------|-------------| | `id` | Database ID (primary key) | | `name` | Tag name (unique) | | `description` | Optional description | | `slug` | UUID identifier | | `enabled` | Whether the tag is active | | `device` | Parent device ID | | `usage` | `0` = Input (read-only), `1` = Output (read/write) | | `range_min` | Minimum expected value | | `range_max` | Maximum expected value | | `units` | Engineering units label | | `decimal_places` | Display precision (0–3) | | `source_type` | `0` = Device, `1` = Expression, `2` = In Memory | | `parent` | Folder ID (if organized in folders) | **Advanced fields:** | Column | Description | |--------|-------------| | `use_lookup_table` | Whether value mapping is enabled | | `lookup_table` | Value mapping rules as a JSON string | | `case_insensitive_lookup` | Case-insensitive value matching | | `reverse_lookup_on_write` | Reverse mapping when writing | | `test_output_enable` | Manual test value enabled | | `test_output_value` | Manual test value | | `write_always` | Write every scan cycle vs only on change | | `is_redundant` | Uses device set failover | | `device_set` | Redundant device set ID | **Protocol-specific fields:** | Columns | Protocol | |---------|----------| | `opcua_namespace`, `opcua_identifier`, `opcua_identifier_type`, `opcua_datatype` | OPC-UA | | `modbus_register`, `modbus_register_type`, `modbus_data_type`, `modbus_byte_swap`, `modbus_word_swap`, `modbus_bit_number` | Modbus TCP | | `ethernet_ip_logix_tagname`, `ethernet_ip_logix_tag_type` | EtherNet/IP (Logix) | | `ethernet_ip_generic_assembly_instance`, `ethernet_ip_generic_byte_offset`, `ethernet_ip_generic_data_type`, `ethernet_ip_generic_bit_number` | EtherNet/IP (Generic CIP) | | `soap_rdm_device`, `soap_rdm_parameter` | SOAP (RDM) | | `rest_boss_device_address`, `rest_boss_variable_code`, `rest_boss_variable_type` | REST (BOSS) | | `sql_query` | Microsoft SQL | | `expression` | Expression | Expression tags use the `expression` column. Internally this protocol is named "Calculation" in the database. **Audit fields (read-only):** | Column | Description | |--------|-------------| | `created_at` | Creation timestamp | | `updated_at` | Last modification timestamp | | `last_modified_by` | User who last modified the tag | --- ## Importing Tags ### How to Import 1. Navigate to the **Tags** page 2. Click the **Import** button in the table toolbar 3. Select a CSV file from your computer 4. Review the preview to verify what will change 5. Click **Confirm Import** to apply the changes ### CSV Format The import expects a CSV file with column headers matching the export format. You don't need to include every column, only the fields you want to set. At minimum, new tags require a `name`. > [!TIP] Start from an export > The easiest way to build an import file is to export your existing tags, edit the CSV in a spreadsheet, and re-import it. The column headers will already be correct. **How the import determines what to do with each row:** | Condition | Action | |-----------|--------| | `id` column is empty | **Create** a new tag | | `id` matches an existing tag and fields differ | **Update** the existing tag | | `id` matches an existing tag and nothing changed | **Skip** the row | | Row has validation errors | **Error**: row is not imported | ### Example: Creating New Tags To create new tags, leave the `id` column empty. Provide at least a `name` and `device` (by ID): ```text id,name,device,enabled,usage,range_min,range_max,units,decimal_places,opcua_namespace,opcua_identifier,opcua_identifier_type,opcua_datatype ,Supply Air Temp,1,True,0,0,100,°C,2,2,ns=2;s=AHU1/SAT,1,7 ,Return Air Temp,1,True,0,0,100,°C,2,2,ns=2;s=AHU1/RAT,1,7 ,Damper Position,1,True,1,0,100,%,1,2,ns=2;s=AHU1/Damper,1,7 ``` ### Example: Updating Existing Tags To update existing tags, include the `id` column with the tag's database ID. Only the fields you include will be checked for changes: ```text id,name,range_min,range_max,units 42,Supply Air Temp,-20,50,°C 43,Return Air Temp,-20,50,°C ``` ### Preview Step After selecting a file, Koios performs a **dry run**. It processes the CSV without saving anything and shows you exactly what will happen: - **Summary**: counts of tags that will be created, updated, skipped, or rejected - **Row details**: click any row to see a field-by-field diff of what will change - **Diff table**: click **Show Diff Table** for a full-width view of all changes across all rows, with changed fields highlighted > [!WARNING] Errors block the import > If any row has a validation error, the entire import is blocked. Fix the errors in your CSV and re-upload. Common errors include duplicate names, missing required fields, and referencing devices that don't exist. ### Validation Rules The import validates each row against the same rules as the create/update forms: | Field | Validation | |-------|------------| | `name` | Required, max 128 characters, must be unique | | `description` | Max 128 characters | | `device` | Must reference an existing device ID | | `usage` | Must be `0` (Input) or `1` (Output) | | `range_min` / `range_max` | Must be valid numbers | | `units` | Max 12 characters | | `decimal_places` | Integer between 0 and 3 | | `source_type` | Must be `0` (Device), `1` (Expression), or `2` (In Memory) | | Protocol fields | Validated against protocol-specific constraints | **Boolean fields** accept: `True`/`False`, `true`/`false`, `1`/`0`, `yes`/`no`. **Foreign key fields** (`device`, `parent`, `device_set`) expect integer IDs. ### After Import Once you confirm the import: - Tags are created or updated in a single transaction. If anything fails, all changes are rolled back - An audit event is recorded (e.g. "Imported 15 tags") with your username - The tag table automatically refreshes to show the updated list - Imported tags start collecting data on the next scan cycle if they are enabled and their device is running > [!NOTE] Service pickup delay > After import, the datacollector detects new or changed tags on its next scan cycle. This typically takes a few seconds. You don't need to restart any services. --- ## Tips - **Bulk-create tags for a new device**: export one configured tag from that device, duplicate the row in your spreadsheet for each new tag, change the names and addresses, clear the `id` column, and import. - **Move tags between Koios instances**: export from one instance, adjust `device` IDs to match the target instance's devices, clear the `id` and `slug` columns, and import on the target. - **Audit trail**: every import creates an event visible on the **Events** page, grouped under a single parent event so you can see what was imported in one action. - **Read-only columns**: `id`, `slug`, `created_at`, `updated_at`, and `last_modified_by` are ignored on create. You can leave them in the CSV (useful when round-tripping an export) but they won't overwrite system-managed values. --- Source: https://ai-ops.com/docs/tags/value-mapping Section: Tags # Value Mapping Value mapping converts raw device values into numeric outputs using an ordered list of match rules. When enabled on a tag, every value read from the device is evaluated against the rules. The first matching rule determines the output. Common use cases include: - Converting status strings like `"Off"` and `"On"` to numeric values `0` and `1` - Mapping numeric ranges (e.g. values above 100 map to an alarm state) - Normalizing wildcard-patterned strings (e.g. anything ending in `_active` maps to `1`) - Providing a catch-all default when no specific rule matches ## How It Works Value mapping rules are evaluated **top-to-bottom**. The first rule that matches the incoming value wins. Its output becomes the tag's numeric value, and the original raw value is preserved as the **lookup key**. For example, given these rules: | # | Match Type | Pattern | Output | |---|------------|---------|--------| | 1 | Exact | Off | 0 | | 2 | Exact | On | 1 | | 3 | Any | — | -1 | If the device returns `"On"`, rule 2 matches. The tag's value becomes `1` and the lookup key shows `"On"`. If the device returns something unexpected like `"Standby"`, rules 1 and 2 don't match, but rule 3 (the catch-all) does, so the value becomes `-1`. > [!TIP] Order matters > Rules are checked in the order you define them. Place specific rules at the top and catch-all rules at the bottom. You can reorder rules using the arrow buttons in the editor. ## Enabling Value Mapping Value mapping is configured in the **Advanced** section of a tag's configuration: 1. Open the tag's **Configuration** tab 2. Scroll to the **Advanced** section 3. Toggle **Use Value Mapping** on 4. Add your rules using the rule editor 5. Save your changes You can also enable value mapping when creating a new tag. The same settings are available in the create form's advanced section. ## Match Types The rule editor supports eight match types: | Match Type | Description | Pattern Format | Example | |------------|-------------|----------------|---------| | **Exact Match** | Value equals the pattern exactly | Text or number | `Off`, `42`, `3.14` | | **Greater Than** | Numeric value is strictly greater than the pattern | Number | `100` | | **Greater or Equal** | Numeric value is greater than or equal to the pattern | Number | `100` | | **Less Than** | Numeric value is strictly less than the pattern | Number | `0` | | **Less or Equal** | Numeric value is less than or equal to the pattern | Number | `0` | | **Between** | Numeric value is between min and max (inclusive) | Two numbers | `10` and `50` | | **Wildcard Pattern** | Glob-style pattern matching | Pattern with `*` or `?` | `*_active` | | **Any (Catch-all)** | Always matches, regardless of value | No pattern needed | — | ### Exact Match Matches when the raw value equals the pattern. For numeric values, this uses a tolerance-based comparison to handle floating-point imprecision, so a value of `0.30000000000000004` (the result of `0.1 + 0.2`) will correctly match a pattern of `0.3`. For string values, it performs a direct string comparison. ### Numeric Comparisons The **Greater Than**, **Greater or Equal**, **Less Than**, **Less or Equal**, and **Between** match types work with numeric values only. If the raw value cannot be parsed as a number, these rules are skipped and evaluation continues to the next rule. **Between** matches when the value falls within a range (inclusive on both ends). In the editor, you enter the minimum and maximum values separately. ### Wildcard Pattern Uses glob-style matching where: - `*` matches any number of characters - `?` matches exactly one character For example, the pattern `Sensor_*_OK` would match `Sensor_01_OK`, `Sensor_Temp_OK`, etc. ### Any (Catch-all) Always matches. Place this as the last rule to provide a default output when no other rule matches. No pattern is needed. > [!WARNING] Unmatched values cause errors > If value mapping is enabled but no rule matches the incoming value, the tag will enter an error state. Always include a catch-all rule at the bottom if you want to handle unexpected values gracefully. If a tag is already showing a mapping error, see [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) to diagnose it. ## Additional Options ### Case-Insensitive Matching When enabled, **Exact Match** and **Wildcard Pattern** rules ignore letter case. For example, `"off"`, `"OFF"`, and `"Off"` would all match a pattern of `"Off"`. This setting has no effect on numeric comparisons (Greater Than, Less Than, Between, etc.) since numbers don't have case. ### Reverse Mapping on Write For **output** tags, enabling reverse mapping converts the numeric output value back to the original string before writing to the device. This only works with **Exact Match** rules. It finds the first exact rule whose output matches the value being written and sends the rule's pattern string to the device instead. For example, if an AI model writes the value `1` to an output tag with the rules above, reverse mapping would convert it back to `"On"` before sending it to the device. > [!NOTE] Output tags only > Reverse mapping is only relevant for output tags that write values back to a device. It has no effect on input tags. ## Viewing the Lookup Key When value mapping is active, the tag's live data displays both: - **Value**: the numeric output from the matched rule - **Lookup Key**: the original raw value from the device, shown in brackets next to the value This appears in the tag list table and on the tag's overview page. It helps you verify which raw value was received and which rule matched. ## Examples ### String-to-Number Mapping Map device status strings to numeric values: | # | Match Type | Pattern | Output | |---|------------|---------|--------| | 1 | Exact | Off | 0 | | 2 | Exact | On | 1 | | 3 | Exact | Standby | 2 | | 4 | Exact | Error | 3 | | 5 | Any | — | -1 | ### Numeric Range Mapping Classify a temperature reading into zones: | # | Match Type | Pattern | Output | |---|------------|---------|--------| | 1 | Less Than | 0 | 0 | | 2 | Between | 0 and 25 | 1 | | 3 | Between | 25 and 35 | 2 | | 4 | Greater Than | 35 | 3 | ### Wildcard Pattern Matching Map device response codes that follow a naming pattern: | # | Match Type | Pattern | Output | |---|------------|---------|--------| | 1 | Wildcard | *_OK | 1 | | 2 | Wildcard | *_WARN | 2 | | 3 | Wildcard | *_FAIL | 3 | | 4 | Any | — | 0 | --- Source: https://ai-ops.com/docs/tags/troubleshooting Section: Tags # Troubleshooting a Tag > [!NOTE] This guide has moved > Tag troubleshooting now lives in the **Troubleshoot** section. For bad quality, missing, or frozen values, see [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). For expression or value-mapping errors, see [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md). For trends gaps or historization, see [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md). Not sure where to start? Begin at [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md). --- Source: https://ai-ops.com/docs/trends/introduction Section: Trends # Trends A **trend** in Koios is an interactive time-series chart that plots one or more tag values over time. Use trends to monitor live processes, investigate historical incidents, compare variables side by side, and export data for offline analysis. ## User Trends vs Model Trends | Type | Created by | Editable | Deletable | |------|-----------|----------|-----------| | **User** | You, from the Trends page | Full control over traces, axes, and settings | Yes | | **Model** | Automatically, when an AI model is enabled | Display settings only. Traces and axes are managed by the model | No | Model trends automatically include the model's bound input and output tags and update when bindings change. You can still customize colors, line styles, and sampling. ## Creating a Trend Click **Add Trend** from the Trends list to open the create dialog. It has three tabs: **General** (name, description, X-Axis Span), **Sampling**, and **Display**. The Sampling and Display tabs expose the same window, aggregate, and chart-style options as the settings drawer, so you can set them at creation or accept the defaults and tune them later. The **X-Axis Span** toggle sets the chart's default time window. **Auto** (the default) remembers your last zoom level between sessions. **Fixed** sets an explicit window that starts at 1 hour. After creation, you are taken to the trend detail page to add tags and configure the chart. > [!TIP] Quick trend from a tag > You can also create a trend pre-populated with specific tags by navigating from a tag's detail page or the tag list. ## The Trend Detail Page The detail page has two main areas: - **Chart area** (left): the time-series chart with a navigation toolbar - **Trace panel** (right): a collapsible sidebar for managing plotted tags and Y-axes How edits are saved depends on whether the trend already exists: - **New trend**: all changes (traces, axes, settings, name, description) are held locally until you click **Save Trend**, and the browser warns you if you try to leave with unsaved changes. The name and description are edited inline in the header. - **Existing trend**: every trace, axis, color, setting, and name change auto-saves immediately, optimistically, and reverts if the save fails. There is no Save button and no leave warning. Edit the name and description from the pencil (Edit Details) modal in the header. ## Chart Navigation The toolbar provides date-time pickers, pan/zoom buttons, and a **timespan selector** with presets (1m, 5m, 30m, 1h, 8h, 1d). You can also scroll to zoom, click-drag to pan, and hold **Cmd/Ctrl + drag** to zoom into a specific region. ### Auto-Scroll (Live Mode) The **Auto Scroll** toggle switches between: - **On**: the chart scrolls forward in real time with a red **NOW** line marking the current moment. Data updates every second. - **Off**: the chart stays at the current view so you can freely explore historical data. The current-moment indicator and the chart's x-axis are anchored to the **server clock**, not the browser clock. If your workstation's wall time is misaligned with the Koios server, the chart still tracks real elapsed time correctly. > [!TIP] Auto-scroll pauses when you interact > Zooming or panning while auto-scroll is on automatically pauses it. Toggle the switch back on to resume. ## Managing Trends From the Trends list, right-click a row (or use its actions menu) to duplicate or delete a trend. Duplicating copies its traces, axes, and display settings into a new trend. You can also duplicate the open trend from the copy icon in the detail-page header. To delete several trends at once, select them with the row checkboxes and choose **Delete** from the bulk actions menu. Model-managed trends cannot be deleted; they are controlled by their AI model. --- ## What's Next - [Traces & Axes](https://ai-ops.com/docs/trends/traces-and-axes.md): add tags, configure multi-axis layouts, and customize colors - [Settings & Export](https://ai-ops.com/docs/trends/settings-and-export.md): adjust sampling, display options, and download data --- Source: https://ai-ops.com/docs/trends/traces-and-axes Section: Trends # Traces & Axes Each tag added to a trend becomes a **trace**, a colored line on the chart. The **trace panel** on the right side of the detail page manages which tags are plotted and how they are scaled. ## Adding & Removing Traces Use the **tag search** at the top of the trace panel to find and add tags. Each new trace is automatically assigned a color from a 10-color palette. Click a trace's **color swatch** to change it using preset swatches or a full color picker. Remove a trace by clicking the trash icon. On an existing trend, adding or removing traces, changing a trace color, and adding, removing, or editing an axis all save automatically. While building a brand-new trend, these changes are held until you click **Save**. > [!NOTE] Model-managed traces are locked > Traces on a model-managed trend show a lock icon and cannot be removed. They are synchronized from the model's bindings. ## Multiple Y-Axes By default, all traces share a single Y-axis. If your tags have different scales (e.g. temperature in degrees and pressure in PSI), click **Add Y-Axis** to create additional axes. ### Axis Configuration Click the **edit icon** on an axis header to configure it: | Setting | Description | Default | |---------|-------------|---------| | **Label** | Display name shown on the chart | Axis 1, Axis 2, etc. | | **Position** | Left or Right side of the chart | Left | | **Min / Max** | Hard limits: the axis never exceeds these bounds | Auto | | **Suggested Min / Max** | Soft limits: preferred range, but the axis expands if data requires it | Auto | | **Color** | Custom color for the axis title and tick labels | Theme default | > [!TIP] Hard vs suggested limits > Use **Min/Max** to fix the range (e.g. 0–100 for a percentage). Use **Suggested Min/Max** when you want a preferred range that can still expand for outliers. ### Assigning Traces to Axes With two or more axes, the trace panel switches to a **grouped view**. Drag traces between axis groups to reassign them. Traces in each group share that axis's scale. The left axis displays grid lines; right axes show ticks and labels only. Each axis is color-coded to match its traces. --- ## What's Next - [Settings & Export](https://ai-ops.com/docs/trends/settings-and-export.md): adjust sampling, display options, and download data - [Trends](https://ai-ops.com/docs/trends/introduction.md): overview and chart navigation --- Source: https://ai-ops.com/docs/trends/settings-and-export Section: Trends # Settings & Export ## Chart Settings Click the **settings icon** in the toolbar to open the settings drawer. Changes apply immediately to the chart. On an existing trend, click **Save** in the drawer footer to persist them. On a trend you haven't saved yet, the drawer shows **Done** instead, and the settings are saved when you create the trend. ### Sampling Sampling controls how raw data points are aggregated when viewing large time ranges. **Window Period** determines the time bucket size: - **Auto**: the system targets 100–5,000 data points on screen based on the visible range - **Custom**: choose a fixed window: Raw (no aggregation), 1s, 5s, 10s, 30s, 1m, 5m, 15m, or 1h **Aggregate Function** reduces each window to a single value: - **Auto**: uses Mean - **Custom**: choose from Mean, Median, Last, First, Min, Max, or Sum **Fill Missing Values** carries the last known value forward to fill gaps and produce a continuous line. Disabled in Raw mode. > [!WARNING] Raw mode on large time ranges > Selecting **Raw** over days or weeks can result in very large data transfers and slow rendering. Use it for short, focused time windows. ### Display | Setting | Range | Default | |---------|-------|---------| | **Show legend** | On / Off | Off | | **Legend position** | Top, Bottom, Left, Right | Top | | **Fill area under lines** | On / Off | Off | | **Fill opacity** | 0 – 1.0 | 0.1 | | **Line width** | 0.5 – 5.0 | 1 | | **Point size** | 0 – 5.0 (0 hides points) | 1.5 | | **Line smoothing** | 0 (sharp) – 0.5 (smooth) | 0.15 | | **Show events** | On / Off | On | --- ## Exporting Data Click the **export icon** in the toolbar to open the export drawer. ### Configuration - **Date range**: defaults to the chart's visible range, or check **Export all data** to export complete history - **Tag selection**: all plotted tags are included by default; uncheck any you don't need, or add tags that aren't in the trend - **Mode**: **Raw** exports every data point as stored; **Resampled** aggregates to regular intervals (1s–1h) with a chosen aggregate function - **Format**: CSV, JSON, or Parquet - **Split into daily files**: creates one file per calendar day, packaged as a ZIP ### Size Limits Koios estimates the export size before starting: | Threshold | Behavior | |-----------|----------| | Under 200 MB | Proceeds normally | | 200 MB – 1 GB | Warning: may temporarily impact system performance | | Over 1 GB | Blocked: narrow the date range or reduce tags | --- ## What's Next - [Trends](https://ai-ops.com/docs/trends/introduction.md): overview and chart navigation - [Traces & Axes](https://ai-ops.com/docs/trends/traces-and-axes.md): add tags and configure multi-axis layouts --- Source: https://ai-ops.com/docs/dashboard/introduction Section: Dashboard # Dashboard The dashboard is the landing page of Koios: a customizable grid of live widgets for monitoring. You can create multiple dashboards, each with its own set of widgets tailored to a specific process, area, or role. ## Managing Dashboards Use the dashboard **selector** at the top of the page to switch between dashboards. The adjacent **three-dots menu** provides options to create a new dashboard, rename the current one, or delete it. To make a dashboard load automatically on login, click the **star icon** next to it in the selector dropdown. A filled yellow star marks your favorite. ## Customize Mode Click **Customize** to enter edit mode. In this mode: - Widgets show drag handles and resize grips - You can **drag** widgets to reposition them on the grid - You can **resize** widgets by dragging the bottom-right corner - Edit, duplicate, and delete icons appear on each widget - The **Add Widget** button becomes available Layout changes are saved automatically. Click **Done** to exit edit mode. ## Adding a Widget In customize mode, click **Add Widget** to open the widget configuration modal: 1. **Choose a widget type** from the grouped dropdown (Tags, Devices, or Models) 2. **Select the entity**: the tag, device, or model the widget will display 3. **Set a title** (optional, defaults to the widget type name) 4. **Configure display settings** using the tabs (varies by widget type) The widget is placed at the first available position on the grid. You can drag it to a different spot after adding. ## Widget Types ### Tag Widgets | Widget | Description | |--------|-------------| | **Tag Value** | Displays a single tag's live value with an optional ring gauge showing where the value falls within its configured range | | **Tag Chart** | Plots one or more tags over time as a live-updating line chart | ### Device Widgets | Widget | Description | |--------|-------------| | **Device Status** | Shows the device's connection state (Running, Stopped, or Failed) with optional error message | | **Device Uptime** | Horizontal status timeline showing running/stopped/failed segments over time | | **Device Execution** | Bar chart of recent scan cycle durations | ### Model Widgets | Widget | Description | |--------|-------------| | **Model Status** | Shows the model's inference state with optional error message | | **Model Uptime** | Horizontal status timeline showing running/stopped/failed segments over time | | **Model Execution** | Bar chart of recent inference cycle durations | ## Widget Configuration Each widget type has its own display settings, accessible when adding or editing a widget. ### Tag Value | Tab | Settings | |-----|----------| | **Text** | Font size (sm / md / lg / xl), font weight, text color (auto or fixed) | | **Ring** | Show ring gauge, ring color, ring size (60–200 px), ring thickness (1–20 px) | | **Labels** | Decimal places override (-1 to 6, or auto from tag config), show units, show tag name | When set to **auto**, text and ring colors follow the tag's live status: teal for running, red for failed, gray for stopped. ### Tag Chart | Tab | Settings | |-----|----------| | **Time** | History period: 5 min, 10 min, 30 min, 1 hour, 8 hours, or 24 hours | | **Line** | Line width, line smoothing, point size | | **Fill** | Fill area under lines, fill opacity | | **Display** | Show X-axis, show Y-axis, show legend, show events (overlays event markers on the time-series chart) | Multiple tags can be added to a single chart widget. Each tag gets a unique color automatically. ### Status Widgets (Device & Model) | Tab | Settings | |-----|----------| | **Text** | Font size, font weight, text color (auto or fixed) | | **Labels** | Show entity name, show error message | Uptime and Execution widgets require only an entity selection, with no additional display settings. ## Editing & Duplicating Widgets In customize mode, click the **gear icon** on a widget to edit its title, entity, or display settings. Click the **copy icon** to duplicate a widget with all its settings. The duplicate is automatically placed at the next available position. ## Grid Layout The dashboard uses a 12-column responsive grid. Widgets snap to grid cells and cannot overlap. On smaller screens the grid reduces to fewer columns (6 on tablets, 4 on large phones, 2 on small phones) and widgets reflow accordingly. ## What's Next - [Trends](https://ai-ops.com/docs/trends/introduction.md): build multi-tag time-series charts for deeper historical analysis. - [Devices](https://ai-ops.com/docs/devices/introduction.md): connect the industrial hardware that feeds your widgets. - [Tags](https://ai-ops.com/docs/tags/introduction.md): define the data points shown in Tag Value and Tag Chart widgets. --- Source: https://ai-ops.com/docs/models/introduction Section: Models # AI Models An **AI model** in Koios runs machine learning inference on live data from your devices. Models read input values from tags, feed them through a pre-trained neural network (ONNX or TensorFlow Lite), and write predictions back to output tags, all in real time, at a configurable scan rate. > [!NOTE] Koios runs models — it does not train them > Koios is an inference engine. You train models externally using your own tools and data, then upload the exported file to Koios for deployment. See [Training a Model](https://ai-ops.com/docs/models/training-a-model.md) for details on this workflow. ## How Models Work On every scan, a model follows this cycle: 1. **Collect**: read current and recent historical values from all input tags 2. **Calibrate**: apply per-binding gain and bias for sensor drift or unit corrections (no-op at defaults) 3. **Normalize**: scale each input to the range the model was trained on 4. **Infer**: run the model file to produce predictions 5. **Denormalize**: scale predictions back to real-world units 6. **Write**: apply inverse calibration and push predictions to output tags This repeats at the model's **scan rate** (e.g. every 1s, 5s, or 30s). Models can also run in [on-demand mode](https://ai-ops.com/docs/models/on-demand-inference.md) for synchronized device reads/writes, or be grouped in a [scan group](https://ai-ops.com/docs/models/scan-groups.md) for batched execution. ## Key Components ### 1. Model File The trained model file (ONNX or TFLite) contains the neural network weights and structure. You can upload multiple versions and switch between them without reconfiguring bindings. | Format | Extension | Description | |--------|-----------|-------------| | **ONNX** | `.onnx` | Open Neural Network Exchange, exported from PyTorch, scikit-learn, etc. | | **TFLite** | `.tflite` | TensorFlow Lite, optimized for edge deployment | ### 2. Bindings Bindings connect the model's inputs and outputs to tags: - **Input bindings** read values from tags and pass them to the model - **Output bindings** receive predictions from the model and optionally write them to tags Every input binding must be assigned to a tag. Output bindings can be left unassigned. ### 3. Normalization Each binding has a normalization setting that controls how values are scaled. The system uses two independent settings: **Normalization type**: the mathematical formula: | Type | Formula | Output Range | |------|---------|-------------| | **None** | Passthrough | Raw values | | **Min-Max** | `(v - min) / (max - min)` | [0, 1] | | **Symmetric** | `2*(v - min)/(max - min) - 1` | [-1, 1] | | **Z-Score** | `(v - mean) / std` | Unbounded | **Normalization source**: where the parameters come from: | Source | Description | |--------|-------------| | **Tag Range** | Uses the tag's configured `range_min` / `range_max` | | **Custom** | Uses custom values set directly on the binding | Z-Score always forces Custom source (tags don't have meaningful mean/std values). > [!TIP] Match your training data > The normalization in Koios should match whatever normalization was used during training. If you trained with min-max scaling using the tag's range, use Tag Range. If you used custom bounds or z-score, use Custom and enter the same values. ### 4. Calibration Each binding can apply a linear gain-and-bias transform on top of the raw value. This is useful for sensor drift, engineering unit conversion, or fine-tuning a model's response without retraining. Defaults are identity (gain `1.0`, bias `0.0`), so existing bindings see no change. See [Calibration (Gain & Bias)](https://ai-ops.com/docs/models/assigning-bindings.md#calibration-gain--bias) for the full pipeline. ### 5. Configuration | Setting | Description | Default | |---------|-------------|---------| | **Output Application** | **Absolute** writes the prediction directly; **Relative** adds the predicted delta to the current tag value | Absolute | | **Output Mode** | **Continuous** maps each output neuron 1:1 to an output binding; **Discrete** selects from an action map via argmax | Continuous | | **Scan Rate** | How often inference runs (seconds) | 1s | | **Sample Rate** | Interval between historical samples in the input tensor (seconds) | 1s | | **On-Demand** | Request fresh device reads before inference, writes after | Off | | **On-Demand Timeout** | Max wait for fresh reads (seconds) | 3s | | **Memory Only** | Store history in process memory instead of the time-series database | Off | | **Scan Group** | Assign to a group for synchronized execution | None | --- ## Memory Only Mode When enabled, the model stores its input history in an **in-memory buffer** instead of querying the time-series database. This eliminates the database read/write round-trip on every cycle, enabling ultra-low-latency inference for fast control loops. **How it works:** The predict engine maintains a rolling buffer per input tag, appending one sample per scan cycle from the live data cache. The model reads from this buffer instead of the database. **Trade-offs:** | Aspect | Standard | Memory Only | |--------|----------|-------------| | Input history source | Time-series database | In-memory buffer | | Execution metrics | Full (charts, missed scans) | Avg cycle duration only | | Data on restart | Persisted | Lost, model warms up from zero | | Latency | Database query per cycle | Near-zero (cache + memory) | **Requirements:** - Requires **On-Demand** to be enabled (the predict engine must actively pull fresh reads) - Cannot be in a **Scan Group** **Warmup:** After a restart, the buffer is empty. The model shows a "Memory buffer warming up" message until it has collected enough samples (determined by `input_depth * sample_rate`). During warmup, inference does not run. > [!NOTE] When to use memory only > Use this for fast control loops (10ms–500ms scan rates) where database latency is the bottleneck. For most models with scan rates above 1 second, standard mode is fine. > [!WARNING] Consider your network latency first > Memory only eliminates the database round-trip, but the on-demand device read still goes over the network. If your device reads take more than 50–100ms (common with remote OPC-UA servers or Modbus devices over WAN), the network round-trip will dominate your cycle time regardless. In that case, standard mode with on-demand is likely sufficient. The database overhead is negligible compared to the device read. Memory only shines when device reads are fast (local PLCs, sub-10ms response) and the database query is the actual bottleneck. --- ## Scan Groups A **scan group** runs multiple models together on a shared schedule. When on-demand is enabled, all member models' reads and writes are combined into a single network request per device, reducing I/O on slow networks. See [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md) for details. --- ## Input Depth and Historical Data Models typically need a **window of historical data**, defined by: - **Input depth**: number of historical samples (read from the model file) - **Sample rate**: time interval between each sample For example, input_depth=10 at sample_rate=0.5s needs the last 5 seconds of data. > [!NOTE] Initialize history for new models > When you first enable a model, use the **Initialize History** action on the overview page to backfill the required data so the model can start immediately. --- ## Model Status | Status | Meaning | |--------|---------| | **Running** | Actively making predictions at its scan rate | | **Stopped** | Disabled or not started | | **Failed** | Error during inference; check error code and message | Each **binding** also has its own status. A binding can fail if the bound tag is disabled, there isn't enough historical data, or the value is outside the normalization range. --- ## Model Lifecycle 1. **Create**: name, output application, output mode, scan rate 2. **Upload a model file**: ONNX or TFLite on the Files tab 3. **Assign bindings**: map inputs and outputs to tags on the Bindings tab 4. **Initialize history**: backfill data if input tags are new 5. **Enable**: activate real-time inference > [!TIP] Input tags must be running > Make sure input tags and their parent devices are enabled and running before enabling the model. --- ## What You See on a Model ### Model List Table with status, name, input/output counts, and timestamps. Supports filtering, search, and bulk actions (enable, disable, delete, export). ### Model Detail | Tab | Content | |-----|---------| | **Overview** | Live status, last prediction, scan progress, active file info, tensor chart, recent events | | **Files** | Upload, manage, and switch model file versions | | **Bindings** | Configure input/output bindings, normalization, failure detection | | **Configuration** | Name, description, output settings, scan rate, sample rate, advanced settings | | **Execution** | Cycle timing charts and performance metrics | | **Logs** | Real-time predict engine log viewer | | **Parameters** | Read-only table of all model fields | | **Cross References** | Tags, components, and other entities referencing this model | --- ## What's Next - [Training a Model](https://ai-ops.com/docs/models/training-a-model.md): what to prepare before deploying a model - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md): tensor shapes and data preparation - [Creating a Model](https://ai-ops.com/docs/models/creating-a-model.md): step-by-step guide - [Managing Model Files](https://ai-ops.com/docs/models/model-files.md): uploading and versioning - [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md): mapping inputs and outputs to tags - [Configuring a Model](https://ai-ops.com/docs/models/configuring-a-model.md): all configuration settings explained - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md): synchronize inference with fresh device data - [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md): grouped execution with shared on-demand - [Monitoring a Model](https://ai-ops.com/docs/models/enabling-a-model.md): live values, diagnostics, and execution performance --- Source: https://ai-ops.com/docs/models/training-a-model Section: Models # Training a Model Koios is an **inference engine**, not a training platform. Its job is to take a model you have already trained and run it continuously against live data from your plant, factory, or building. It reads sensor values, makes predictions, and writes outputs back to control systems in real time. **Training happens externally.** You train your model in whatever environment suits your workflow (Python scripts, Jupyter notebooks, cloud ML platforms, or dedicated training infrastructure). Once you have a trained model, you export it as an ONNX or TFLite file and upload it to Koios. ## What Koios Does | Koios handles | You handle externally | |---------------|----------------------| | Connecting to PLCs, controllers, and sensors | Collecting and curating training datasets | | Reading live tag values at scan rate | Feature engineering and model architecture | | Normalizing inputs to match your training pipeline | Training, validation, and hyperparameter tuning | | Running inference (ONNX Runtime / TFLite) | Exporting to `.onnx` or `.tflite` | | Denormalizing and writing predictions to outputs | Evaluating model accuracy and retraining | | Monitoring model health, uptime, and performance | | ## Collecting Training Data with Koios While Koios does not train models, it can serve as a **data historian**, collecting and storing high-resolution time-series data from your devices that you can then use for training. This is particularly useful if you don't have an existing historian, or if your current historian doesn't provide the resolution you need. Koios records tag values to its time-series database at your configured scan rate, and you can [export that data](https://ai-ops.com/docs/trends/settings-and-export.md#exporting-data) as CSV, JSON, or Parquet from any trend. For long-term data collection, review the [Data Retention](https://ai-ops.com/docs/system/retention.md) settings to ensure your retention and compression policies preserve the resolution your training pipeline requires. ## Typical Workflow ```text Your Environment Koios ────────────── ───── 1. Collect historical data ───► (Koios can serve as your historian) 2. Export data for training ◄─── (Export from Trends as CSV/JSON/Parquet) 3. Train model (PyTorch, TF, sklearn...) 4. Export to .onnx or .tflite ───► 5. Upload model file 6. Assign bindings to tags 7. Configure normalization 8. Enable — inference runs continuously 9. Monitor predictions & retrain as needed ``` ## Preparing Your Model for Koios Your exported model must meet specific tensor shape and format requirements. The key points: - **Input shape:** - `[1, num_inputs]`: flat models that read the *current* sensor snapshot (RL policies, regressors, classifiers) - `[1, input_depth, num_inputs]`: time-series models that consume a window of recent history (forecasters, LSTMs, etc.) - **Output shape:** `[1, num_outputs]` for single-step predictions, or `[1, output_depth, num_outputs]` for multi-step forecasts - **Data type:** float32 - **Formats:** ONNX (`.onnx`) or TensorFlow Lite (`.tflite`) See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md) for the full specification, including tensor layout, interpolation behavior, and normalization details. > [!TIP] Test before uploading > Run a quick inference locally with a dummy input of the expected shape before uploading to Koios. This catches shape mismatches and export issues early. > [!WARNING] Export to a supported ONNX version > Koios loads ONNX files up to **IR version 13**. Very recent export toolchains can target a higher IR version, which Koios rejects at upload. Export at IR 13 or lower, or annotate the model with the Koios model-utils library, which clamps the IR version to a safe value for you. TFLite files are unaffected. ## Normalization Must Match Training The normalization you configure in Koios (on each binding) must match what was used during training. If your training pipeline scaled inputs with min-max normalization using specific bounds, configure the same type and bounds in Koios. A mismatch means the model receives inputs in a different range than it was trained on, producing meaningless predictions. See [AI Models: Normalization](https://ai-ops.com/docs/models/introduction.md#3-normalization) for the available normalization types and sources. ## Retraining and Updating When you retrain a model, export a new file and upload it as a new version on the [Files](https://ai-ops.com/docs/models/model-files.md) tab. Koios supports multiple file versions per model. You can switch between them without reconfiguring bindings, as long as the input/output count stays the same. This supports A/B testing: upload the new version, activate it, monitor performance, and roll back if needed. > [!NOTE] Embedded metadata for automation > ONNX files can include Koios-specific metadata that auto-configures normalization, sample rate, and binding names on upload. This reduces manual setup when deploying from a training pipeline. See [Embedded Metadata](https://ai-ops.com/docs/models/model-files.md#embedded-metadata). ## What's Next - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md): the full tensor shape, layout, interpolation, and normalization spec your exported model must meet. - [Creating a Model](https://ai-ops.com/docs/models/creating-a-model.md): register your trained model in Koios and upload its file. ## Need Help with Training? If you need a bespoke model trained for your specific process or application, **Ai-Ops can help**. Our team can work with your data to develop, validate, and deploy custom models tailored to your site. Contact us at [support@ai-ops.com](mailto:support@ai-ops.com) for a quote. > [!NOTE] Ronin: Ai-Ops training platform > **Ronin**, our dedicated model training platform, is currently in beta development. Ronin will provide an integrated workflow for building and deploying models directly to Koios. Stay tuned for updates. --- Source: https://ai-ops.com/docs/models/inference-requirements Section: Models # Model Inference Requirements This page explains how Koios prepares data for your model and what shape your exported model file needs to be. Koios is an inference engine. Models must be [trained externally](https://ai-ops.com/docs/models/training-a-model.md) and exported as ONNX or TFLite. ## Input Tensor Shape Koios supports two input shapes. Pick the one that matches how your model was trained: | Shape | Rank | Label in UI | Use Case | |-------|------|------|----------| | `[1, num_inputs]` | 2 | **Flat** (depth 1) | Single-step models (RL policies, simple regressors, classifiers reading the *current* sensor snapshot only) | | `[1, input_depth, num_inputs]` | 3 | **Time-series** (depth > 1) | Models that consume a window of recent history (forecasters, LSTMs, transformers, time-series classifiers) | Koios detects the shape from the model graph at upload time and validates it against the model's embedded metadata. Model list and detail pages label each model as "5 inputs, depth 1" (flat) or "5 inputs, depth 6" (time-series), so the list shows the input count and depth for each model. In both shapes: - **Batch size is always 1.** - **`num_inputs`** is the number of input features, one per input binding. - **`input_depth`** (rank-3 only) is the number of historical time steps Koios queries per scan. ### Flat models (rank-2) A flat model reads three input tags as a single row: ```text Binding 1 Binding 2 Binding 3 Supply Temp °C Return Temp °C Fan Speed % (normalized) (normalized) (normalized) ┌─────────────────────────────────────────────────┐ current │ 0.47 0.60 0.83 │ └─────────────────────────────────────────────────┘ Shape: [1, 3] No time dimension — just the most recent sample per binding. ``` ### Time-series models (rank-3) A time-series model reading the same three tags with input depth 6 and sample rate 10s: ```text Binding 1 Binding 2 Binding 3 Supply Temp °C Return Temp °C Fan Speed % (normalized) (normalized) (normalized) ┌─────────────────────────────────────────────────┐ t₀ (oldest) │ 0.42 0.65 0.80 │ t₁ (-40s) │ 0.43 0.64 0.80 │ t₂ (-30s) │ 0.45 0.63 0.81 │ t₃ (-20s) │ 0.44 0.62 0.79 │ t₄ (-10s) │ 0.46 0.61 0.82 │ t₅ (newest) │ 0.47 0.60 0.83 │ └─────────────────────────────────────────────────┘ Shape: [1, 6, 3] Time flows top → bottom. Columns ordered by binding order. ``` ### Key Rules - **Batch size is always 1** - **Time flows forward** in rank-3: row 0 is oldest, last row is newest - **Columns match binding order**: binding 1 is column 0, binding 2 is column 1, etc. - **Values are normalized** (unless using "None" normalization) - **Input shape is fixed**: read from your model file and cannot be changed after upload --- ## Data Preparation Pipeline On every scan, Koios: 1. **Query**: fetch historical data for each input tag covering `input_depth × sample_rate` seconds 2. **Interpolate**: resample to an evenly-spaced time grid using PCHIP interpolation (monotone cubic, no artificial peaks) 3. **Normalize**: scale each value using the binding's normalization type and source 4. **Assemble**: stack columns by binding order, wrap in batch dimension → `[1, input_depth, num_inputs]` > [!NOTE] At least 2 data points required > Interpolation needs at least 2 raw data points. If a tag is new, use **Initialize History** on the model overview page. When a binding won't run because of a shape mismatch or too little history, see [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) to diagnose it. --- ## Output Tensor Shape Three output shapes are supported: | Shape | Use Case | |-------|----------| | `[]` or `[1]` | Single prediction → output binding 1 | | `[1, num_outputs]` | One prediction per output binding | | `[1, output_depth, num_outputs]` | Multi-step forecast: each binding's **output index** selects which time step to use | --- ## Model File Requirements | Format | Extension | Runtime | |--------|-----------|---------| | **ONNX** | `.onnx` | ONNX Runtime (CPU) | | **TFLite** | `.tflite` | TFLite Runtime (CPU) | ### What Koios Reads from Your File | Property | Used For | |----------|----------| | **num_inputs** | Number of input bindings to create | | **num_outputs** | Number of output bindings to create | | **input_depth** | Historical samples queried per scan | | **output_depth** | Future time steps the model predicts | ### Shape Convention Koios accepts two input shapes: - **Flat:** `[batch_size, features]`. No time dimension; used by single-step models (RL policies, regressors, classifiers) - **Time-series:** `[batch_size, time_steps, features]`. Time/depth dimension must be static - **Output:** `[batch, time, features]`, `[batch, features]`, or scalar - **Data type:** float32 - **ONNX:** batch dimension can be dynamic; time dimension must be static - **TFLite:** input must have at least 2 dimensions > [!WARNING] Test your model file before uploading > Run a quick inference locally with a dummy input of the expected shape before uploading to Koios. --- ## Quick Reference | Concept | Value | |---------|-------| | Flat input shape | `[1, num_inputs]` | | Time-series input shape | `[1, input_depth, num_inputs]` | | Time direction | Oldest first → newest last (rank-3 only) | | Interpolation | PCHIP (monotone cubic Hermite) | | Min data points | 2 per input tag (rank-3); 1 (rank-2) | | Data type | float32 | | Batch size | Always 1 | | Binding order | 1-based (binding 1 → column 0) | | Output index | 1-based (step 1 → array index 0) | --- Source: https://ai-ops.com/docs/models/creating-a-model Section: Models # Creating a Model Models are created from the **Models** list page. You provide a name and optionally upload a model file in the same step. ## Create Model Dialog Click **Add Model** in the top-right corner to open the create dialog. | Field | Required | Description | |-------|----------|-------------| | **Name** | Yes | A unique name for the model | | **Description** | No | Optional notes about the model's purpose | | **Model File** | No | An ONNX (`.onnx`) or TFLite (`.tflite`) file to upload immediately | If you select a model file, two additional fields appear: | Field | Required | Description | |-------|----------|-------------| | **Version** | No | A version label (e.g. `1.0.0` or `v2-beta`). If left blank, an auto-generated name like `warm-fox-12` is assigned. | | **Notes** | No | Optional notes about this file version | The button label changes to **Create & Upload** when a file is attached. ## What Gets Set Automatically The create dialog only asks for the essentials. All other settings start with sensible defaults and can be changed on the **Configuration** tab after creation: | Setting | Default | |---------|---------| | Output Application | Absolute | | Output Mode | Continuous | | Scan Rate | 1s | | Sample Rate | 1s | | Enabled | Off | ## After Creation Where you land depends on whether you included a file: - **Without a file**: you're taken to the model's **Files** tab so you can upload one - **With a file**: the file is uploaded and activated automatically, then you're taken to the **Configuration** tab If the model was created but the file upload fails (network issue, invalid file), an alert explains that the model exists and you can upload later from the Files tab. > [!NOTE] Embedded metadata > If your ONNX file contains embedded Koios metadata (`koios.training` and `koios.bindings` properties), those values are automatically applied to the model's configuration and bindings on the first upload. See [Embedded Metadata](https://ai-ops.com/docs/models/model-files.md#embedded-metadata) for details. ## Next Steps After creation, a model needs three things before it can run: 1. **An active model file**: uploaded during creation or added on the [Files](https://ai-ops.com/docs/models/model-files.md#uploading-a-file) tab 2. **Bindings assigned to tags**: see [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md) 3. **Enable the model**: toggle Enabled in the model header or Configuration tab ## Duplicating a Model To create a copy of an existing model, open the model's detail page, click the **three-dot menu** in the header, and select **Duplicate**. Enter a new name and the model is cloned with all its configuration. You'll be taken to the new model's Configuration tab. > [!TIP] Review output tag assignments > Duplicating a model copies configuration settings and model files. Input tag assignments are copied, but output tag assignments are cleared. You'll need to assign output tags on the new model's Bindings tab. --- Source: https://ai-ops.com/docs/models/model-files Section: Models # Managing Model Files Model files contain the pre-trained neural network weights and structure that Koios uses for inference. Models must be [trained externally](https://ai-ops.com/docs/models/training-a-model.md) and exported as ONNX or TFLite before uploading. Each model can have multiple file versions, but only one is **active** at a time. ## Supported Formats | Format | Extension | Notes | |--------|-----------|-------| | **ONNX** | `.onnx` | Must not use external data files. Batch dimension can be dynamic; time/depth dimension must be static. IR version must be 13 or lower. | | **TFLite** | `.tflite` | Must have at least 2 dimensions (batch and depth). | Both formats must use **float32** data type. --- ## Uploading a File Open the model's **Files** tab and click **Upload New File**. | Field | Required | Description | |-------|----------|-------------| | **File** | Yes | Drag and drop or click to select an `.onnx` or `.tflite` file | | **Version** | No | A label like `1.0.0` or `v2-beta`. Auto-generated if left blank (e.g. `warm-fox-12`). Must be unique per model. | | **Notes** | No | Optional notes about this version | ### What Happens During Upload Koios validates the file and extracts: | Property | Description | |----------|-------------| | **num_inputs** | Number of input features (creates one input binding per feature) | | **num_outputs** | Number of output features (creates one output binding per feature) | | **input_depth** | Number of historical time steps the model expects | | **output_depth** | Number of future time steps the model predicts (1 for single-step models) | If this is the model's **first file**, it is automatically activated and bindings are created. For subsequent uploads, you choose when to activate. --- ## Activating a File When you upload a second or later file, Koios shows a post-upload step before activation: ### Activation Preview Before activating, Koios shows what will change: - **Binding changes**: if the new file has a different number of inputs or outputs, bindings will be added or removed. Existing bindings (and their tag assignments) are preserved where the binding order matches. - **Action map diff** (discrete models only): if the new file's action map differs from the current one, you can choose to keep the current map or use the new file's map. - **Metadata preview**: if the file contains embedded metadata, a summary shows what will be applied (see [Embedded Metadata](#embedded-metadata) below). You can toggle this on or off. Click **Set as Active** to activate, or **Close** to keep the current file active and activate later. ### Activating Later From the file version history on the Files tab, click the **Set Active** button on any inactive file. You'll see the same activation preview before confirming. ### Binding Review After activation, a review step lets you verify and edit binding names and descriptions. Named bindings enable fuzzy tag matching recommendations, so it's worth filling these in. --- ## File Version History The Files tab shows all uploaded versions in a timeline, newest first. The active file is marked with a checkmark and an **Active** badge. Each version shows: - Version label and filename - Input/output counts and input depth - Creation timestamp - Action count (for discrete models) ### Actions per File | Action | Description | |--------|-------------| | **Set Active** | Activate this file (not shown on the currently active file) | | **View** | Open the file's detail page with structure visualization and metadata | | **Download** | Download the original file | | **Edit** | Change the version label or notes | | **Delete** | Remove this version (disabled for the active file) | --- ## Embedded Metadata ONNX files can include Koios-specific metadata that is automatically applied to the model's configuration and bindings. This reduces manual setup, which is especially useful when deploying models from a training pipeline. > [!NOTE] Evolving feature > Embedded metadata support is functional but still being expanded. The properties described below are supported today. Additional metadata fields and tooling for embedding them during training are planned. ### How It Works Metadata is stored as custom properties in the ONNX file's `metadata_props`, using keys prefixed with `koios.`. When a file with metadata is uploaded: - **First file:** metadata is applied automatically - **Subsequent files:** you can toggle "Apply metadata from this file" during activation ### Training Metadata (`koios.training`) Applied to the model's configuration: | Key | Applied To | |-----|-----------| | `sample_rate` | Model's sample rate and scan rate | | `model_type` | Output application (Absolute / Relative) | | `output_mode` | Output mode (Continuous / Discrete) | | `action_map` | Action map on the model file (discrete models) | ### Binding Metadata (`koios.bindings`) Applied to each binding by binding order: | Key | Applied To | |-----|-----------| | `name`, `description` | Binding name and description | | `normalization_type` | Normalization type (None / Min-Max / Symmetric / Z-Score) | | `normalization_source` | Normalization source (Tag Range / Custom) | | `custom_minimum`, `custom_maximum` | Custom normalization bounds | | `custom_mean`, `custom_std` | Custom Z-Score parameters | | `range_min`, `range_max` | Failure range bounds | ### Reset from Metadata If a model has an active file with embedded metadata, you can re-apply it at any time using the **Reset from Metadata** action on the model's overview page. This updates configuration and binding settings from the metadata without affecting tag assignments. ### Viewing Metadata Open the file's detail page (click **View** on any file version) and go to the **Metadata** tab to see the raw training and binding metadata extracted from the file. --- ## File Detail Page Each file version has its own detail page with: | Tab | Content | |-----|---------| | **Overview** | Input depth, output depth, creation date. For discrete models, the action map editor. | | **Visualize** | Interactive network graph of the model structure (rendered via Netron) | | **Metadata** | Training info and binding metadata extracted from the file (ONNX only) | --- ## What's Next - [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md): connect model inputs and outputs to tags - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md): tensor shape requirements and data preparation --- Source: https://ai-ops.com/docs/models/assigning-bindings Section: Models # Assigning Bindings ## What Are Bindings? Bindings connect your AI model to live data. Every model has **inputs** (data the model reads) and **outputs** (predictions the model writes). Bindings map each input and output to a **tag**, a live data point collected from a connected device. Without bindings, the model has no data to process and nowhere to write its results. Once bindings are assigned and configured, the Predict Engine automatically feeds live tag values into the model at each scan cycle and writes the model's predictions back to the output tags. ```text Tags (live data) Model Tags (predictions) ┌──────────────────┐ ┌───────────┐ ┌──────────────────────┐ │ Temperature ────│───►│ │───►│ Predicted Failure │ │ Pressure ────│───►│ ONNX │───►│ Recommended Action │ │ Flow Rate ────│───►│ Model │ └──────────────────────┘ │ Vibration ────│───►│ │ └──────────────────┘ └───────────┘ Input Bindings Output Bindings ``` ### How the Predict Engine Uses Bindings At each scan cycle, the Predict Engine: 1. **Reads** the recent history of each input tag (the number of samples depends on the model's `sample_rate` configuration) 2. **Calibrates** each value by applying the binding's gain and bias (no-op when both are at defaults) 3. **Normalizes** each value according to the binding's scaling configuration (e.g., Min-Max scales to 0–1) 4. **Runs inference**: feeds the normalized input history through the model 5. **Denormalizes** each output back to real-world units 6. **Calibrates inversely** on outputs to convert from model space back to engineering units 7. **Writes** the result to each output tag 8. **Validates** that input values are within expected ranges (failure detection) This happens automatically and continuously once the model is enabled. --- ## The Bindings Tab Navigate to a model's detail page and select the **Bindings** tab. The tab displays a two-column layout: - **Left column**: Input bindings (data the model reads) - **Right column**: Output bindings (predictions the model writes) Each binding appears as a card showing: - **Binding order number**: the position in the model's input or output array - **Tag name**: the assigned tag, or "Unassigned" if no tag is linked - **Live values**: for inputs, the raw tag value and its normalized model input; for outputs, the model's raw output and the denormalized tag value - **Failure bounds**: the expected value range for failure detection - **Status indicator**: running, stopped, error, or unassigned > [!NOTE] Bindings are created automatically > When you upload a model file, Koios reads the model's input and output dimensions and creates the corresponding bindings automatically. You don't create bindings manually. You assign tags to them. --- ## Assigning a Tag Click any binding card to open its configuration drawer. The **Tag** section at the top contains a tag picker where you assign which tag feeds data into (or receives data from) this binding. 1. Click the binding card to open the drawer 2. In the **Tag** section, use the tag picker to search and select a tag 3. The binding saves automatically when you close the drawer For **output bindings**, the tag picker only shows writable tags, tags configured with output usage that can accept written values. > [!WARNING] Assign all input bindings > A warning appears on the Bindings tab if any input bindings are unassigned. The model cannot run inference correctly with missing inputs. ### Training Metadata If the model file includes training metadata (embedded via `koios-model-utils`), each binding may show a **"From training"** info box. This displays the binding's original name and description from training, helping you match bindings to the correct tags. For example, a binding named `temperature_sensor_1` tells you which physical measurement it expects. --- ## Scaling (Normalization) Most ML models expect inputs in a specific numeric range (e.g., 0 to 1, or -1 to 1). Raw tag values like temperature (20–200) or pressure (0–500) need to be scaled before the model can process them. The **Scaling** section configures this transformation. ### Scaling Methods | Method | Formula | Output Range | Use Case | |--------|---------|--------------|----------| | **None** | No transformation | Raw values | Model trained on raw data | | **Min-Max** | (value - min) / (max - min) | 0 to 1 | Most common for neural networks | | **Symmetric** | 2 * (value - min) / (max - min) - 1 | -1 to 1 | Models using tanh activation | | **Z-Score** | (value - mean) / std | Centered at 0 | Standardized features | ### Parameter Source When using Min-Max or Symmetric scaling, you choose where the min/max parameters come from: - **Tag Range**: Uses the `rangeMin` and `rangeMax` configured on the assigned tag. This is convenient when your tag ranges already match the training data ranges. - **Custom**: You provide explicit minimum and maximum values. Use this when the tag range doesn't match what the model was trained on. > [!TIP] Z-Score always uses Custom > Z-Score normalization requires a mean and standard deviation, which cannot be derived from a tag's range. When you select Z-Score, the source is automatically set to Custom and you enter the mean and standard deviation values. ### Clamp Output For **output bindings**, an optional **Clamp Output** toggle constrains the model's prediction to the binding's configured range. When enabled, if the model produces a value outside the normalization bounds, it is clamped to the minimum or maximum before being written to the tag. This prevents unexpected extreme values from reaching the output device. ### Output Index For models that forecast multiple future time steps (output depth > 1), each output binding has an **Output Index** setting (1-based) that selects which time step to use as its prediction. For example, if a model outputs 12 future steps and you only care about step 12, set the output index to 12. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md#output-tensor-shape) for details on multi-step output shapes. --- ## Calibration (Gain & Bias) Every binding can apply a linear transform on top of the raw value. The Scaling tab exposes two fields: | Field | Default | Description | |---|---|---| | **Gain** | `1.0` | Multiplier applied to the value. Cannot be zero. | | **Bias** | `0.0` | Offset added after the gain. | Use calibration to correct sensor drift, convert engineering units, or fine-tune a model's response, without retraining or re-uploading the model file. Both values are non-nullable and default to the identity transform, so existing bindings see no change after upgrading to v1.1.0. ### How Calibration Is Applied **Input bindings:** ```text calibrated_value = (raw_tag_value × gain) + bias ``` Calibration runs **before** range checks, rate-of-change detection, and normalization, so every downstream check operates in the calibrated value space. If your gain or bias is non-default, the normalization source is automatically set to **Custom**. The tag's native range no longer matches what the model sees. **Output bindings (inverse):** ```text tag_value = (denormalized_model_output − bias) / gain ``` Calibration is the final step before the value is written back to the tag. > [!TIP] When to use calibration vs normalization > Use **normalization** to match the value range the model was trained on. Use **calibration** for physical-world adjustments: a sensor that reads 2°C low, a transducer with a 0.98 scale factor, a setpoint that needs to be offset by 5 units. The two are independent and compose cleanly. --- ## Failure Detection Failure detection monitors whether input values fall outside expected bounds. If an input is out of range, it may indicate a sensor fault, a disconnected device, or abnormal process conditions, any of which could cause the model to produce unreliable predictions. ### Failure Range Mode | Mode | Behavior | |------|----------| | **Disabled** | No range checking performed | | **Normalization Range** | Uses the same min/max bounds configured in the Scaling section | | **Custom** | You provide separate minimum and maximum failure bounds | ### Failure Evaluation When the model uses interpolated samples (multiple data points per scan), this setting controls how samples are evaluated against the failure bounds: | Evaluation | Behavior | |------------|----------| | **Any** | Fails if any single sample is out of range | | **Latest** | Only checks the most recent sample | | **Average** | Checks the average of all samples | ### Failure Debounce The debounce count prevents transient spikes from triggering failures. Set the number of **consecutive** scans that must fail before the binding enters a failure state. A value of 0 means failure triggers immediately on the first out-of-range scan. ### Recovery Hysteresis Once a binding enters a failure state, it doesn't recover the instant values return within bounds. The hysteresis percentage defines how far **inside** the range values must return before the binding recovers. This prevents rapid toggling between failed and healthy states when values hover near the boundary. For example, with a range of 0–100 and 5% hysteresis, a failed binding only recovers when the value drops below 95 (or rises above 5). --- ## Rate of Change Detection Rate of Change (ROC) detection flags values that are changing too quickly, which can indicate equipment malfunction, sudden process upsets, or noisy sensors even when the value itself is within the normal range. | Setting | Description | |---------|-------------| | **ROC Enabled** | Toggle rate-of-change detection on or off | | **ROC Threshold** | Maximum allowed change per minute | | **Threshold Mode** | Express the threshold in raw units per minute or as a percentage of the normalization range per minute | | **Direction** | Detect rising changes, falling changes, or both | | **ROC Window** | Time window (in seconds) over which the rate of change is calculated | --- ## Stale Data Detection The **Allowed Missed Samples** setting controls how many consecutive scan cycles a tag can miss (produce no new data) before the binding is flagged as stale. This protects against situations where a device disconnects or a tag stops updating. The model would otherwise keep using the last known value indefinitely. --- ## Binding Name and Description Each binding has an editable **name** and **description** visible at the top of the configuration drawer. Click either field to edit it inline. If the model file included training metadata, the name and description are auto-populated from the metadata. These fields are for your reference only. They help you identify which physical measurement or prediction each binding represents. They do not affect how the Predict Engine processes the binding. --- ## Typical Workflow 1. **Upload a model file**: bindings are created automatically from the model's input/output dimensions 2. **Review training metadata**: if present, use the binding names to understand what each input/output expects 3. **Assign tags**: click each binding and select the appropriate tag 4. **Configure scaling**: set the normalization method and parameters to match how the model was trained 5. **Set failure detection**: define acceptable ranges to catch sensor faults or abnormal data 6. **Enable the model**: once all bindings are assigned and configured, enable the model to start inference > [!TIP] Match your training configuration > The scaling method and parameters must match how the model was trained. If the model was trained with Min-Max normalization using a range of 0–500 for a pressure input, configure that binding with Min-Max scaling and Custom source with minimum 0 and maximum 500. --- ## What's Next - [Configuring a Model](https://ai-ops.com/docs/models/configuring-a-model.md): scan rate, sample rate, on-demand, and other model settings - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md): synchronize inference with fresh device data - [Monitoring a Model](https://ai-ops.com/docs/models/enabling-a-model.md): live values, diagnostics, execution performance, and trends - [Managing Model Files](https://ai-ops.com/docs/models/model-files.md#embedded-metadata): embedded metadata that auto-populates binding settings --- Source: https://ai-ops.com/docs/models/configuring-a-model Section: Models # Configuring a Model After creating a model and uploading a file, use the **Configuration** tab on the model's detail page to adjust settings. The tab has two sections: **General Configuration** and **Advanced Configuration**. A third section, **Action Map**, appears when the model uses discrete output mode. Each section saves independently. Make your changes and click the section's save button. --- ## General Configuration ### Model Name A unique name for the model. Required. ### Description Optional free-text notes about the model's purpose. ### Output Application Controls how predictions are applied to output tags. | Option | Behavior | |--------|----------| | **Absolute** | Writes the predicted value directly to the output tag | | **Relative** | Adds the predicted delta to the tag's current value. Used for closed-loop control where the model outputs incremental adjustments | ### Output Mode Controls how the model's raw output tensor is interpreted. | Option | Behavior | |--------|----------| | **Continuous** | Each output neuron maps 1:1 to an output binding. Used with algorithms like PPO and SAC. | | **Discrete** | Outputs are treated as Q-values. The argmax selects a discrete action from the [action map](#action-map). Used with DQN. | > [!WARNING] Changing output mode rebuilds bindings > Switching between Continuous and Discrete removes existing output bindings and creates new ones. Tag assignments on output bindings will be lost. A confirmation dialog explains the impact before the change is applied. ### Scan Group Optionally assign the model to a [scan group](https://ai-ops.com/docs/models/scan-groups.md) for synchronized execution with other models. The dropdown shows each scan group's status and scan rate. When a scan group is assigned: - **Scan Rate** is disabled, controlled by the group - **On-Demand** and **On-Demand Timeout** in Advanced are disabled, controlled by the group Select "No scan group" to remove the assignment. ### Scan Rate and Sample Rate Scan rate controls **how often** the model runs inference; sample rate controls **the spacing of historical data points** in the input tensor. - **Scan Rate**: accepts values down to 10ms with multiple time units (milliseconds, seconds, minutes, hours) - **Sample Rate**: for example, a model with input depth 10 and sample rate 5s needs the last 50 seconds of data, resampled to 10 evenly-spaced points 5 seconds apart For nearly every forecasting model these two values are the same, so the form **links them by default**. A chain icon between the two fields shows the link state. Edit one and the other follows. Click the chain to unlink them and edit independently; this is the right choice for controllers that need to react faster than the training data was sampled at (e.g. `sample_rate=1.0` history lookback with `scan_rate=0.1` execution). When a scan group is assigned, the chain is hidden: - **Scan Rate** is disabled, controlled by the group - **Sample Rate** remains editable (it's a per-model setting) --- ## Action Map This section only appears when **Output Mode** is set to **Discrete**. In discrete mode, the model outputs Q-values for each possible action. The action with the highest Q-value is selected, and its mapped value is written to the output tag. The action map is configured **per file** rather than per model, since different model files may define different action sets. The Configuration tab shows a link to the active file's detail page where the map is edited. On the file detail page, the action map editor is a table: | Column | Description | |--------|-------------| | **Index** | The action index (read-only, sequential) | | **Value** | The engineering value written to the output tag when this action is selected | | **Label** | Optional descriptive label (e.g. "Decrease", "Hold", "Increase") | You can add and remove actions. The number of actions should match the model's output count. When [activating a new file](https://ai-ops.com/docs/models/model-files.md#activating-a-file), you can choose to copy the current action map to the new file or use the new file's embedded map. --- ## Advanced Configuration ### On-Demand When enabled, the model requests fresh device reads before each inference cycle and triggers immediate writes after. This synchronizes the model with its devices, eliminating stale data from independent scan cycles. For details on how the on-demand cycle works, device-side settings, and when to use it, see [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md). When a scan group is assigned, this field is disabled and controlled by the group. ### On-Demand Timeout The maximum time (0.5–30 seconds) to wait for a fresh device read before the model fails the scan. If the timeout expires, no inference runs. This prevents the model from silently predicting on stale data. Start with 5 seconds and increase if you see timeout errors. Devices on slow networks or with many tags may need 10–15 seconds. When a scan group is assigned, this field is disabled and controlled by the group. ### Memory Only When enabled, the model stores its input history in process memory instead of the time-series database. This eliminates the database round-trip on every cycle, enabling ultra-low-latency inference. **Key behaviors:** - Automatically enables **On-Demand** (required: the model must actively pull fresh reads) - Removes any **Scan Group** assignment on save (memory-only models cannot be grouped) - History is lost on service restart. The model warms up its buffer before predictions begin For a full explanation of trade-offs and when to use this, see [Memory Only Mode](https://ai-ops.com/docs/models/introduction.md#memory-only-mode). --- ## Settings Affected by Scan Groups When a model belongs to a scan group, several settings are controlled by the group and disabled in the model's configuration: | Setting | When Grouped | |---------|-------------| | Scan Rate | Shows the group's scan rate (disabled) | | On-Demand | Shows the group's on-demand state (disabled) | | On-Demand Timeout | Shows the group's timeout (disabled) | | Memory Only | Disabled (incompatible with scan groups) | | Sample Rate | Still editable (per-model setting) | The disabled fields display a note indicating which scan group controls them and the current value. --- ## What's Next - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md): full on-demand cycle and when to use it - [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md): synchronized multi-model execution - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md): tensor shapes and sample rate details - [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md): connect model inputs and outputs to tags --- Source: https://ai-ops.com/docs/models/on-demand-inference Section: Models # On-Demand Inference By default, devices and models run on **independent scan cycles**. The model reads whatever value is currently in the cache, which may be anywhere from 0 to `scan_rate` seconds old. **On-demand inference** synchronizes the model's cycle with its devices. Before running inference, Koios requests fresh reads from all input devices and waits for the data. After inference, it triggers immediate writes to all output devices. --- ## The Timing Problem When device and model scan rates are similar (e.g. both 30s), the model may consistently predict on stale data depending on when each service started: ```text Device reads: ┃ ┃ ┃ t=0 t=30 t=60 Model infers: ┃ ┃ t=12 t=42 ▲ ▲ Data is 12s Data is 12s old ``` The offset is unpredictable and can be anywhere from 0 to a full scan cycle. With on-demand enabled, the model **triggers** a fresh read before each inference and writes outputs immediately after: ```text Model wakes → Request read → Device polled → Infer on fresh data → Write outputs ``` --- ## The On-Demand Cycle 1. **Model wakes up** at its configured scan rate 2. **Request fresh reads** from all devices with bound input tags 3. **Wait** until all input values are newer than the start of this cycle, or until the timeout expires 4. **Inference**: read fresh values, run model, produce predictions 5. **Request writes**: push prediction values to output devices immediately If the timeout expires before fresh data arrives, the model **fails the scan** rather than predicting on stale data. --- ## When to Use On-Demand | Use On-Demand | Skip On-Demand | |---------------|----------------| | Device scan rate similar to model scan rate | Device scans 10x+ faster than model (cache always fresh) | | Model writes control outputs to PLCs | Model only produces dashboard/alert predictions | | Freshness directly affects prediction quality | Data changes slowly relative to scan rates | | Multiple models share a device (see [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md)) | — | **Rule of thumb:** If your device scan rate is 10x faster than your model scan rate, you don't need on-demand. If the rates are similar, or if the model writes control outputs, on-demand is strongly recommended. > [!TIP] On-demand lets you slow down device polling > With on-demand, the device only needs to be polled when a model needs data. You can increase the device's scan rate to reduce load. The model triggers reads on its own schedule. --- ## Configuration On-demand involves settings on **both the model and the device**. ### Model Settings Found on the model's **Configuration** tab under **Advanced Configuration**. | Setting | Description | Default | Range | |---------|-------------|---------|-------| | **On-Demand** | Enable on-demand inference | Off | — | | **On-Demand Timeout** | Max wait for a fresh device read before failing | 3s | 0.5–30s | Start with 3 seconds and increase if you see timeout errors. Devices on slow networks may need 10–15 seconds. ### Device Settings Found on the device's **Configuration** tab under **Advanced Configuration**. | Setting | Description | Default | |---------|-------------|---------| | **On-Demand Freshness** | Max age of cached data before a fresh read is required | 0s | | **On-Demand Batch Window** | Time to wait before executing, batching concurrent requests | 0s | For detailed explanations of each setting, see [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md#settings-reference). --- ## Scan Groups and On-Demand When multiple models share devices, individual on-demand requests can multiply network I/O. A **scan group** solves this by running models together and combining all reads into a single request per device. See [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md) for details. --- ## Troubleshooting | Problem | Cause | Solution | |---------|-------|----------| | Model fails with timeout | Device slow or offline | Increase timeout; check device status | | On-demand reads seem slow | High batch window on device | Reduce batch window if only one model uses the device | | Data still seems stale | On-demand not enabled, or freshness too high | Verify on-demand is on; reduce device freshness setting | --- Source: https://ai-ops.com/docs/models/scan-groups Section: Models # Scan Groups A **scan group** runs multiple AI models together on a shared schedule. All member models execute in the same inference cycle, and when on-demand mode is enabled, their device reads and writes are consolidated into a single batched request per device. The primary benefit is efficiency on slow industrial networks. Instead of each model independently issuing its own on-demand read, the scan group computes the union of all tag IDs needed by every member model and requests them in one round-trip. ```text Without scan groups — each model reads independently Model A fires: read tags A,B,C from Device 1 (round-trip 1) Model B fires: read tags B,D,E from Device 1 (round-trip 2) Model C fires: read tags A,F,G from Device 1 (round-trip 3) With a scan group — one shared read Scan group fires: Union of all tags: {A,B,C,D,E,F,G} Single read from Device 1 (round-trip 1) All 3 models infer in parallel Single write of all outputs to Device 1 ``` --- ## How a Scan Group Executes When the group's timer fires: 1. **Collect member models**: all enabled models in the group with valid bindings and model files 2. **Gather tag IDs**: union of all input and output tag IDs across every member model 3. **On-demand read** (if enabled): single batched read of all gathered tags; wait for fresh values 4. **Run inference**: each member model executes concurrently 5. **On-demand write** (if enabled): single batched write of all output tags 6. **Record timing**: per-cycle metrics (total time, read time, inference time, write time) If the on-demand read times out (step 3), the entire cycle fails. No inference runs and no writes are triggered. --- ## Creating a Scan Group 1. Navigate to **Models > Scan Groups** in the sidebar 2. Click **Create Scan Group** 3. Enter a name, optional description, and scan rate 4. Toggle **On-Demand** if you want synchronized reads and writes 5. Click **Create** The scan group starts disabled. Add models to it and enable it when ready. ### Adding Models On the scan group's detail page, go to the **Models** tab, click **Add Models**, and select from ungrouped models. A model can only belong to one scan group at a time. > [!WARNING] Memory-only models cannot join a scan group > Models with the memory-only option store history in process memory and are incompatible with scan groups. --- ## Settings ### General | Setting | Description | Default | Range | |---------|-------------|---------|-------| | **Name** | Unique name | — | Max 128 chars | | **Description** | Optional notes | — | Max 256 chars | | **Scan Rate** | How often the group runs (seconds) | 30s | 0.01–3,600s | ### Advanced | Setting | Description | Default | Range | |---------|-------------|---------|-------| | **On-Demand** | Synchronized reads before inference, writes after | Off | — | | **On-Demand Timeout** | Max wait for fresh device reads before cycle fails | 3s | 0.5–30s | | **Log Level** | Verbosity of predict engine logs for this group | INFO | DEBUG / INFO / WARNING / ERROR | > [!NOTE] Group settings override model settings > When a model belongs to a scan group, the group's scan rate, on-demand, and on-demand timeout override the model's own values. The model's individual settings are disabled in the UI. --- ## On-Demand Mode in Scan Groups When on-demand is enabled, the cycle coordinates with the datacollector: - **Before inference**: the group collects every input and output tag ID across all member models and sends a single on-demand read request. The datacollector groups those tags by device and performs one network read per device. - **After inference**: the group sends a single on-demand write request covering all output tags from models that succeeded. ### Shared Timeout The timeout applies to the combined read covering all devices. Set it high enough for your slowest device. If your scan group includes a fast local device (100ms response) and a slow remote device (2–3s response), the timeout must accommodate the slowest. ### When On-Demand Adds the Most Value - **Models share devices**: the shared read saves N-1 round-trips - **Devices are slow**: OPC-UA over VLAN, Modbus TCP with large tag counts - **Models write control outputs**: synchronized writes ensure all control actions use consistent predictions - **Scan group rate is similar to device scan rate**: without on-demand, models may read data that's nearly a full cycle old ### When to Skip On-Demand - Devices have fast scan rates relative to the group scan rate (cache is nearly always fresh) - Models only read (no output writes) For device-side on-demand settings (freshness, batch window), see [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md#on-demand-freshness). --- ## Scan Group vs. Individual On-Demand Models | | Per-Model On-Demand | Scan Group On-Demand | |--|---------------------|----------------------| | **Reads per cycle** | One per model | One per device (shared) | | **Inference timing** | Each model on its own schedule | All models together at group scan rate | | **Write timing** | Each model writes after its own inference | All outputs written in a single request | | **Best for** | Models with different scan rates | Models that share devices and need a synchronized cycle | > [!TIP] Scan groups require a common scan rate > A model's individual scan rate is not used while it belongs to a scan group. If your models need significantly different scan rates, keep them independent. --- ## Overscan If a cycle takes longer than the scan rate, the next scheduled cycle is skipped and rescheduled. This is called **overscan** and typically happens when: - The on-demand read is slow (device unresponsive, too many tags) - Inference takes longer than expected (large models, many members) - The scan rate is too aggressive **To resolve:** increase the scan rate, reduce member count, increase the device's batch window, or investigate slow devices. --- ## Monitoring ### Overview Tab Shows status, last scan time, model count, scan rate, scan progress ring, configuration summary, and recent events. ### Execution Tab Per-cycle timing metrics from the last 24 hours: | Metric | Description | |--------|-------------| | **Total Cycle Time** | End-to-end (read + inference + write) | | **On-Demand Read Time** | Time waiting for fresh device reads | | **Inference Time** | Time running all member models | | **On-Demand Write Time** | Time writing outputs to devices | | **Models Succeeded** | Count of models that completed without error | ### Error Codes | Error | Meaning | |-------|---------| | **Overscan** | Previous cycle still running when next was scheduled | | **On-Demand Read Failed** | Read request timed out or encountered an error | | **On-Demand Write Failed** | Write request failed | | **Generic Exception** | Unexpected error. Check the logs tab | --- ## Example: Five Models on a Shared OPC-UA Server Five models all read from the same OPC-UA server that takes 800ms–1.2s to respond. Each model reads ~20 tags. **Without a scan group:** Five on-demand requests fire within milliseconds of each other. Five sequential reads total 4–6 seconds. **With a scan group:** | Setting | Value | |---------|-------| | Scan rate | 60s | | On-Demand | On | | On-Demand Timeout | 10s | The scan group collects all ~100 tag IDs, sends one read to the OPC-UA server (800ms–1.2s total), runs all five models in parallel, and writes outputs in a single request. --- ## What's Next - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md): how on-demand works at the individual model level - [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md): device-side freshness and batch window settings --- Source: https://ai-ops.com/docs/models/importing-exporting Section: Models # Importing & Exporting Models You can import and export AI model configurations (including their bindings) as CSV files. This is useful for migrating models between Koios instances, bulk-editing binding settings in a spreadsheet, or backing up model configurations before making changes. > [!NOTE] Configuration only: model files are separate > Import and export covers model settings and binding configurations, not the model files themselves (ONNX/TFLite). Model files must be uploaded separately through the model files page. See [Managing Model Files](https://ai-ops.com/docs/models/model-files.md). ## How Models and Bindings Relate Each AI model has a set of **bindings**: input bindings that map tags to model inputs, and output bindings that map model outputs back to tags. When you export models, Koios exports both the model settings and all of their bindings together. The export produces a **ZIP file** containing two CSV files: | File | Contents | |------|----------| | `models.csv` | One row per model: general settings, inference config, and scan options | | `bindings.csv` | One row per binding: tag assignments, normalization, failure detection, and output settings | --- ## Exporting Models ### How to Export There are two ways to export model configurations: 1. **From the model table**: select one or more models using the checkboxes, then click **Export config** in the bulk actions menu. Only the selected models and their bindings are exported. 2. **Export all**: if no models are selected, the export includes every model and binding in the system. The export downloads a file named `models_export.zip`. ### What's Included Both CSVs contain all configuration fields. Columns that don't apply to a particular model or binding will be empty. > [!NOTE] Config only, not live data > The export contains static configuration from the database. Live inference values, status, and error states are not included. ### Model CSV Columns **Core fields:** | Column | Description | |--------|-------------| | `id` | Database ID (primary key) | | `slug` | UUID identifier | | `name` | Model name (unique) | | `description` | Optional description | | `enabled` | Whether the model is actively running inference | **Inference settings:** | Column | Description | |--------|-------------| | `output_application` | `0` = Absolute, `1` = Relative | | `output_mode` | `0` = Continuous, `1` = Discrete | | `scan_rate` | Inference interval in seconds (0.01–3600) | | `sample_rate` | Historical data resample rate in seconds | | `on_demand` | Whether on-demand inference is enabled | | `on_demand_timeout` | On-demand timeout in seconds (0.5–30) | | `memory_only` | Store input history in process memory instead of the time-series database (ultra-low-latency; requires on-demand) | | `log_level` | Diagnostic log level (INFO, DEBUG, WARNING, ERROR) | **References:** | Column | Description | |--------|-------------| | `aiopmodel_file` | Active model file (read-only, set by file upload) | | `scan_group` | Scan group ID (for synchronized execution) | | `remote_enable_tag` | Tag ID for remote enable/disable control | | `parent` | Folder ID (if organized in folders) | **System-managed fields (read-only):** | Column | Description | |--------|-------------| | `inputs` | Number of model inputs (set by model file metadata) | | `outputs` | Number of model outputs (set by model file metadata) | | `created_at` | Creation timestamp | | `updated_at` | Last modification timestamp | | `last_modified_by` | User who last modified the model | > [!WARNING] Locked fields > The `inputs`, `outputs`, and `aiopmodel_file` fields are set automatically when a model file is uploaded. They cannot be changed through import. Any values in these columns are ignored. ### Binding CSV Columns **Core fields:** | Column | Description | |--------|-------------| | `id` | Database ID (primary key). **Required** for binding import | | `slug` | UUID identifier | | `aiopmodel` | Parent model ID | | `usage` | `0` = Input, `1` = Output | | `binding_order` | Position in the input or output list (0-based) | | `name` | Binding name (from model file metadata) | | `description` | Optional description | | `tag` | Assigned tag ID (required for inputs, optional for outputs) | **Normalization:** | Column | Description | |--------|-------------| | `normalization_type` | `0` = None, `1` = Min-Max, `2` = Symmetric, `3` = Z-Score | | `normalization_source` | `0` = Tag Range, `1` = Custom | | `custom_minimum` | Custom min value (when source is Custom) | | `custom_maximum` | Custom max value (when source is Custom) | | `custom_mean` | Custom mean (for Z-Score normalization) | | `custom_std` | Custom standard deviation (for Z-Score normalization) | **Calibration:** | Column | Description | |--------|-------------| | `gain` | Linear multiplier (default `1.0`). Cannot be zero. See [Calibration (Gain & Bias)](https://ai-ops.com/docs/models/assigning-bindings.md#calibration-gain--bias). | | `bias` | Linear offset added after gain (default `0.0`). | **Output settings:** | Column | Description | |--------|-------------| | `output_index` | 1-based output tensor index | | `clamp_output` | Clamp output values to the normalization range | | `max_upper_step` | Maximum output step increase per scan | | `max_lower_step` | Maximum output step decrease per scan | **Failure detection:** | Column | Description | |--------|-------------| | `failure_range_mode` | `0` = Disabled, `1` = Custom, `2` = Normalization Range | | `custom_failure_minimum` | Custom failure range minimum | | `custom_failure_maximum` | Custom failure range maximum | | `failure_evaluation` | `0` = Any, `1` = Latest, `2` = Average | | `failure_debounce` | Consecutive failing scans before the model enters a failed state | | `consider_stale_allowed_samples` | Allowed missed input samples before failure | | `recovery_hysteresis` | Recovery hysteresis percentage (0–50%) | **Rate-of-change detection:** | Column | Description | |--------|-------------| | `roc_enabled` | Whether rate-of-change detection is enabled | | `roc_threshold` | ROC threshold value | | `roc_threshold_mode` | `0` = Units per minute, `1` = Percent of range per minute | | `roc_direction` | `0` = Rising, `1` = Falling, `2` = Both | | `roc_window` | ROC measurement window in seconds | **Audit fields (read-only):** | Column | Description | |--------|-------------| | `created_at` | Creation timestamp | | `updated_at` | Last modification timestamp | | `last_modified_by` | User who last modified the binding | --- ## Importing Models ### How to Import 1. Navigate to the **Models** page 2. Click the **Import** button in the table toolbar 3. Select a file: either a ZIP (with `models.csv` and/or `bindings.csv`) or a single CSV 4. Review the preview to verify what will change 5. Click **Confirm Import** to apply the changes ### File Formats The import accepts three file formats: | Format | Contents | |--------|----------| | **ZIP file** | Contains `models.csv` and/or `bindings.csv`; both are processed together | | **Single CSV (models)** | Detected automatically by column headers; creates or updates models | | **Single CSV (bindings)** | Detected automatically by column headers; updates bindings only | Koios auto-detects whether a CSV contains models or bindings based on the column headers. > [!TIP] Start from an export > The easiest way to build an import file is to export your existing models, edit the CSVs in a spreadsheet, and re-import the ZIP. The column headers will already be correct. ### Models: Create or Update **How the import determines what to do with each model row:** | Condition | Action | |-----------|--------| | `id` column is empty | **Create** a new model | | `id` matches an existing model and fields differ | **Update** the existing model | | `id` matches an existing model and nothing changed | **Skip** the row | | Row has validation errors | **Error**: row is not imported | ### Bindings: Update Only > [!WARNING] Bindings cannot be created through import > Bindings are created automatically when you upload a model file. They reflect the model's input and output structure. Import can only **update** existing bindings (for example, assigning tags, changing normalization, or adjusting failure detection settings). If a binding row has no `id` or references a binding that doesn't exist, it will be rejected. **How the import determines what to do with each binding row:** | Condition | Action | |-----------|--------| | `id` matches an existing binding and fields differ | **Update** the existing binding | | `id` matches an existing binding and nothing changed | **Skip** the row | | `id` is empty or doesn't match a binding | **Error**: bindings cannot be created | ### Import Order When importing a ZIP with both files, Koios processes models first, then bindings. This ensures any new models exist before their bindings are updated. ### Example: Creating New Models To create new models, leave the `id` column empty. Provide at least a `name`: ```text id,name,description,enabled,scan_rate,sample_rate,output_application,output_mode,log_level ,AHU Supply Air Model,Predicts supply air temperature,False,1.0,1.0,0,0,INFO ,Chiller Efficiency Model,Estimates COP from sensor data,False,5.0,5.0,0,0,INFO ``` > [!TIP] New models need a model file > After importing new models, upload a model file (ONNX or TFLite) to each one. This creates the bindings and sets the input/output count. Then export again, edit the bindings CSV to assign tags and configure normalization, and re-import. ### Example: Bulk-Editing Binding Normalization Export your models, then edit the bindings CSV to set normalization for all input bindings at once: ```text id,normalization_type,normalization_source,custom_minimum,custom_maximum 501,1,1,-20,50 502,1,1,0,100 503,1,1,0,500 ``` This sets Min-Max normalization with custom ranges on three bindings. ### Example: Assigning Tags to Bindings ```text id,tag 501,42 502,43 503,44 ``` This assigns tag IDs 42, 43, and 44 to the three input bindings. ### Preview Step After selecting a file, Koios performs a **dry run**. It processes the CSV(s) without saving anything and shows you exactly what will happen: - **Summary**: counts of items that will be created, updated, skipped, or rejected - **Row details**: click any row to see a field-by-field diff of what will change - **Diff table**: click **Show Diff Table** for a full-width view of all changes, with changed fields highlighted If the import includes both models and bindings (from a ZIP), the preview shows results for both. > [!WARNING] Errors block the import > If any row has a validation error, the entire import is blocked. Fix the errors in your CSV and re-upload. Common errors include duplicate model names, missing required fields, and attempting to create bindings (instead of updating existing ones). ### Validation Rules **Model validation:** | Field | Validation | |-------|------------| | `name` | Required, max 128 characters, must be unique | | `description` | Max 256 characters | | `scan_rate` | Number between 0.01 and 3600 | | `sample_rate` | Number between 0.01 and 3600 | | `on_demand_timeout` | Number between 0.5 and 30 | | `output_application` | Must be `0` (Absolute) or `1` (Relative) | | `output_mode` | Must be `0` (Continuous) or `1` (Discrete) | | `log_level` | Must be INFO, DEBUG, WARNING, or ERROR | **Binding validation:** | Field | Validation | |-------|------------| | `id` | Required, must match an existing binding | | `tag` | Must reference an existing tag ID | | `normalization_type` | Must be `0` (None), `1` (Min-Max), `2` (Symmetric), or `3` (Z-Score) | | `normalization_source` | Must be `0` (Tag Range) or `1` (Custom) | | `recovery_hysteresis` | Number between 0 and 50 | **Boolean fields** accept: `True`/`False`, `true`/`false`, `1`/`0`, `yes`/`no`. **Foreign key fields** (`tag`, `aiopmodel`, `scan_group`, `remote_enable_tag`, `parent`) expect integer IDs. ### After Import Once you confirm the import: - Models and bindings are created or updated in a single transaction. If anything fails, all changes are rolled back - An audit event is recorded (e.g. "Imported 5 models") with your username - The model table automatically refreshes to show the updated list - Updated models pick up changes on the next inference cycle if they are enabled > [!NOTE] Service pickup delay > After import, the predict engine detects configuration changes within a few seconds. You don't need to restart any services. --- ## Tips - **Typical workflow for new models**: create models via import (or the UI), upload model files to generate bindings, export the bindings, bulk-edit tag assignments and normalization in a spreadsheet, then re-import the bindings. - **Bulk-edit normalization**: export, filter the bindings CSV to input bindings (`usage` = `0`), set `normalization_type`, `normalization_source`, and custom range columns, then import just the bindings CSV. - **Move models between Koios instances**: export from one instance, clear the `id` and `slug` columns in the models CSV (and the `id`, `slug` columns in the bindings CSV), adjust any `tag` and `scan_group` IDs to match the target instance, and import on the target. You'll also need to re-upload the model files. - **Audit trail**: every import creates an event visible on the **Events** page, grouped under a single parent event so you can see what was imported in one action. - **Read-only columns**: `id`, `slug`, `inputs`, `outputs`, `aiopmodel_file`, `created_at`, `updated_at`, and `last_modified_by` are ignored on model create. You can leave them in the CSV but they won't overwrite system-managed values. --- Source: https://ai-ops.com/docs/models/enabling-a-model Section: Models # Monitoring a Model Once a model is enabled and running, Koios provides real-time visibility into every aspect of its operation. The model detail page is organized into tabs, each focused on a different dimension of monitoring. A **floating status pill** follows you across tabs, always showing the model's current state (Running, Stopped, or Failed) so you never lose context. In the navigation, the model's brain icon is wrapped in a **live prediction ring**, a radial progress indicator that fills over the model's scan rate and pulses briefly each time a new prediction lands. The ring is anchored to the server clock, so it stays in sync with what the Predict Engine is actually doing rather than the browser's wall time. --- ## Enabling a Model Before a model can run, it needs: 1. An **active model file** uploaded and activated 2. All **input bindings assigned** to tags 3. The **Enabled** toggle switched on (in the model header or Configuration tab) Once enabled, the Predict Engine begins inference at the configured scan rate. If any prerequisite is missing, the model stays stopped and displays a warning. --- ## Overview Tab The Overview tab gives you a snapshot of the model's current state. - **Status hero**: large status indicator with the current state, last scan timestamp, and a 24-hour uptime bar chart showing the percentage of time spent in each state (Running, Stopped, Failed) - **Model file card**: the active file's name, format, upload date, and input/output dimensions - **Training info**: if the model file includes embedded metadata, displays the training framework, description, and author - **Configuration summary**: key settings (scan rate, sample rate, output mode, on-demand) - **Recent events**: the last few events for this model (enable, disable, config changes, errors) --- ## Live Binding Values The **Bindings** tab has two views, toggled by the segmented control at the top: **Config** and **Diagnostics**. ### Config View Each binding displays a live value card showing the data flow in real time: - **Input bindings**: shows `Tag Value → Model Input`. The left side is the raw value from the tag; the right side is the normalized value fed into the model (after scaling is applied). - **Output bindings**: shows `Model Output → Tag Value`. The left side is the raw model output; the right side is the denormalized value written back to the tag. Values update every second. If a binding is unassigned or its tag is not running, the card indicates the issue. ### Diagnostics View Diagnostics provides deeper insight into each input binding's data quality: - **Interpolated data chart**: visualizes the recent sample history used by the model at each inference cycle. The chart overlays failure bounds (if configured) so you can see when values approach or exceed the expected range. - **Stale regions**: highlighted sections where the tag stopped producing new data (missed samples exceeded the allowed threshold) - **Range violations**: markers where values exceeded the configured failure bounds - **Failure state indicator**: shows whether the binding is currently in a failure state and, if debounce is configured, the current consecutive failure count > [!TIP] Diagnostics help you tune failure detection > Use the diagnostics view to verify that your failure bounds and debounce settings match real operating conditions. If you see frequent false positives, widen the bounds or increase the debounce count. ### Discrete Action Monitor For models using **Discrete** output mode with an action map, the Bindings tab includes an action monitor that shows which discrete action the model is currently selecting and the confidence values across all possible actions. --- ## Execution Tab The Execution tab shows how long each inference cycle takes and where time is spent. This is essential for diagnosing performance issues and tuning scan rates. ### Cycle Breakdown A **stacked bar chart** breaks each recent cycle into segments: | Segment | Description | |---------|-------------| | **Query** | Time reading input data from the data store | | **Inference** | Time running the model (ONNX/TFLite execution) | | **Read** | On-demand device read time (only when on-demand is enabled) | | **Write** | On-demand device write time (only when on-demand is enabled) | | **Overhead** | Remaining time (normalization, denormalization, bookkeeping) | ### History Chart A line chart shows cycle timing trends over the last 24 hours, making it easy to spot patterns. For example, inference times that spike during certain process conditions or read times that increase when a device is under load. ### Metric Cards Four summary cards show key stats: - **Average Cycle Time**: mean total cycle duration - **Max Cycle Time**: worst-case cycle - **Success Rate**: percentage of cycles that completed without error - **Overscans**: count of cycles that exceeded the scan rate > [!NOTE] Memory-only models show simplified metrics > Models with memory-only mode enabled skip the data store query step, so the Execution tab shows a simplified view without the Query segment. --- ## Logs Tab The Logs tab streams the model's runtime logs in real time via server-sent events. Logs appear as they are written, with no need to refresh. - **Log level selector**: filter by severity (Debug, Info, Warning, Error). The log level here controls the Predict Engine's per-model verbosity, not just the display filter. - **Auto-scroll**: the log viewer automatically scrolls to new entries. Scroll up to pause auto-scroll; scroll back to the bottom to resume. - **Search**: use the browser's find-in-page (Ctrl/Cmd+F) to search within the loaded log content. --- ## Parameters Tab The Parameters tab shows all model parameters organized into two sections: - **Live Data**: real-time values from the Predict Engine: status, error code, error message, last scan time, scan progress, and cycle timing metrics - **Configuration**: the model's settings as stored in the database: name, scan rate, sample rate, output mode, and other configuration values Any parameter can be **mapped to a tag** by clicking the map icon next to it. This records the parameter's value in the time-series database, letting you trend model health metrics alongside process data. --- ## Viewing Historical Trends Every model has a linked **Trend** page for viewing historical data. Click the **View Trend** button in the model's header to open it. The trend page plots the time-series values of the model's bound tags (both inputs and outputs) over a configurable time range. This is useful for: - Reviewing how model predictions correlated with actual process behavior - Comparing input patterns before and after a process change - Investigating specific time periods where the model produced unexpected outputs > [!TIP] Tag history requires the time-series database > Trend data is only available for tags that are recording to the time-series database. Models using memory-only mode do not write to the database, so their bound tags will only have historical data if the tags are also collected by a device at a regular scan rate. --- ## What's Next - [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md): configure scaling, failure detection, and rate-of-change monitoring - [Configuring a Model](https://ai-ops.com/docs/models/configuring-a-model.md): adjust scan rate, output mode, and advanced settings - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md): synchronize inference with fresh device reads - [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md): group models for synchronized execution --- Source: https://ai-ops.com/docs/models/troubleshooting Section: Models # Troubleshooting a Model > [!NOTE] This guide has moved > Model and binding troubleshooting now lives in the **Troubleshoot** section. See [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) to work down from a failed model through its bindings to the tags and devices feeding it. Not sure where to start? Begin at [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md). --- Source: https://ai-ops.com/docs/components/introduction Section: Components # Components Components let you deploy custom logic that runs in real-time inside the Koios platform. Use them to build control algorithms, data transformations, state machines, alarm logic, and custom protocol adapters, all without managing external infrastructure. --- ## Key Concepts The component system has four main building blocks: | Concept | What It Is | |---------|-----------| | **Library** | A packaged collection of component types, uploaded as a `.kcl` (Koios Component Library) file | | **Environment** | An execution context where component instances run at a shared scan rate | | **Instance** | A running copy of a component type, placed on an environment's canvas | | **Wire** | A data connection between an instance's input/output and a tag, another instance, or historical data | ### How They Fit Together ```text Library (.kcl) Environment ├── Adder ├── Instance: "Room Temp Avg" (Adder) ├── Latch ├── Instance: "Alarm Latch" (Latch) └── MovingAverage └── Instance: "Smoothed Pressure" (MovingAverage) ↕ wires ↕ Tags, other instances, historical data ``` 1. **Upload a library** containing one or more component types 2. **Create an environment** with a scan rate (how often components execute) 3. **Add instances** of components to the environment's visual canvas 4. **Wire inputs and outputs** to tags, other components, or historical data 5. **Enable the environment**: the component engine begins executing your logic --- ## Component Categories Each component carries a category label chosen by its author. The category controls how components are grouped in the library tray. Any string works as a category, and components without one fall back to **Miscellaneous**. Common categories: | Category | Use Case | Examples | |----------|----------|---------| | **Math** | Arithmetic and numeric operations | Add, multiply, scale, unit conversion | | **Statistics** | Aggregation and summary metrics | Moving averages, min/max, standard deviation | | **Filter** | Signal conditioning | Low-pass, deadband, rate limiting | | **Analysis** | Data inspection and trend detection | Trend analyzers, comparisons | | **Logic** | Decision making and state management | State machines, latches, edge detection | | **Control** | Feedback loops and setpoint management | PID controllers, cascade control | | **Monitoring** | Watching values and raising alerts | Threshold alarms, health checks | Koios ships with a **Core Library** containing common building blocks: math operations, boolean logic, comparisons, and signal processing. You can also build and upload your own libraries. --- ## Execution Model Each environment runs its components in a continuous loop at the configured scan rate: 1. **Read inputs**: resolve all wired input values from tags and other components 2. **Sort by dependencies**: components are automatically ordered so that upstream outputs are available before downstream inputs need them 3. **Execute**: each component's logic runs in dependency order 4. **Write outputs**: results are pushed to wired tags and made available to other components Components maintain their internal state between cycles. A moving average remembers its buffer, a latch remembers its position, an integrator accumulates over time. State resets when the instance is reconfigured or the engine restarts (offline values provide reset defaults). > [!NOTE] Error isolation > If one component fails during execution, the remaining components in the environment continue to run normally. The failed component's status changes to **Error** and the error message is logged. It will retry on the next cycle. --- ## What's Next - [Component Libraries](https://ai-ops.com/docs/components/libraries.md): upload, activate, and manage component packages - [Component Environments](https://ai-ops.com/docs/components/environments.md): create execution contexts and configure scan rates - [Component Canvas](https://ai-ops.com/docs/components/canvas.md): add instances, wire inputs and outputs, and monitor execution - [Building Components](https://ai-ops.com/docs/components/building-components.md): develop your own components with the Koios Component Builder --- Source: https://ai-ops.com/docs/components/libraries Section: Components # Component Libraries Navigate to **Components > Libraries** to manage component library packages. A library is a `.kcl` (Koios Component Library) file containing one or more component types that can be instantiated on an environment canvas. --- ## Library List The library list page shows all uploaded libraries grouped by name. Each row displays: | Column | Description | |--------|-------------| | **Name** | Library name | | **Versions** | Number of uploaded versions | | **Components** | Number of component types in the active version | | **Status** | Whether the library has an active version | | **Created** | When the first version was uploaded | | **Description** | Library description from the package metadata | Click a row to open the library detail page. --- ## Uploading a Library 1. Click **Upload Library** at the top of the list page 2. Drag and drop a `.kcl` file into the upload area (or click to browse) 3. Koios validates the package metadata and extracts component definitions 4. On success, you are taken to the library detail page > [!NOTE] File format > Libraries must be packaged as `.kcl` files using the Koios Component Builder. See [Building Components](https://ai-ops.com/docs/components/building-components.md) for details. If this is the first version of a new library, it is automatically activated. If you are uploading a new version of an existing library, you will be prompted to review and activate it. ### Upload Limits and Safety - **Maximum size: 500 MiB.** Uploads above this size are rejected before the file is read into memory. A full data-science stack (numpy + pandas + scipy + sklearn) lands around 110 MiB, leaving plenty of headroom for typical ONNX bundles and additional dependencies. - **Safe extraction.** The platform rejects archives that contain path-traversal entries (zip slip), absolute paths, or malformed member names. Bundled wheels are extracted into an isolated location and their metadata is filtered before installation. - **Library name validation.** Library names are restricted to lowercase letters, digits, hyphens, and underscores. Uploads with invalid names are rejected at the validation step. --- ## Library Detail The library detail page has up to five tabs. Documentation appears only when the library includes a README. ### Overview Shows all uploaded versions of this library, sorted by version number (newest first). Each version row shows: - **Version**: semantic version (e.g., `1.2.0`) - **Status**: Active, Inactive, or Invalid - **Created**: upload date - **Instances**: how many component instances use this version - **Actions**: Activate, View, or Delete ### Components Lists all component types defined in this library. Click a component to view its full specification: - **Inputs**: fields that receive data (name, type, description, default value) - **Outputs**: fields that produce data - **Configuration**: static settings that don't change at runtime (with constraints like min/max values and dropdown choices) ### Dependencies Shows the library's package dependencies: - **Bundled Packages**: third-party packages that are included in the `.kcl` file and installed when the library is activated - **Platform Packages**: packages that are already pre-installed in the Koios container and do not need to be bundled. If a dependency is satisfied by a platform package, it is listed here with the installed version. ### Documentation If the library includes documentation (a README), it is rendered here. ### Danger Zone Permanently delete all versions of this library. You must type the library name to confirm. If any instances exist, they will also be deleted. --- ## Activating a Version Only one version of a library can be active at a time. The active version determines which component types are available on the canvas. To activate a different version: 1. Open the library detail page 2. On the **Overview** tab, click **Activate** next to the version you want 3. A migration preview appears showing: - **Component changes**: which component types were added, removed, or modified - **Affected instances**: which existing instances will be migrated or deleted - **Wires to remove**: any wires that connect to fields that no longer exist 4. Review the changes and click **Activate** (or **Upgrade** / **Downgrade** depending on the version direction) > [!WARNING] Removed components > If a component type was removed in the new version, all instances of that type will be permanently deleted along with their wires. The migration preview shows exactly what will be affected before you confirm. Koios automatically detects whether the activation is an upgrade, downgrade, or lateral move based on semantic versioning. --- ## Versioning Libraries use [semantic versioning](https://semver.org/) (`major.minor.patch`) with optional pre-release tags (e.g., `1.0.0-beta.1`). When you upload a new version of an existing library: - The new version appears as **Inactive** in the version list - The previously active version remains active until you explicitly activate the new one - You can have multiple inactive versions uploaded at the same time - Activating a version migrates all existing instances to the new component definitions --- ## What's Next - [Component Environments](https://ai-ops.com/docs/components/environments.md): create an execution context for your components - [Component Canvas](https://ai-ops.com/docs/components/canvas.md): add instances of library components to an environment - [Building Components](https://ai-ops.com/docs/components/building-components.md): create your own component libraries --- Source: https://ai-ops.com/docs/components/environments Section: Components # Component Environments Navigate to **Components > Environments** to manage component execution environments. An environment is an isolated execution context. It defines a scan rate and contains the component instances and wiring that make up your processing logic. --- ## Environment List The environment list page shows all environments with: | Column | Description | |--------|-------------| | **Status** | Enabled (teal) or Disabled (gray) | | **Name** | Environment name | | **Description** | Optional description | | **Scan Rate** | How often components execute (e.g., every 1 second) | | **Instances** | Number of component instances in this environment | | **Created / Updated** | Timestamps | Click a row to open the environment detail page. Select one or more rows to reveal bulk actions in the toolbar. From there you can enable, disable, or delete all selected environments at once. --- ## Creating an Environment 1. Click **Add Environment** at the top of the list page 2. Fill in the form: | Field | Description | Required | |-------|-------------|----------| | **Name** | A descriptive name for the environment | Yes | | **Description** | What this environment does | No | | **Scan Rate** | Execution interval in seconds (minimum 0.1s) | Yes | | **Enabled** | Whether the engine should execute this environment | Yes | 3. Click **Create Environment** You are taken to the environment detail page where you can start adding components on the canvas. ### Choosing a Scan Rate The scan rate controls how frequently all components in the environment execute. Choose based on your use case: | Scan Rate | Use Case | |-----------|----------| | 0.1–0.5s | Real-time control loops requiring fast response | | 1s | General-purpose data processing and monitoring | | 5–30s | Periodic calculations and aggregations | | 60s+ | Slow-moving processes and batch logic | > [!TIP] Performance > A faster scan rate means more frequent execution. If your components take longer to execute than the scan rate allows, the engine will log a warning and skip to the next scheduled cycle. Monitor the **Execution** tab to verify your components complete within the scan window. --- ## Environment Detail The environment detail page has a header showing the environment name, scan rate, instance count, and an **Enable/Disable** toggle. Below the header are seven tabs: ### Overview Summary of the environment including its status, scan rate, component count, and key metrics. ### Canvas The visual editor where you add component instances, configure them, and wire inputs and outputs. See [Component Canvas](https://ai-ops.com/docs/components/canvas.md) for the full guide. ### Execution Real-time and historical performance metrics for this environment: - **Scan Rate**: configured interval - **Avg Scan Time**: how long each execution cycle takes on average - **Latest Scan**: when the last cycle completed - **Component Count**: number of instances in this environment A chart shows execution time over time. Toggle between **Live** (updates in real time) and **Last Day** (historical view) using the selector above the chart. Use this tab to verify that your components are executing within the scan rate window and to identify performance bottlenecks. ### Configuration Edit the environment's general settings: - **Name**: rename the environment - **Description**: update the description - **Scan Rate**: change the execution interval Click **Save** after making changes. ### Parameters View and edit runtime parameters for component instances in this environment. Parameters are configuration values defined by the component author that can be adjusted without modifying the component code. Changes take effect on the next scan cycle. ### Cross References Shows how component instances in this environment connect to external entities (tags, devices, and other environments). Use this tab to understand the environment's dependencies and trace data flow across the system. ### Logs View real-time logs for individual component instances. The left panel lists all instances in the environment. Select one to stream its log output in the right panel. Logs are color-coded by severity: | Color | Level | |-------|-------| | Red | Error | | Orange | Warning | | Default | Info and Debug | The log terminal auto-scrolls to follow new output. Scroll up to pause, scroll back to the bottom to resume. Click **Clear** to reset the terminal. --- ## Enabling and Disabling Use the toggle in the environment header to enable or disable the environment: - **Enabled**: the component engine executes all instances in this environment at the configured scan rate - **Disabled**: execution stops. Component state is preserved and will resume when re-enabled. Disabling an environment does not delete any instances or wiring. It pauses execution. --- ## Deleting an Environment Open the environment detail page, click the menu icon, and select **Delete**. This permanently removes the environment and all of its instances, connectors, and wires. --- ## What's Next - [Component Canvas](https://ai-ops.com/docs/components/canvas.md): add instances, wire them together, and monitor live values - [Component Libraries](https://ai-ops.com/docs/components/libraries.md): upload the component types available on the canvas --- Source: https://ai-ops.com/docs/components/venvs Section: Components # Venvs Navigate to **Components > Venvs** to manage isolated Python environments. A venv holds a set of Python packages that only the component environments attached to it can see. Use a venv when a component needs a library the platform does not ship, or a version that conflicts with the one it does. Components that need nothing special run on the platform environment and require no venv at all. --- ## How Venvs Work You upload wheels into a venv. Koios builds the venv from those wheels and runs every attached component environment inside a dedicated worker process. Packages in a venv take precedence over the platform's, so a venv containing `pandas 2.3.1` gives its components that version even though the platform ships a different one. Everything the platform provides that the venv does not override stays available. Each venv in use costs one worker process. Budget roughly 200 MB of memory per venv, and reuse a venv across environments rather than creating one per environment. > [!CAUTION] Uploaded code runs with full privileges > Only upload wheels from sources you trust. Code installed into a venv runs with full platform privileges on the Koios server. --- ## Venv List The venv list page shows: | Column | Description | |--------|-------------| | **Status** | Build state, or the state of the worker process running it | | **Name** | Venv name | | **Description** | Optional description | | **Wheels** | Number of wheels installed | | **Environments** | Number of component environments attached | | **Worker Memory** | Memory used by the worker process, when one is running | | **Updated** | Last change | Click a row to open the venv detail page. ### Status Values | Status | Meaning | |--------|---------| | **Pending** | Queued for building | | **Building** | Being built now | | **Build failed** | The build did not finish. Open the **Build** tab for the log | | **Running** | A worker process is executing attached environments | | **Worker failed** | The worker stopped unexpectedly. It restarts automatically | | **Not in use** | Built and ready, but no enabled environment is attached | --- ## Creating a Venv 1. Click **Add Venv** on the list page 2. Enter a name and an optional description 3. Click **Create Venv** The venv is created empty. Add packages to it next. --- ## Adding Packages Open the venv and go to the **Wheels** tab. There are two ways to add packages. ### Uploading Wheels Drag `.whl` files onto the upload area, or click to browse. You can drop several at once — the whole batch triggers a single rebuild. > [!WARNING] Upload every dependency > Koios installs exactly the wheels you upload and does not download anything else. Upload the package **and** every package it depends on. A missing dependency surfaces as a failed component environment rather than a failed build. Wheels must be built for Linux (`manylinux`) and match the Python version shown on the venv's Overview tab. Wheels for macOS or Windows are rejected on upload with a message naming the problem. ### Importing a Bundle A `.kvenv` bundle collects a package and its full dependency tree in one file. Build one on a development machine with the component builder: ```bash koios-component-builder export-venv -r requirements.txt --name my-venv ``` Or capture the environment you are working in: ```bash koios-component-builder export-venv --from-env --name my-venv ``` The bundle downloads Linux wheels for each dependency regardless of the machine you build it on, which makes it the practical way to move a large dependency set onto an air-gapped server. Click **Import Bundle** on the list page to create a venv from a bundle, or **Import bundle** on the Wheels tab to add its packages to an existing venv. --- ## Attaching a Venv to an Environment 1. Open a component environment 2. Go to the **Configuration** tab 3. Choose the venv under **Venv** 4. Click **Save Configuration** Instances in that environment now run inside the venv. Clearing the field detaches the environment, and its instances go back to running on the platform environment. Attaching an environment to a venv that failed to build is allowed, but its instances will not run until the build succeeds. --- ## Rebuilding Koios rebuilds a venv automatically whenever its wheels change. To rebuild on demand — after a Koios upgrade, or to retry a failed build — open the venv and choose **Rebuild venv** from the actions menu. A rebuild restarts the worker process, so components in attached environments restart with it. Removing a wheel has the same effect. --- ## Deleting a Venv Deleting is blocked while any environment is attached. Detach every environment first; the error message names the ones still using it. Uploaded wheels are included in backups, so restoring a backup restores your venvs. The built environments themselves are not backed up — Koios rebuilds them from the stored wheels on the first start after a restore. --- ## Troubleshooting | Symptom | Cause | Fix | |---------|-------|-----| | Build failed with a "No solution found" or missing-file error | A dependency was not uploaded | Upload the missing wheels, or import a bundle built with `export-venv` | | Upload rejected for platform tags | The wheel targets macOS or Windows | Obtain the `manylinux` build of the package | | Upload rejected for Python version | The wheel targets a different Python | Match the version shown on the venv's Overview tab | | Component fails with an import error | The package is present but one of its dependencies is not | Upload the missing dependency and rebuild | | Environment stays stopped | Its venv has not finished building, or the build failed | Check the venv's status and build log | --- Source: https://ai-ops.com/docs/components/canvas Section: Components # Component Canvas The canvas is the visual editor where you build processing logic by placing component instances, connecting their inputs and outputs, and monitoring live execution. Open it from the **Canvas** tab on any environment detail page. --- ## Adding Instances The **Library Tray** on the left side of the canvas lists all component types from the active library. To add a component: 1. Open the library tray (left sidebar) 2. Find the component type you want (components are organized by category) 3. Drag it onto the canvas A new instance node appears with the component's default configuration. Each node shows: - **Header**: component name and icon - **Input pins** (left side): fields that receive data - **Output pins** (right side): fields that produce data You can drag nodes to reposition them on the canvas. Nodes snap to a grid for clean alignment. --- ## Configuring an Instance Double-click a component instance (or right-click and select **Configure**) to open the configuration drawer. It has tabs for: ### Overview Shows the instance name and tables of the input and output fields with their current wire connections and values. Edit **offline values** for input fields here (see [Offline Values](#offline-values) below). - **Instance Name**: a custom name to identify this instance (e.g., "Room 3 Temp Avg") - **Input Fields**: each field's live value, offline value, and wire connection - **Output Fields**: each field's live value and wire connection ### Configuration Shown only when the component defines config fields. Static settings that don't change at runtime and control how the component behaves. Depending on the component, you may see: - **Number fields**: with optional min/max bounds and step size - **Text fields**: with optional validation patterns - **Toggle switches**: for boolean settings - **Dropdowns**: for predefined choices ### Canvas Controls how the node looks and sits on the canvas: - **Position**: the node's X/Y coordinates, snapped to the grid - **Node Width**: the visual width of the node in grid units - **Minimal Mode**: a compact view without the header and status bar - **Customize Layout...**: opens the pin-layout editor (see [Per-Instance Pin Layouts](#per-instance-pin-layouts) below) ### Documentation Shown only when the component type ships documentation. Rendered here. --- ## Connectors Connectors are the bridge between the canvas and the rest of Koios. They appear as square nodes on the canvas and come in seven types. Input connectors feed live data into a component; output connectors receive a component's result and write it somewhere. | Connector | Direction | Source / Sink | |---|---|---| | **Tag** | Input or Output | A tag (live value, quality, timestamp, status, error code) | | **History** | Input only | A tag's historical time-series data, queried on demand | | **Device** | Input only | A device's live status (running, stopped, failed, error code, last seen) | | **AI Model** | Input only | A model's live status and current prediction | | **Binding** | Input only | The live value flowing through a specific model binding | | **Scan Group** | Input only | A scan group's live status and timing metrics | | **Component** | Input only | An output from another component instance (any environment) | Each connector type only exposes the fields that make sense for it. For example, a Device connector lets you wire `status` or `error_code` into a component, but not `value`, because devices don't have one. The connector picker filters the available fields based on the entity you choose. ### Tag Connector Reads from or writes to a tag. - **Tag**: which tag to read from or write to - **Field**: which tag field to use: `value`, `quality`, `timestamp`, `status`, or `error_code` For **output** tag connectors, only writable tags (output usage) are listed. ### History Connector Provides on-demand access to a tag's historical data. The connected component receives a history provider that can query the time-series database for trends, rolling statistics, or pattern detection. - **Tag**: which tag's history to access ### Device, AI Model, Binding, Scan Group Connectors Each of these reads a curated set of live fields from the named entity. Use them to build components that react to system state. For example, gate control logic on a device's status, or feed a model's current prediction into another component. - **Entity**: pick the device, model, binding, or scan group - **Field**: the connector picker shows only the fields valid for that entity ### Component Connector Reads an output from another component instance. This is typically used for cross-environment composition, for example a fast control loop in one environment feeding a slower analytics environment. It can also reference a component in the current environment. - **Environment**: which environment contains the source component - **Instance**: which component instance to read from - **Output Field**: which output field to use > [!NOTE] Same-environment wiring > To connect two components in the **same** environment, the normal approach is to draw a wire directly between their pins. A Component connector can also reference the current environment, but a direct pin-to-pin wire is simpler. --- ## Wiring Wires carry data between component pins and connectors. To create a wire: 1. Click on an output pin (right side of a component or an input connector) 2. Drag to an input pin (left side of a component or an output connector) 3. Release to create the wire **Rules:** - Each component input can have at most **one** incoming wire - Each output connector can have at most **one** incoming wire - Component outputs can fan out to multiple destinations - Wires automatically validate type compatibility ### Wire Validation Type compatibility is checked as you draw the wire and again at save time. If a connection is invalid, the wire paints **red** with a tooltip explaining why. For example, "string output cannot connect to numeric input." Invalid wires are not allowed to save: the offending wire is highlighted directly on the canvas instead of failing with a generic error. The same contract runs in the component engine at runtime. If a wire ever produces a type mismatch (for example, an upstream component changes type after a library upgrade), the affected instance enters an ERROR state with the offending pin called out in the diagnostics. Allowed coercions: - `int`, `float`, and `bool` connect to each other in any direction. - A value is adjusted so it matches the pin it lands on. A `float` arriving at an `int` pin is **rounded to the nearest whole number**, with `.5` rounding up: `2.5` becomes `3`, `-2.5` becomes `-2`. A number arriving at a `bool` pin becomes `true` when it is non-zero and `false` when it is zero. - If you need different rounding — always down, always toward zero — put a math component in front of the wire. Identical types always pass. `str`, `list`, and `dict` require an exact type match. ### Custom Wire Routing Click any wire to reveal a midpoint handle. Drag it perpendicular to the wire's direction to de-stack overlapping wires or reshape the route for readability. Double-click the wire to reset it to the default path. Routing is saved with the canvas and survives copy/paste. ### Dependency Ordering When components are wired together, the engine automatically determines the correct execution order using topological sorting. Components whose outputs feed into other components' inputs execute first, ensuring data flows correctly in a single scan cycle. If a circular dependency is detected (A feeds B, B feeds C, C feeds A), the engine logs a warning and executes the components in a best-effort order. Components in the cycle will see values from the previous scan cycle rather than the current one. --- ## Per-Instance Pin Layouts Every instance has its own pin layout. The component type ships a default ordering, and you can layer your own customizations on top: reorder, insert gaps for visual grouping, or hide pins you don't need on this particular instance. Open the **Canvas** tab on the instance configuration drawer and click **Customize Layout...** (or click the pin layout icon on the node) to open the editor: - **Drag pins** in the input or output column to reorder them - **Insert a gap** between pins for visual separation - **Hide a pin** by dragging it to the hidden tray on the right - **Restore a hidden pin** by dragging it back from the tray - **Reset to default** to discard the instance's overrides and fall back to the component type's layout Layouts persist across canvas saves, environment clones, and copy/paste operations. Cross-side drags (e.g., trying to move an input pin to the output column) are rejected with visual feedback. > [!NOTE] Hiding doesn > Hiding a pin removes it from the visual node but does not delete any wires connected to it. If you re-show the pin later, the wire is still there. To remove a wire, delete it directly from the canvas or the Wiring tab. --- ## Offline Values Each input field can have an **offline value**: a fallback used when the input is not wired or when live data is unavailable. Edit offline values in the Input Fields table on the instance's **Overview** tab. You can also click **Save Live to Offline** to capture the current runtime values as the new offline defaults. This is useful for initializing components with known-good values after a period of live operation. --- ## Saving the Canvas Changes to the canvas (adding/removing instances, moving nodes, creating wires, editing pin layouts, customizing wire routes) are held locally until you click **Save** in the toolbar. The save operation is atomic: all changes are applied together or not at all. If a save is rejected, the canvas highlights the specific instance, connector, or wire that failed validation rather than showing a generic error. The toolbar also provides: | Button | Action | |--------|--------| | **Undo / Redo** | Step through recent changes (including arrow-key nudges and selection changes) | | **Refresh** | Reload the canvas from the server (discards unsaved changes) | | **Delete** | Remove the selected node or wire | | **Save** | Persist all changes to the server | --- ## Monitoring Live Values When the environment is enabled, the canvas shows live values flowing through wires and pins. Input and output fields on each instance display their current values, updating in real time at the environment's scan rate. Use the **Execution** tab on the environment detail page for performance metrics, and the **Logs** tab to stream per-instance log output for debugging. --- ## What's Next - [Component Environments](https://ai-ops.com/docs/components/environments.md): configure scan rates and monitor execution performance - [Component Libraries](https://ai-ops.com/docs/components/libraries.md): manage the component types available on the canvas - [Building Components](https://ai-ops.com/docs/components/building-components.md): create your own component types --- Source: https://ai-ops.com/docs/components/building-components Section: Components # Building Components The Koios Component Builder lets you build custom component types in Python, package them as libraries, and upload them to Koios for real-time execution. This page provides a high-level overview of the development workflow. For complete documentation, examples, and API reference, see the [Koios Component Builder documentation](https://github.com/Ai-Ops-Inc/koios-component-builder). --- ## Overview A component is a Python class that defines typed **inputs**, **outputs**, and **configuration fields**. The component engine calls your `execute()` method on every scan cycle, passing in the latest input values and reading back your outputs. ```python from koios_component_builder import Component, Input, Output class TemperatureConverter(Component): """Converts Celsius to Fahrenheit.""" celsius: Input[float] = Input(default=0.0, description="Temperature in Celsius") fahrenheit: Output[float] = Output(default=32.0, description="Temperature in Fahrenheit") def execute(self) -> None: self.fahrenheit = self.celsius * 9 / 5 + 32 ``` When deployed to Koios, this component appears on the canvas with a `celsius` input port and a `fahrenheit` output port. Wire a tag to the input, wire the output to another tag or component, and the conversion runs automatically at the environment's scan rate. --- ## Development Workflow ```text 1. Write 2. Package 3. Upload 4. Wire & Run Component ───► .kcl file ───► to Koios ───► on Canvas (Python) (CLI tool) (drag & drop) (visual editor) ``` 1. **Write** your component classes using the SDK's base classes and field descriptors 2. **Package** them into a library using the `koios-component-builder` CLI tool 3. **Upload** the `.kcl` file through the Koios UI at **Components > Libraries** 4. **Wire** instances on an environment canvas and enable the environment --- ## What You Can Build | Component Type | Description | |---------------|-------------| | **Data processing** | Scaling, filtering, moving averages, unit conversion | | **Control logic** | PID controllers, setpoint management, cascade loops | | **Decision logic** | State machines, alarm rules, threshold detection, latches | | **Analytics** | Rolling statistics, trend analysis, anomaly detection | | **Custom protocols** | Proprietary device adapters, data format converters | --- ## Key Concepts ### Fields Components declare their interface using typed field descriptors: | Field Type | Purpose | |-----------|---------| | **Input** | Receives data from a wired tag, another component, or a manual value | | **Output** | Produces data that can be wired to tags or other components | | **Config** | Static settings configured once per instance (numbers, text, booleans, dropdowns) | | **HistoryInput** | Provides on-demand access to a tag's historical time-series data | ### State Components can maintain internal state between execution cycles. Instance variables set in `__init__` or during `execute()` persist across cycles, useful for integrators, moving averages, edge detectors, and any logic that depends on previous values. ### Libraries Components are organized into libraries. A library is a named, versioned collection of component types. When you upload a new version of an existing library, Koios offers a migration flow that maps existing instances to the updated component definitions. ### Metadata Each component can declare visual metadata (icon, category, canvas width) that controls how it appears on the canvas. The SDK provides a catalog of icons and categories to choose from. ### Pin Layout (koios-component-builder 1.1+) By default, pins appear on the canvas in declaration order. To control ordering and grouping, declare `inputs_layout` and `outputs_layout` on the component's `Meta` class: ```python from koios_component_builder import Component, Input, Output, Gap class PIDController(Component): sensor: Input[float] = Input(default=0.0) setpoint: Input[float] = Input(default=0.0) enable: Input[bool] = Input(default=True) output: Output[float] = Output(default=0.0) class Meta: inputs_layout = ["sensor", "setpoint", Gap(), "enable"] outputs_layout = ["output"] ``` `Gap()` (or `Gap(size=2)` for wider spacing) inserts visual separation between pins. The layout you declare is the component-type default. Users can override it [per instance](https://ai-ops.com/docs/components/canvas.md#per-instance-pin-layouts) on the canvas. `Meta.inputs_layout` and `Meta.outputs_layout` replace the older `FieldDescriptor(order=...)` convention, which is deprecated as of koios-component-builder 1.1 (manifest `sdk_base_version` 3) and scheduled for removal in 2.0. ### Wire Contract The `koios_component_builder.wire_contract` module exposes the platform's canonical pin type vocabulary (`int`, `float`, `bool`, `str`, `list`, `dict`, plus the `HistoryProvider` sentinel) and the coercion rules that the canvas and engine enforce. Use it if you need to validate wire compatibility outside the platform (for example, in unit tests for a custom component library) so your assertions match what Koios actually allows. --- ## Getting Started For the full development guide (including installation, field types, configuration options, testing, packaging, and example components), see the [Koios Component Builder documentation](https://github.com/Ai-Ops-Inc/koios-component-builder). The builder repository includes: - Installation and setup instructions - Complete API reference for all field types and base classes - The Koios Core Library (in koios-component-libraries) with 40+ example components (math, logic, signal processing, statistics) - CLI reference for packaging and exporting libraries --- ## What's Next - [Component Libraries](https://ai-ops.com/docs/components/libraries.md): upload your packaged library to Koios - [Component Canvas](https://ai-ops.com/docs/components/canvas.md): wire instances of your components to tags and other components - [Component Environments](https://ai-ops.com/docs/components/environments.md): configure scan rates and monitor execution --- Source: https://ai-ops.com/docs/explorer/introduction Section: Explorer # Explorer The Site Explorer is a slide-out panel for organizing everything on your instance into a folder hierarchy you build yourself. Group your devices, tags, models, device sets, and local values into folders that mirror your plant: site, building, area, line, and equipment. Once organized, you can browse the tree, check live values, and jump to any entity's full page without leaving the panel. Explorer is for organizing and navigating, not analysis. The detail panel shows a live sparkline for the selected tag, but Explorer does not replay historical trends or export data. To chart values over time, use [Trends](https://ai-ops.com/docs/trends/introduction.md). ## Opening the Explorer Open the Explorer two ways: - Click **Explorer** at the top of the left navigation. - Press `Cmd+E` (macOS) or `Ctrl+E` (Windows and Linux) from anywhere in the app. The panel slides in from the left. Your expanded folders and last selection are remembered between sessions, so it reopens where you left off. ## Layout The panel is split into two sides: | Side | Shows | |------|-------| | **Left** | The folder tree, a search box, and the add menu | | **Right** | The detail panel for whatever is selected, or the item browser when you are adding entities | ## Creating and nesting folders Use the add menu (the **+** button next to the search box) to build your hierarchy: - **New Folder** creates a top-level folder when no folder is selected. - With a folder selected, the same option becomes **New Sub-folder** and nests the new folder inside it. Each folder has a name, an optional description, and an icon. Pick an icon that matches the level it represents: | Icon | Typical use | |------|-------------| | Folder | Generic grouping | | Site | A physical site or plant | | Building | A building within a site | | Area | An area or zone | | Line | A production line | | Equipment | A single machine or asset | To rearrange folders, drag one folder onto another to nest it, or drag it to the **Drop here to move to root** zone at the bottom of the tree to un-nest it. ## Adding entities to folders Folders group your existing devices, tags, models, device sets, and local values. Adding an entity to a folder is purely organizational: it does not move, copy, or change the entity itself. There are two ways to add entities: 1. **Add Items mode.** Open the add menu and choose **Add Items**. The right side becomes a searchable browser. Filter by entity type, find what you need, choose **Add to Folder**, and pick the destination folder in the dialog. 2. **Drag and drop.** Drag an entity from one folder onto another folder in the tree to move it. An entity can live in one folder at a time. Adding it to a new folder moves it there. ## Selecting and bulk actions Click any item to select it. To act on several at once: - **Shift-click** to select a range within a group. - **Cmd/Ctrl-click** to toggle individual items in and out of the selection. When more than one item is selected, a bulk actions bar appears at the bottom of the tree: | Action | Effect | |--------|--------| | **Move** | Move all selected items into a folder you pick | | **Remove** | Take the selected items out of their folders (back to unassigned) | You can also drag a selection onto the trash zone that appears over the detail panel while dragging to remove those items from their folders. > [!WARNING] Removing is not deleting > Removing an item from a folder, or deleting a folder, never deletes the underlying entity. When you delete a folder, its sub-folders move up to the parent and its items become unassigned. Devices, tags, and models are only deleted from their own pages. ## The detail panel Selecting a single entity opens its detail panel on the right. For a tag, that includes the live current value, a sparkline, its status, range, device, and protocol details, all updating in real time. The panel also gives you quick controls: - **Enable / disable** the entity in place. - **Open** to jump to the entity's full page (for example, the tag or device detail view). - The entity's action menu for the same operations available on its full page. ## Search The search box at the top of the tree filters folders by name as you type. In **Add Items** mode, the browser has its own search that filters the available devices, tags, models, device sets, and local values by name. ## What's Next - [Getting Started](https://ai-ops.com/docs/getting-started/introduction.md) for a high-level tour of the Koios platform. - [Trends](https://ai-ops.com/docs/trends/introduction.md) for charting live and historical tag values over time. --- Source: https://ai-ops.com/docs/events/introduction Section: Events # Events The Events page is the platform-wide activity log and audit trail. Every meaningful action in Koios records an event: a device connecting or failing, a tag going into alarm, a model starting inference, a component throwing an error, a user changing a setting, or a service reporting its health. Open **Events** from the sidebar to see the full stream, newest first. Each event captures what happened, which service reported it, which entity it relates to, and who triggered it (a user or an API client). Configuration changes also record the exact field values before and after. ## Event Types Every event has a type that sets its severity and color. Filter the list by one or more types. | Type | Meaning | |------|---------| | **Information** | Normal activity worth recording, no action needed | | **Success** | An operation completed successfully (connected, started, restored) | | **Warning** | A condition that may need attention but is not yet failing | | **Alarm** | A monitored value crossed an alarm threshold | | **Error** | An operation failed (connection lost, inference error, validation failure) | | **Configuration** | A user or client changed a setting; carries the field-level before and after values | | **Action** | A user or client triggered an operation (enable, disable, reconnect, acknowledge) | ## Event Sources The source is the service that recorded the event. Filter the list by one or more sources. | Source | Records events for | |--------|--------------------| | **WebApp** | Configuration changes, user and client actions, backup and restore | | **Data Collector** | Device connections, tag reads, protocol errors | | **Prediction Engine** | Model inference, binding validation, execution failures | | **Mapping** | Data transformation and normalization | | **Performance Monitor** | CPU, memory, and disk alarms | | **Heartbeat** | Service health and availability checks | | **Component Engine** | Component instance execution and errors | | **Expression Evaluator** | Calculated tag and expression evaluation | | **None** | Events with no specific originating service | ## The Event List The list shows one row per event with these columns: | Column | Contents | |--------|----------| | **Type** | Severity badge with icon | | **Time** | Relative time; hover for the exact timestamp | | **Message** | The one-line summary | | **Entity Type** | The kind of related entity (device, tag, model, and so on) | | **Entity** | The name of the related entity | | **Source** | The service that recorded the event | | **User** | The user or API client responsible, if any | | **Acknowledged** | A check mark when the event has been acknowledged | Use the column filters to narrow by type, source, entity type, or a time range, and type in the message filter to search event text. Sort by time, type, source, or message. The list loads more rows as you scroll. By default the list shows only **unacknowledged** events and hides events from muted entities. Use **View all** to include acknowledged and muted events. When new events arrive while you are scrolled down, a **new events** pill appears at the top; click it to jump back and load them. > [!NOTE] Seen is per-user, acknowledged is shared > Whether an event has been *seen* is tracked per user and drives your popup notifications. Whether an event is *acknowledged* is shared across everyone, so acknowledging clears it from the default view for all users. ## Event Detail Click any row to open the detail drawer. Depending on the event, it shows: | Section | Contents | |---------|----------| | **Message** | The full summary line | | **Detail** | Extended context, such as an error traceback | | **Related Entity** | A link to the device, tag, model, or other entity the event is about | | **Time** | Relative and absolute timestamps | | **User / API Client** | Who triggered the event, linking to their profile or client | | **Field Changes** | For configuration events, each changed field with its previous and current value | | **Parent Event / Cascade** | Links to related events when the event is part of a group | ## Acknowledging Events Acknowledging an event marks it as handled and removes it from the default unacknowledged view. Acknowledge a single event from its detail drawer, select several rows and acknowledge them together, or use **Acknowledge all** to clear every unacknowledged event at once. Acknowledging requires the **Acknowledge events** permission. Without it, the acknowledge controls are visible but disabled with a tooltip explaining why. See [Roles & Permissions](https://ai-ops.com/docs/system/roles-permissions.md) to grant it. ## Muting Muting suppresses your popup notifications without hiding events from the log. Muting is per-user, so it never affects what your teammates see. - **Mute an entity**: from an event's detail drawer, mute the related device, tag, or model for a set duration or indefinitely. Muted entities are also hidden from the default event view. - **Mute all notifications**: silence every popup notification for a duration or indefinitely from the notification bell in the header. Events still record; only the popups stop. Manage these from the notification settings, reachable via the bell icon in the Events page header. ## Related Events When one root cause produces many events, such as a bulk enable touching hundreds of tags or a device failure cascading to its tags, Koios groups them. The originating event becomes the **root**, and the rest become its children. The list collapses each group to its root row and shows a **+N related** badge with the child count. Use the **Expand** toggle to reveal child events inline. Open a root event to see the full **Event Cascade** timeline, drill into any child, and step back to the parent. **Acknowledge All** on a root acknowledges the root and every child together. ## Real-Time Notifications New events raise popup notifications in the corner of the screen for events you have not yet seen. During a sustained burst, Koios consolidates the individual popups into a single storm notification with a live counter, so a flood of events never buries the interface. The counter keeps climbing until activity quiets down. The event list itself is never collapsed; every event is always recorded and browsable. ## Retention Events are kept for a configurable number of days (90 by default) and older events are deleted automatically. Adjust the **Event Retention** period in [Data Retention](https://ai-ops.com/docs/system/retention.md). ## What's Next - [Data Retention](https://ai-ops.com/docs/system/retention.md): control how long events and other history are kept. - [Roles & Permissions](https://ai-ops.com/docs/system/roles-permissions.md): grant the Acknowledge events permission and control access. --- Source: https://ai-ops.com/docs/system/information Section: System # System Overview Navigate to **System > Overview** to see a summary of your Koios deployment. The page displays four status cards at the top and a system information panel below. --- ## Status Cards ### Platform Shows the platform name and a brief description. This card is static. ### Version Displays the current Koios version number. If the version is a pre-release (e.g., alpha or release candidate), a yellow badge appears next to the version. Click the card to expand a popover listing the individual version of each internal service (Data Collector, Predict Engine, Web App, etc.) and the release date. ### System Health Shows the overall health status of the platform: | Status | Meaning | |--------|---------| | **Healthy** | All services are running and reporting heartbeats | | **Degraded** | Some services are healthy but at least one is not responding | | **Unhealthy** | All services are unresponsive | | **Unknown** | No health data is available | Click the card to expand a popover listing each service with its status, last heartbeat timestamp, and any error messages. ### Server Time Displays the current server time (updating every second), timezone, and UTC offset. If the server clock and your browser clock are out of sync, a warning icon appears: - **Yellow warning**: drift between 2 and 30 seconds - **Red warning**: drift exceeds 30 seconds Hover the warning icon to see the exact drift amount and direction. > [!WARNING] Why clock drift matters > Koios stamps every device read, model prediction, event, and historical sample with the host clock. Drift causes: > > - **Trends and history off the timeline**: samples appear at the wrong time, breaking comparisons against PLC, SCADA, or external historian data. > - **"Live" values look stale or future-dated**: the UI flags freshness against its own clock; a server running fast or slow makes recent values look wrong. > - **Model evaluation skews**: predictions and the device data they're scored against no longer line up. > > The cause is almost always either the **browser machine** or the **Koios host** drifting. Both should be synchronized via NTP. On the host, verify with `timedatectl status`. It should report `System clock synchronized: yes`. See [System Requirements > Time Synchronization](https://ai-ops.com/docs/installation/system-requirements.md) for setup details. --- ## System Information Below the status cards, a full-width panel shows details about the host system, organized into two columns. ### Host & OS | Field | Description | |-------|-------------| | **Hostname** | The server's network hostname | | **Operating System** | OS name and version | | **Kernel** | Kernel version string | | **Architecture** | CPU architecture (e.g., x86_64, aarch64) | | **Timezone** | The configured system timezone | | **Uptime** | How long the server has been running (e.g., "2d 5h") | ### Hardware & Network | Field | Description | |-------|-------------| | **CPU Cores** | Number of logical CPU cores | | **Total Memory** | Total system RAM | | **Total Disk** | Total disk capacity | | **IP Address** | Primary network IP | | **MAC Address** | Primary network MAC address | | **Virtual Machine** | Whether the system is running in a VM, with VM type if detected | The panel also shows the **Python version** used by backend services. --- ## What's Next - [Services](https://ai-ops.com/docs/system/services.md): monitor individual service status and restart services - [Performance](https://ai-ops.com/docs/system/performance.md): CPU, memory, and disk usage monitoring - [License](https://ai-ops.com/docs/system/license.md): view and manage your Koios license --- Source: https://ai-ops.com/docs/system/license Section: System # License Navigate to **System > License** to view your current license status and manage activation. --- ## License Status The page displays a status banner at the top indicating the current state: | Status | Banner | Meaning | |--------|--------|---------| | **Active** | Teal | License is valid and all licensed features are available | | **Grace Period** | Orange | License has expired, but data collection continues for a countdown of days until the grace period ends | | **No License** | Yellow | No license file has been uploaded. Activation is required | | **Invalid** | Red | License is expired, corrupted, or does not match the current hardware | --- ## License Details When a license is present (valid or invalid), a details card shows: | Field | Description | |-------|-------------| | **Product Name** | The licensed product tier (e.g., "Koios Pro") | | **License ID** | The license key identifier | | **Request ID** | The activation request identifier (for support) | | **Hardware ID** | The machine fingerprint this license is bound to | | **Expires** | When the license expires, with a relative countdown | The License ID, Request ID, and Hardware ID fields are copyable. Click them to copy to your clipboard. --- ## Activating a License If no valid license is present, the page shows the three-step activation wizard. This is the same flow shown on first login. For step-by-step activation instructions, see [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md). --- ## Re-Activation If you need to re-activate (for example, after moving Koios to a different server or VM), click **"Need to re-activate your license?"** on the license page. This expands the activation wizard so you can generate a new activation file for the current hardware. > [!WARNING] Hardware-tied license > The Koios license is bound to the hardware it was activated on. Moving Koios to different hardware invalidates the existing license file. You'll need to generate a new activation file and obtain a new license file from the portal. --- ## First-Login Flow On first login to a new Koios installation, the application guides you through an onboarding sequence: 1. **Account setup**: optionally set your email, name, and a new password 2. **License activation**: the three-step activation wizard 3. **Application access**: after activation, you're taken to the home page You can skip both the account setup and license activation steps, but without a valid license the platform operates in a limited state. --- ## What's Next - [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md): detailed activation walkthrough - [System Overview](https://ai-ops.com/docs/system/information.md): version, health, and server details --- Source: https://ai-ops.com/docs/system/users Section: System # Users Navigate to **System > Users** to manage user accounts. The user list shows all accounts with their status, role, and last login time. --- ## User List The user table displays the following columns: | Column | Description | |--------|-------------| | **Status** | Active (teal) or Inactive (gray) | | **Username** | The account's login name | | **Email** | Email address, if set | | **Name** | First and last name combined | | **Role** | The assigned role: Superuser, a group name, or View Only | | **Last Login** | Relative timestamp of the last successful login | Inactive users appear at reduced opacity. Superusers display a crown icon next to their role. Use the search bar to filter by username, email, or name. Column filters are available for status, role, and last login date range. ### Bulk Actions Select multiple users with the checkboxes, then open the **Actions** menu to: - **Enable** or **Disable** all selected users - **Delete** all selected users (with confirmation) ### Row Actions Right-click any user row to access quick actions: Edit User, Change Password, Enable/Disable, or Delete. --- ## Creating a User Click **Add User** to open the creation dialog. | Field | Required | Notes | |-------|----------|-------| | **Username** | Yes | Cannot be changed after creation. Letters, digits, and `@.+-_` only. | | **Password** | Yes | Minimum 8 characters | | **Email** | No | Optional email address | | **First Name** | No | Optional | | **Last Name** | No | Optional | | **Role** | Yes | Select a role or "View Only (No group)" | | **Active** | No | Default: on. Inactive users cannot log in. | The user can log in immediately after creation if marked as active. --- ## User Detail Page Click any user row to open their detail page. The header shows the username, role badge, join date, last login, and an enable/disable toggle. ### Overview Tab Metric cards summarize: - **Date Joined:** when the account was created - **Last Login:** when the user last authenticated (or "Never") - **Role:** the assigned role name - **Status:** Active or Inactive Below the metrics, a user information card shows the username, email, and name fields. ### Settings Tab Two editable sections: **User Details:** edit email, first name, last name, role, and active status. Username is read-only. If the user is a superuser, the role dropdown is disabled (superuser status is managed separately from roles). **Change Password:** enter a new password and confirm it. Minimum 8 characters. ### Roles Tab Shows the user's current role assignment. From here you can assign the user to a different role or remove them from their current role. Superusers do not have a role assignment. Their access bypasses all permission checks. ### Permissions Tab Displays the user's effective permissions based on their role: - **Superusers:** full access indicator with a note that superuser privileges bypass all permission checks - **View Only:** read-only access indicator with a note that no permissions are granted - **Role-assigned users:** the role name and a grouped list of all permissions granted by that role --- ## My Profile Users can view and edit their own account at **Profile > My Profile** (accessible from the user menu in the top-right corner). The layout matches the user detail page with Settings, Notifications, and Permissions tabs, but the role field is read-only. Users cannot change their own role. ### Notifications Tab Configure personal notification preferences. Control which event types trigger notifications and how they are delivered. --- ## What's Next - [Roles & Permissions](https://ai-ops.com/docs/system/roles-permissions.md): create roles, assign permissions, and manage group membership --- Source: https://ai-ops.com/docs/system/roles-permissions Section: System # Roles & Permissions Navigate to **System > Roles** to manage access control. The page uses a split layout: roles listed on the left, details on the right. --- ## Access Levels Every user falls into one of three access levels: | Level | Description | |-------|-------------| | **Superuser** | Full access to everything. Bypasses all permission checks. Cannot be assigned a role. | | **Role** | Custom permissions defined by an administrator. A user can belong to one role at a time. | | **View Only** | Default level for users not assigned to any role. Read-only access: can view data but cannot make changes. | --- ## Built-In Entries Two entries always appear in the role list and cannot be deleted: - **Superusers**: lists all users with superuser privileges. Superuser status is set at the account level, not through role assignment. - **View Only**: lists all users who have no role assigned. This is the default access level. --- ## Creating a Role 1. Click **Create Role** 2. Enter a **Role Name** 3. Optionally select **Base Permissions** to copy permissions from an existing role 4. Click **Create Role** The new role starts with no users. Add users and configure permissions from the role detail panel. --- ## Role Detail Select a role from the list to view its details. The detail panel has two tabs. ### Users Tab Shows all users assigned to this role. From here you can: - **Add users**: click **Add User** and select from a multi-select dropdown. Users already in another role will be moved to this one (a warning is shown). - **Remove users**: click the remove button on a user row. The user moves to View Only. > [!NOTE] One role per user > A user can only belong to one role at a time. Adding a user to a role automatically removes them from their previous role. ### Permissions Tab Permissions are organized by category (Devices, Tags, AI Models, System, etc.). Each category is an expandable section showing toggle switches for individual permissions. A badge on each category header shows the count of enabled toggles out of those available (e.g., "1/2"). Most categories offer a **Manage** toggle and a **Control** toggle; some offer **Manage** only. Toggle the switches to grant or revoke permissions, then click **Save Changes**. All users in the role immediately receive the updated permissions. --- ## Managing Roles ### Editing a Role Click the **edit** button in the role detail header to rename the role. ### Duplicating a Role Open the role's menu (three-dot icon) and select **Duplicate Role**. A new role is created with the same permissions and a name like "Original Name (Copy)". ### Deleting a Role Open the role's menu and select **Delete Role**. A confirmation dialog shows how many users will be moved to View Only. Built-in entries (Superusers, View Only) cannot be deleted. --- ## Permission Categories Permissions are grouped by domain and entity type. Each entity exposes up to two permissions: - **Manage**: full control, including create, edit, and delete. - **Control**: operational actions only, such as enabling or disabling the entity. ### Data Collection | Category | Permissions | |----------|-------------| | **Devices** | Manage, Control | | **Tags** | Manage, Control | | **Device Sets** | Manage, Control | | **Protocols** | Manage | ### AI & Automation | Category | Permissions | |----------|-------------| | **AI Models** | Manage, Control | | **Scan Groups** | Manage, Control | | **Component Libraries** | Manage | | **Component Environments** | Manage, Control | ### Visualization | Category | Permissions | |----------|-------------| | **Trends** | Manage | | **Dashboards** | Manage | ### System | Category | Permissions | |----------|-------------| | **System Administration** | Manage users, roles, licenses, logs, retention | | **System Settings** | Change system settings | | **Events** | Acknowledge events | ### API Access | Category | Permissions | |----------|-------------| | **API Clients** | Manage | Each permission controls a scope of actions. For example, a user with **Control Device** can enable or disable devices, but cannot create, edit, or delete them without **Manage Device**. > [!TIP] Start with a template > When creating a new role, select an existing role's permissions as the base, then adjust individual toggles. This is faster than enabling permissions one by one. --- ## Typical Workflow 1. **Create roles** for your team, for example "Operator" (view + limited control), "Engineer" (full device/tag/model access), "Admin" (everything) 2. **Configure permissions** on each role using the toggle switches 3. **Create user accounts** and assign each user to the appropriate role 4. **Adjust as needed**: add or remove permissions from roles, move users between roles --- ## What's Next - [Users](https://ai-ops.com/docs/system/users.md): create accounts and assign roles --- Source: https://ai-ops.com/docs/system/endpoints Section: System # API Clients Navigate to **System > Connections** to manage API clients. API clients provide OAuth2-style credentials (Client ID + Client Secret) that external systems use to authenticate with the Koios GraphQL and REST APIs. --- ## Client List The client table shows all registered API clients with the following columns: | Column | Description | |--------|-------------| | **Status** | Enabled (teal) or Disabled (gray) | | **Name** | A descriptive name for the client | | **Client ID** | The UUID used for authentication (copyable) | | **Last Used** | When the client last authenticated | | **Created** | When the client was created | Disabled clients appear at reduced opacity and cannot authenticate until re-enabled. ### Bulk Actions Select multiple clients with checkboxes, then use the **Actions** menu to enable, disable, or delete them in bulk. --- ## Creating a Client 1. Click **Add API Client** 2. Enter a **Name** and optional **Description** 3. Click **Create** After creation, a one-time credentials dialog appears showing the **Client ID** and **Client Secret**. Copy both values immediately. The secret cannot be retrieved again. > [!WARNING] Save the secret now > The client secret is only displayed once at creation time. If you lose it, you'll need to regenerate a new secret, which invalidates the previous one. --- ## Client Detail Page Click any client row to view its detail page. ### Overview Tab - **Last Activity**: when the client last authenticated - **Status**: enabled or disabled - **Client Credentials**: the Client ID (copyable) and a masked Client Secret. Click the secret field to regenerate it (with confirmation). - **Description**: the client's purpose, if set ### Roles Tab Assign roles to the API client to control what it can access. Works the same as user role assignment. Select a role from the list to grant the client that role's permissions. An API client can have one role at a time. ### Permissions Tab Displays the effective permissions for the API client based on its assigned role. Permissions are shown grouped by category with toggle indicators, matching the layout used on user detail pages. --- ## Regenerating a Secret If a client secret is compromised or lost, you can regenerate it from the client's detail page: 1. Click the masked secret field in the Credentials card 2. Confirm the regeneration. This invalidates the current secret immediately 3. Copy the new credentials from the dialog Any external system using the old secret will stop authenticating until updated with the new one. --- ## Enabling and Disabling Use the toggle switch in the client detail header or the bulk actions menu on the list page. Disabled clients receive authentication errors on every request. Their credentials remain valid. Re-enabling restores access without regenerating secrets. --- ## What's Next - [Users](https://ai-ops.com/docs/system/users.md): manage user accounts - [Roles & Permissions](https://ai-ops.com/docs/system/roles-permissions.md): control what users and clients can access --- Source: https://ai-ops.com/docs/system/backup Section: System # Backup & Restore Navigate to **System > Backup & Restore** to create backups, manage backup files, and restore the system from a previous state. > [!NOTE] Docker volume backups > For infrastructure-level backups using Docker CLI commands (useful when Koios is not running or for host-level backup scripts), see [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md). --- ## Backup Tiers Every backup is either **Configuration** or **Full**: | Tier | Contents | Typical Size | |------|----------|-------------| | **Configuration** | System database (devices, tags, users, models, settings), media files, certificates, and license | 10–100 MB | | **Full** | Everything in Configuration plus historical time-series data | Varies with retention settings | Configuration backups complete in seconds. Full backups may take several minutes depending on how much historical data exists. --- ## Scheduled Backups The settings section at the top of the page configures automatic backups: | Setting | Description | |---------|-------------| | **Automatic Backups** | Enable or disable scheduled backups | | **Backup Day** | Run daily, or on a specific day of the week (backups run at 2:00 AM) | | **Backup Tier** | Configuration or Full | | **Backups to Keep** | Maximum number of backup files to retain (1–50). When exceeded, the oldest backup is automatically deleted. | Click **Save Changes** after modifying any setting. --- ## Creating a Manual Backup 1. In the **Create Backup** card, select the tier (**Configuration** or **Full**) 2. Click **Create Backup** 3. A progress bar appears showing the current step and completion percentage 4. When finished, the backup appears in the history table below All other actions on the page are disabled while a backup or restore is in progress. > [!TIP] Back up before upgrading > Before updating Koios to a new version, create a manual backup so you have a restore point in case you need to roll back. See [Updating the Koios Version](https://ai-ops.com/docs/updates/general.md). --- ## Backup History The history table lists all existing backups with: | Column | Description | |--------|-------------| | **Filename** | The backup archive name | | **Tier** | Configuration or Full | | **Size** | Archive file size | | **Created** | Timestamp | | **By** | The user who created it | Each row has two actions: - **Download**: saves the backup file to your computer - **Delete**: permanently removes the backup file from the server --- ## Restoring from a Backup 1. In the **Restore from Backup** card, drag and drop (or browse to select) a `.tar.gz` backup file 2. After upload, the backup's metadata is displayed: filename, tier, Koios version, and who created it 3. For **Full** backups, an optional checkbox lets you include historical time-series data in the restore. Leave it unchecked to restore only the configuration. 4. Click **Restore System** 5. A confirmation dialog warns that this will overwrite all current system data 6. Confirm to start the restore. A progress bar tracks the operation. > [!CAUTION] Restore cannot be undone > Restoring overwrites the system database, media files, certificates, license, and data cache. If you included time-series data, that is overwritten too. Consider creating a backup of the current system before restoring from an older one. After a successful restore, services may restart automatically for changes to take full effect. --- ## What's Next - [Data Retention](https://ai-ops.com/docs/system/retention.md): configure how long historical data is kept - [System Overview](https://ai-ops.com/docs/system/information.md): check system status after a restore --- Source: https://ai-ops.com/docs/system/retention Section: System # Data Retention Navigate to **System > Retention** to configure how long Koios keeps historical data and how aggressively it compresses stored values. The page is organized into three sections: storage monitoring, history compression, and retention policies. --- ## Storage Overview The storage overview card shows the current state of disk usage on the Koios server. - **Ring indicator**: percentage of disk used, color-coded: teal (healthy), orange (above 90%), red (above the alarm limit) - **Free space**: remaining capacity in GB - **Daily change rate**: average storage consumed or freed per day - **Projected time remaining**: estimated days until the disk is full, based on the daily rate - **Daily storage chart**: a bar chart showing daily storage deltas for the last 7 days. Green bars indicate growth; blue bars indicate shrinkage (from retention cleanup or manual deletion). ### Storage Alarm Limit Below the chart, a **Storage Alarm Limit** field sets the disk usage percentage that triggers a storage alarm. This setting saves automatically when changed. --- ## History Compression History compression controls how tag values are recorded in the time-series database. Rather than storing every single sample, Koios uses **Swinging Door Trending (SDT)** to discard values that don't meaningfully change the trend. ### How SDT Works SDT maintains a tolerance band (a "door") around the last recorded point. As new values arrive, the algorithm checks whether they fall inside or outside this band. Values inside the band are redundant (the trend line already represents them) and are discarded. When a value falls outside the band, it is recorded and the door resets. The width of the door is controlled by the **Compression Deviation** setting, which is calculated as a **percentage of the tag's configured range** (Range Min / Range Max). For example, a tag with a range of 0–100 and a 2% deviation has a tolerance band of 2.0 units. A tag with a range of 0–1000 and the same 2% deviation has a tolerance band of 20.0 units. ### Settings | Setting | Description | Range | |---------|-------------|-------| | **Compression Enabled** | Master switch. When turned off, all tag values are stored without compression. Individual tags can override this with their own setting. | On / Off | | **Compression Deviation** | Maximum allowed deviation from the trend line, as a percentage of the tag's range. Lower values store more points (higher fidelity). | 0.01–100% | | **Maximum Time Between Samples** | Forces a sample after this many seconds even if the value hasn't deviated. Guarantees a minimum recording rate for stable signals. | 1–86,400s | When compression is disabled, the deviation and maximum time settings are grayed out. They have no effect until compression is re-enabled. > [!TIP] Balancing fidelity and storage > A compression deviation of 1–2% works well for most process data. Critical control signals may benefit from per-tag overrides with tighter deviation. Slow-moving values like ambient temperature can tolerate 5–10%. ### Per-Tag Compression Overrides The settings above apply globally to every tag. If a specific tag needs different compression behavior (tighter tolerance for a critical control signal, or compression disabled entirely for a diagnostic value), you can override the global settings on that tag. On a tag's **Configuration** tab, the **History Compression** section has an **Override global compression settings** toggle. When enabled, three tag-specific settings appear: | Setting | Description | |---------|-------------| | **Compression Enabled** | Whether to compress this tag's history (overrides the global switch) | | **Compression Deviation** | Tag-specific deviation percentage (overrides the global deviation) | | **Maximum Time Between Samples** | Tag-specific forced sample interval (overrides the global interval) | When the override is off, the tag uses whatever is configured here on the Retention page. The tag's configuration shows a link back to this page so you can see what the current global settings are. > [!NOTE] Override scope > Per-tag overrides are fully independent of the global settings. A tag with override enabled uses only its own compression deviation and maximum time. Changes to the global settings have no effect on that tag. This is useful for tags that must always record at high fidelity regardless of how the global settings are tuned. ### Tag Range and Compression Because SDT calculates the tolerance band from the tag's range, **an incorrect range can silently prevent historization**. The default tag range is **0–100**. If a tag's actual values only span a much narrower band (for example 0–1, 4–20 mA, or 0.0–5.0), the tolerance band is far too wide relative to the signal. A 1% deviation on a 0–100 range is 1.0 unit, which is larger than the entire 0–1 signal. The result: almost no data points pass the filter, and Trends show flat lines or missing data. **To avoid this, always set each tag's Range Min and Range Max to match the actual expected value range.** A tag that reads 0–1 should have its range set to 0–1, not the default 0–100. > [!WARNING] Common gotcha with default tag range > If a tag's live value is updating but Trends show flat lines or far fewer recorded points than expected, the most likely cause is a mismatch between the tag's range and the compression deviation. See [Tag is not historizing properly](https://ai-ops.com/docs/troubleshoot/stale-data.md#tag-is-not-historizing-properly) for a step-by-step fix. --- ## Retention Policies Retention policies control automatic cleanup of old data. Three independent retention periods are configurable: | Setting | Description | Range | |---------|-------------|-------| | **History Database Retention** | How long to keep time-series tag history. Specified in weeks. Leave empty for infinite retention. | 1–520 weeks | | **Event Retention** | Automatically delete events older than this many days. | 1–365 days | | **Log File Retention** | Automatically delete log files older than this many days. | 1–90 days | > [!WARNING] Reducing retention deletes data > When you reduce a retention period, existing data older than the new limit is permanently deleted. A confirmation dialog appears before saving any reduction. --- ## What's Next - [Tag Introduction](https://ai-ops.com/docs/tags/introduction.md): tag configuration including per-tag compression overrides - [Troubleshooting a Tag](https://ai-ops.com/docs/troubleshoot/stale-data.md): diagnosing tag errors including historization issues - [System Overview](https://ai-ops.com/docs/system/information.md): disk and hardware details - [Logs](https://ai-ops.com/docs/system/logs.md): view and stream system logs --- Source: https://ai-ops.com/docs/system/performance Section: System # System Health Navigate to **System > Health** to monitor hardware resource usage in real time. The page has four tabs (**CPU**, **Memory**, **Network**, and **Disk**), each with a live chart, alarm configuration, and display options. A red dot on a tab indicates that the metric's alarm is currently active. --- ## Common Controls All four tabs share the same chart controls: | Control | Description | |---------|-------------| | **Time range** | Select from 15 minutes, 1 hour, 6 hours, 24 hours, or 7 days | | **Auto-scroll** | When on, the chart continuously scrolls to show the latest data with a "NOW" marker. Turning it off freezes the view for manual exploration. | | **Zoom & pan** | Scroll to zoom the time axis; click and drag to pan. Double-click to reset. | | **Fullscreen** | Expand the chart to fill the entire screen. Press Escape to exit. | | **Legend** | Click a dataset label in the legend to show or hide it. Some datasets (like CPU Total) are locked and always visible. | The polling interval adapts to the selected time range. Shorter ranges poll more frequently (every 5 seconds for 15 minutes) while longer ranges poll less often (every 2 minutes for 7 days). --- ## CPU Shows overall CPU usage as a percentage (0–100%). ### Additional Datasets - **CPU Cores**: individual usage per logical core. Toggle with the **Show CPU Cores** setting. - **Service Processes**: per-service CPU breakdown (Web App, Data Collector, Predict Engine, etc.). Toggle individual services in the chart legend. ### Settings | Setting | Description | |---------|-------------| | **CPU Alarm Limit** | Percentage threshold that triggers the CPU alarm | | **Show Setpoint** | Display the alarm threshold as a dashed red line on the chart | | **Show CPU Cores** | Overlay per-core usage lines | --- ## Memory Shows memory usage as a percentage of total system RAM. ### Additional Datasets - **Service Processes**: per-service memory usage. Toggle individual services in the chart legend. ### Settings | Setting | Description | |---------|-------------| | **RAM Alarm Limit** | Percentage threshold that triggers the memory alarm | | **Show Setpoint** | Display the alarm threshold as a dashed red line on the chart | | **Show in Bytes** | Switch the Y-axis from percentage to absolute values (GB/MB) | --- ## Network Shows upload and download throughput in MB/s for a selected network interface. ### Interface Selector A dropdown lets you choose which network interface to monitor. Each option shows the interface name, status indicator (teal for up, gray for down), IP address, and link speed. > [!NOTE] Select an interface first > The network chart requires a selected interface. If none is selected, the chart shows a prompt to choose one from the dropdown. ### Settings | Setting | Description | |---------|-------------| | **Network Alarm Limit** | Throughput threshold (MB/s) that triggers the network alarm | | **Show Setpoint** | Display the alarm threshold as a dashed red line on the chart | | **Alarm on Packet Drops** | When enabled, triggers the alarm if incoming or outgoing packet drops are detected | --- ## Disk Shows disk usage as a percentage of total capacity. The live info display includes the current usage percentage, free space remaining, daily change rate, and a projected time-to-full estimate based on recent trends. When that projection runs short or the storage alarm fires, see [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) to diagnose and free up space. ### Settings | Setting | Description | |---------|-------------| | **Storage Alarm Limit** | Percentage threshold that triggers the disk alarm | | **Show Setpoint** | Display the alarm threshold as a dashed red line on the chart | --- ## Alarm Behavior Each metric has an independently configurable alarm threshold. When the current value exceeds the threshold: - A **red dot** appears on the corresponding tab - The **setpoint line** on the chart highlights where the threshold is - The alarm state is checked every 10 seconds Alarm thresholds save automatically when changed, so no save button is needed. > [!TIP] Set meaningful thresholds > A CPU alarm at 90% catches sustained overload without false positives from brief spikes. A storage alarm at 85% gives you time to act before the disk fills. Adjust based on your deployment's normal operating range. --- ## What's Next - [Services](https://ai-ops.com/docs/system/services.md): view individual service status, restart services - [Network Diagnostics](https://ai-ops.com/docs/system/network.md): ping, traceroute, and port checks - [Data Retention](https://ai-ops.com/docs/system/retention.md): manage storage growth with retention policies --- Source: https://ai-ops.com/docs/system/network Section: System # Network Navigate to **System > Network** to scan your local network for devices, view interface details, and run diagnostic commands from the Koios server. The page is organized into three tabs: **Interfaces**, **Scanner**, and **Diagnostics**. --- ## Interfaces The Interfaces tab displays a card for each network interface detected on the server. Each card shows: - **Status:** Up (teal icon) or Down (gray icon) with a status badge - **Name:** the interface identifier (e.g. `eth0`, `lo`, `docker0`) - **Link details:** speed (Mbps), MTU, and duplex mode when available - **IPv4 Address:** copyable - **Subnet Mask:** copyable - **Gateway:** copyable, if detected - **IPv6 Address:** copyable, if assigned - **MAC Address:** copyable Click any address or value to copy it to the clipboard. --- ## Scanner The Scanner tab lets you discover hosts on your plant network using ARP scanning, then view and manage the results in a table. ### Running a Scan The **Network Scanner** card at the top contains three fields: - **Interface:** select the network interface to scan from. Only active interfaces with an IPv4 address are shown. The first active interface is selected by default. - **IP Range:** CIDR notation for the subnet to scan (e.g. `192.168.1.0/24`). Auto-populated based on the selected interface. A description below the field shows the exact host range and count that will be scanned. - **Scan:** starts the ARP scan. A progress bar appears showing the current step (scanning, resolving hostnames, saving results). ### How ARP Scanning Works The network scanner sends raw ARP packets to discover hosts on your subnet. This uses a container capability called `NET_RAW`, which is included in Docker's default capability set. No extra configuration is needed for standard Docker deployments. The capability is scoped to a single dedicated process inside the container. All other Koios services (the web server, data collector, predict engine, etc.) are unaffected. The scanner can only broadcast ARP "who has this IP?" requests and read the replies on the selected interface. It cannot access traffic on other networks, read application data, or bypass firewall rules. ### Disabling ARP Scanning If your security policy requires removing raw network access from containers, you can explicitly drop the `NET_RAW` capability. This will disable the scanner. A yellow banner will appear on the Scanner tab explaining that scanning is unavailable. To disable scanning, add the `--cap-drop=NET_RAW` flag to your container start command: ```bash docker run --cap-drop=NET_RAW ... aiopinc/koios:latest ``` If you are running Koios as a systemd service, add the flag to the `ExecStart` line in your service file: ```ini ExecStart=/usr/bin/docker run --rm --name=%n --network host --cap-drop=NET_RAW ... ``` Then restart the service: ```bash sudo systemctl daemon-reload sudo systemctl restart docker.koios.service ``` > [!NOTE] Kubernetes deployments > Kubernetes Pod Security Standards may drop all capabilities by default. If scanning is unavailable in a Kubernetes deployment, add `NET_RAW` to the container's `securityContext.capabilities.add` list. ### Discovered Hosts Table Below the scanner card, a table displays all hosts discovered on the selected interface. Each row shows: | Column | Description | |--------|-------------| | **IP Address** | The host's IPv4 address (copyable) | | **MAC Address** | Hardware address (copyable) | | **Vendor** | Manufacturer identified from the MAC address OUI database | | **Hostname** | Reverse DNS hostname, if available | | **Alias** | User-defined friendly name (editable) | | **Notes** | Free-text notes (editable) | | **Last Seen** | When the host last responded to a scan | **Unresponsive hosts:** hosts that were previously discovered but did not respond during the most recent scan are dimmed in the table. Their "Last Seen" column shows the timestamp of the last successful response. ### Table Actions Open the **Actions** dropdown above the table to access: - **Edit Mode:** toggle inline editing for the Alias and Notes columns. - **Delete unresponsive hosts:** remove all hosts on the current interface that did not respond during the last scan. Useful for cleaning up stale entries without selecting them individually. A confirmation dialog appears before deletion. - **Bulk delete:** select rows using the checkboxes, then delete the selected hosts. Deleted hosts will reappear on the next scan if they are still active. Right-click any row to open a context menu with edit and delete options for that individual host. > [!TIP] Keeping the table clean > After running a scan, hosts that have gone offline are automatically dimmed. Use **Delete unresponsive hosts** in the Actions menu to remove them in one step rather than selecting and deleting individually. --- ## Diagnostics The Diagnostics tab provides four network diagnostic tools. Select a tool, enter a target, and click **Run**. Results stream in real time to a terminal-style output area. ### Ping Sends ICMP echo requests to a target host. Enter a hostname or IP address and the number of packets to send (1–100, default 4). Useful for checking basic connectivity and round-trip latency. ### Traceroute Traces the network path to a target host, showing each hop along the route. Enter a hostname or IP address. Useful for identifying where packets are being dropped or delayed. ### DNS Lookup Queries DNS records for a domain name. Select the record type from the dropdown: | Record Type | Description | |-------------|-------------| | **A** | IPv4 address | | **AAAA** | IPv6 address | | **MX** | Mail exchange server | | **NS** | Nameserver | | **TXT** | Text record | | **CNAME** | Canonical name (alias) | | **SOA** | Start of authority | | **PTR** | Pointer (reverse lookup) | | **SRV** | Service locator | ### TCP Port Check Tests whether a specific TCP port is reachable on a target host. Enter the hostname or IP, port number (1–65535, default 80), and timeout in seconds (1–30, default 5). Useful for verifying that a device's communication port is open before configuring a connection. > [!TIP] Test device connectivity > Use the TCP port check to verify that a device is reachable before creating a device connection. For example, check port 4840 for OPC-UA or port 502 for Modbus TCP. If a connection is already failing, see [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) to diagnose it. ### Results Terminal Diagnostic output streams to a terminal panel below the tool form. The terminal supports: - **Auto-scroll:** follows new output as it arrives. Scroll up to pause; scroll back to the bottom to resume. - **Pause/Resume:** buffer output while paused; flush on resume. - **Clear:** remove all output from the terminal. --- ## What's Next - [System Overview](https://ai-ops.com/docs/system/information.md): IP address, hostname, and hardware details - [System Health](https://ai-ops.com/docs/system/performance.md): network throughput monitoring and alarms --- Source: https://ai-ops.com/docs/system/services Section: System # Services Navigate to **System > Service Status** to view the status of all Koios services and start, stop, or restart them as needed. --- ## Service Tables Services are divided into two tables: ### Application Services | Service | Description | |---------|-------------| | **Data Collector** | Industrial device polling | | **Predict Engine** | AI model inference | | **Expression Evaluator** | Calculated tags and user-defined expressions | | **Parameter Mapping** | Data transformation and normalization | | **Performance Monitoring** | System metrics collection | | **Component Engine** | Custom component execution | The web application server (API, GraphQL) is not listed here. Its health and version are shown on System Overview instead. ### Infrastructure | Service | Description | |---------|-------------| | **Celery Worker** | Asynchronous task queue | | **Configuration database (PostgreSQL)** | Stores device, tag, user, and model configuration | | **Time-series database (InfluxDB)** | Stores historical tag values for trends and analysis | | **In-memory cache (Cache)** | Caches live tag values and status for real-time access | | **Nginx** | Web proxy and SSL termination | | **Telegraf** | Metrics collection agent for system monitoring | Each table shows the service name, status, CPU usage, memory usage, PID, and uptime. **Event Relay** runs as a dedicated process that bridges the live-data cache pub/sub to WebSocket event notifications. It is not listed on the Services page. --- ## Status Indicators | Status | Color | Meaning | |--------|-------|---------| | **Running** | Teal | Service is healthy and responding | | **Stopped** | Gray | Service is not running | | **Failed** | Red | Service crashed or exited with an error | | **Starting** | Yellow | Service is in the process of starting | | **Stopping** | Yellow | Service is in the process of stopping | | **Unresponsive** | Orange | Process is running but not sending healthy heartbeats | | **Standalone** | Orange | Heartbeats are healthy but the process is not managed by the service manager | Hover over any status badge for a plain-language explanation. --- ## Service Detail Drawer Click any service row to open its detail drawer. ### Overview Tab - **Description**: what the service does - **Metrics**: CPU, memory, thread count (application services only), PID, and uptime - **Last Heartbeat**: when the service last reported in (application services only). Shows as "Last Seen" if the service is stopped. - **Error Info**: if the service has a reported error, the error message and detail are displayed - **Service Info**: the system service name, category, and current process state ### Diagnostics Tab Appears only for application services that have diagnostic data available. Shows real-time workload metrics: - **Pressure**: thread pool utilization as a rolling average. Indicates how busy the service is. - **In-Flight**: tasks currently executing - **Queued**: tasks waiting to execute If the service supports on-demand operations (like the Data Collector or Predict Engine), a separate set of on-demand pressure, in-flight, and queued metrics is also shown. **Top Contributors**: for the Predict Engine, lists the AI models putting the highest load on the service, with progress bars and contribution percentages. Click a model name to navigate to its detail page. A badge appears on the Diagnostics tab when pressure reaches warning levels (yellow at 70%, red at 90%); see [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) to diagnose a service that is failing or under sustained load. --- ## Service Actions Action buttons appear in the detail drawer footer based on the service's current state: | Current State | Available Actions | |---------------|-------------------| | **Stopped / Failed** | Start | | **Running / Unresponsive** | Restart, Stop | | **Starting / Stopping** | None (wait for transition) | - **Start** and **Restart** execute immediately - **Stop** shows a confirmation dialog before proceeding After any action, the service list refreshes automatically. The configuration database, in-memory cache, and web proxy cannot be started, stopped, or restarted from the UI. No action buttons appear for these services. --- ## Service Diagnostics Settings Below the service tables, a **Service Diagnostics** section lets you configure advanced metric recording for application services. These settings control whether pressure, queue depth, and top contributor data are collected and made available in the detail drawer's Diagnostics tab. --- ## What's Next - [System Health](https://ai-ops.com/docs/system/performance.md): CPU, memory, disk, and network monitoring with alarms - [Logs](https://ai-ops.com/docs/system/logs.md): stream real-time logs for any service --- Source: https://ai-ops.com/docs/system/logs Section: System # Logs Navigate to **System > Service Logs** to stream real-time output from any Koios service or browse archived log files. The page has two tabs: **Live Logs** and **Log Files**. --- ## Live Logs The Live Logs tab streams log output from a selected service in real time using server-sent events (SSE). ### Selecting a Service The left panel lists all available services. Each entry shows the service name, a brief description, and a badge indicating its current log level. Click a service to begin streaming its logs in the terminal on the right. Use the search bar at the top of the list to filter services by name or description. ### Log Terminal Once a service is selected, its log output streams into a terminal-style viewer. | Control | Description | |---------|-------------| | **Log level** | Dropdown to change the service's verbosity (Debug, Info, Warning, Error, Critical). Takes effect immediately. | | **Search** | Text filter that hides lines not matching your query. The footer shows how many lines match (e.g., "50 of 200 lines"). | | **Auto-scroll** | The terminal follows new output automatically. Scroll up to pause auto-scroll; scroll back to the bottom to resume. A floating jump-to-bottom button appears when scrolled up. | | **Pause / Resume** | Pauses incoming lines without disconnecting. Buffered lines are shown in the footer and flush to the terminal when you resume. | | **Clear** | Removes all lines from the terminal. | ### Log Level Colors Lines are color-coded by severity: | Level | Color | |-------|-------| | **Critical** | Red (bold) | | **Error** | Red | | **Warning** | Yellow | | **Info** | Cyan | | **Debug** | Gray | ### Connection Status A badge in the terminal footer shows the current streaming state: **Connecting**, **Connected**, **Error**, or **Disconnected**. The connection automatically attempts to reconnect on error. > [!TIP] Adjust log level for troubleshooting > Set a service to **Debug** for maximum detail when investigating an issue, then return it to **Info** or **Warning** afterward to reduce noise. The change applies immediately, with no service restart required. --- ## Log Files The Log Files tab lets you browse, search, and download archived log files stored on the server. ### File List The left panel lists all log files with their filename, associated service, file size, and last-modified date. Click a file to open it in the viewer on the right. Each file has a context menu (three-dot icon) with options to **View**, **Download**, or **Delete** the file. Deleting a log file is permanent and requires confirmation. Use the search bar to filter files by name or service. ### File Viewer The file viewer displays the selected log file with line numbers, color-coded by log level (same colors as the live terminal). | Control | Description | |---------|-------------| | **Search** | Text search within the file. Filters to lines containing your query and resets to page 1. | | **Level filter** | Dropdown to show only lines at a specific severity (Debug, Info, Warning, Error, Critical) or all levels. | | **Pagination** | Files are displayed 500 lines per page. Use the Previous / Next buttons to navigate. The footer shows the current page, total pages, and total line count. | | **Refresh** | Re-fetches the current page to pick up newly written lines. | | **Download** | Downloads the full log file to your computer. | > [!NOTE] Server-side filtering > Search and level filters are applied on the server, so only matching lines count toward pagination. This makes it efficient to find specific entries in large log files. --- ## Settings The Settings tab provides configuration options for log-related behavior: - **Debug Timer**: configure how long debug-level logging stays active before automatically reverting to the previous log level. This prevents accidentally leaving services in verbose debug mode. - **Log File Retention**: set how long archived log files are kept before automatic cleanup. Older files are removed to manage disk usage. - **Active Debug Services**: lists all services currently running with debug-level logging enabled, along with how much time remains before each reverts. --- ## What's Next - [Services](https://ai-ops.com/docs/system/services.md): view service status, restart services, and check diagnostics - [System Health](https://ai-ops.com/docs/system/performance.md): monitor CPU, memory, network, and disk usage --- Source: https://ai-ops.com/docs/troubleshoot/introduction Section: Troubleshoot # Troubleshooting Koios This is the starting point when something in Koios isn't working. Find what you're seeing in the symptom table below and jump straight to the guide that covers it. If you're not sure where to start, read [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) first — it explains the three diagnostic fields (error code, error message, error detail), the status and quality legend, and the master error-code lookup that every other article references. ## What Are You Seeing? | Symptom | Where to go | |---------|-------------| | A device is **Failed** / offline, won't connect, or a **Test** connection fails | [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | A tag has **no value**, bad quality, a frozen value, or a read/write error | [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | A **calculation tag** or **value mapping** is throwing an error | [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) | | A **model** or one of its **bindings** won't run, or predictions are wrong | [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) | | **Trends are flat**, history has gaps, or data looks stale everywhere | [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) | | A **service** is unhealthy, a **heartbeat** is stale, or a **CPU / memory / disk / network** alarm is active | [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | A **scan group** is failing or **overscanning** | [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | A **license** warning, invalid license, or **Unlicensed (999)** on a device / tag / model | [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md) | | The **server won't load** or the container won't start | [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md) | | You've fixed nothing yet and need to **file a support ticket** | [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md) | ## Work Down the Stack Koios processes data in layers. A failure almost always lives at the layer where you see it, or one layer below it. When you troubleshoot, start where the symptom appears and work **downward** until the errors stop pointing further down. ```text Layer 5 Platform services, heartbeats, CPU / memory / disk / network, license ▲ Layer 4 Inference models run on collected + processed data ▲ Layer 3 Transformation expressions and value mappings turn raw reads into usable values ▲ Layer 2 Collection the datacollector reads tag values on each scan cycle ▲ Layer 1 Connection a device holds the link to the industrial endpoint ``` The chain of causation runs bottom-up: a **model** fails because one of its **binding tags** is bad; that **tag** is bad because its parent **device** is down; that **device** is down because of a **network or certificate** problem. Fixing the lowest broken layer clears everything above it automatically — errors self-heal on the next successful scan or inference cycle. > [!TIP] Follow the error down, not up > When every input on a model shows "Binding Tag Failed" or "Parent Failed", stop looking at the model. Open the failing tag, then its device. The real fix is at the bottom of the stack, and it cascades back up on its own. A few concrete chains you'll see: - **All tags on one device show "Parent Failed" (tag code 1)** → the device itself failed (connection layer). Fix the device; the tags clear. See [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). - **A model shows "Binding Tag Bad Quality" or "Binding Tag Failed" (binding codes 12 / 13)** → the bound tag has a read problem (collection layer). Fix the tag. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). - **A binding shows "Bad: Expression" or "Mapping Error" (tag codes 110 / 108)** → the transformation layer failed on that tag. See [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md). - **A binding shows "Upstream Model Failure" (binding code 17)** → the input tag is written by another model that is itself failing. Fix the upstream model first. ## Reading the System Alerts Banner The alerts panel in the top bar aggregates every active problem across the platform. Each alert category maps to one troubleshooting guide — use it as a shortcut to the right layer: | Alert | What it means | Where to go | |-------|---------------|-------------| | **No License Found** / **License Invalid** / **License Grace Period** | Licensed functionality may be limited, or your license is expiring | [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md) | | **N Failed Devices** | One or more devices failed to connect | [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | **N Failed Tags** | One or more tags are in a failed state | [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | **N Failed Models** | One or more AI models have failed | [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) | | **N Failed Scan Groups** | One or more scan groups have failed | [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | **N Unhealthy Services** | A background service is not running | [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | **N Performance Alarms** | A CPU, Memory, Disk, or Network threshold was crossed | [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | > [!NOTE] Failed counts are cascades, not separate problems > A single failed device inflates the failed-tag and failed-model counts too, because every tag on that device and every model bound to those tags fails with it. Clear the device alert first and watch the tag and model counts fall on their own. ## The Universal Recovery Path Whatever the layer, the same loop applies. Errors are not sticky — they clear on the next successful cycle, so your job is to fix the underlying cause, not to dismiss the error: 1. Read the **error message** and **error detail** on the failed entity to get the specifics. 2. Open the entity's **Logs** tab and set the log level to **Debug** for maximum detail. See [System Logs](https://ai-ops.com/docs/system/logs.md). 3. Work **down** the stack — if the error points at a lower layer (parent device, binding tag, upstream model), go fix that first. 4. Correct the configuration or connection, or use the **Test** button to confirm the fix in isolation. 5. As a last resort, toggle the entity off and on with the **Enabled** switch. For the full field-by-field explainer, the status and quality color legend, and the "why is this stuck?" checklist, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) — the shared reference: three diagnostic fields, status and quality legend, stuck checklist, master code lookup - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) — layer 1: device and tag connectivity, certificates, network, Test - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) — layer 2: bad quality, no value, read/write, configuration - [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) — layer 3: transformation errors - [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) — layer 4: model and binding inference - [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) — cross-cutting: historization and trends gaps - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) — layer 5: services, heartbeats, resource alarms, scan groups - [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md) — license state and Unlicensed (999) - [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md) — container, logs, and restart during an outage - [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md) — what to gather before opening a ticket - [System Logs](https://ai-ops.com/docs/system/logs.md) — set the Debug log level and stream service logs --- Source: https://ai-ops.com/docs/troubleshoot/reading-status-and-errors Section: Troubleshoot # Reading Status, Quality & Errors Every device, tag, model, binding, and scan group in Koios reports its health the same way: a **status**, and — when something goes wrong — three diagnostic error fields. This page is the shared reference for reading those signals and for looking up any error code you see anywhere in the product. Start here, then follow the link for your specific error code to the article that owns its cause and fix. ## The Three Diagnostic Fields When an entity hits a problem, Koios records three pieces of information: - **Error Code**: a category that identifies _what kind_ of failure occurred (e.g. `1 — Failed to Connect`). - **Error Message**: a short, human-readable description of the problem. - **Error Detail**: additional context, typically the underlying exception or system message that caused the failure. Together they tell you what went wrong, why, and where to start investigating. The **error code** points you to the right troubleshooting article (see the [master lookup](#master-error-code-lookup) below); the **error message** and **error detail** give you the specifics for that instance. > [!TIP] Copy errors quickly > On any detail page, click the red error strip to copy both the error message and error detail to your clipboard. This is useful when sharing diagnostics or searching logs. ## Status Legend Every entity reports one of three stored statuses — **Running**, **Stopped**, or **Failed**. The rest of the states below are derived at display time by combining that status with the entity's enabled flag, its parent's state, and any advisory or test conditions. | Status | Color | Meaning | |--------|-------|---------| | **Running** | Teal | Enabled entity operating normally. | | **Stopped** | Gray | Disabled or cleanly stopped entity. | | **Failed** | Red | The entity hit a failure; an error message is shown. | | **Starting** | Gray | Transitional: enabled but not yet running (spinning up). Shown as an animated spinner. | | **Stopping** | Gray | Transitional: disabled but still shutting down. Shown as an animated spinner. | | **Warning** | Amber | Running, but with an advisory (e.g. overscanning). Behavior is normal; the amber strip flags attention. | | **Testing** | Violet | A manual test-output override is active (test mode). Overrides the normal status display. | | **Parent Disabled** | Gray | Stopped because the parent device or scan group is disabled. Not a transition — genuinely idle until the parent is enabled. | > [!NOTE] Only three statuses are stored > Running, Stopped, and Failed are the only persisted states. Starting, Stopping, Warning, Testing, and Parent Disabled are computed in the interface from those three plus context — you will not find them as distinct values in exports or the API. ## Data Quality Legend Each tag also carries a **quality** value describing how much you can trust its most recent reading. Quality is a free-form string, so the exact text depends on the protocol, but it collapses to a few meanings: | Quality | Color | Meaning | |---------|-------|---------| | **Good** | Teal | Successful read; the value is trustworthy. | | **Bad** | Red | Read failed or the value is not trustworthy. Set on any read exception across every protocol. Drives tag error code `107 — Bad: Read Quality`. | | **Uncertain** | Amber | OPC-UA only: the server returned an Uncertain-class status code. A value is present but the source flagged it as questionable. | | _OPC-UA status code name_ | Gray | For OPC-UA reads, quality is the raw status code name (e.g. `Good`, `Uncertain`, `Bad_NodeIdUnknown`). Any `Bad_*` code, or an exception, collapses to `Bad`. | > [!NOTE] Quality is not the same as an error code > A `Bad` quality reading is what triggers the tag error `107 — Bad: Read Quality` and the binding error `12 — Binding Tag Bad Quality`. Those are error codes _caused by_ bad quality — not quality values themselves. ## Where Errors Surface The same three fields appear in several places across the product: - **Detail page hero + red strip**: a device, tag, model, or binding's Overview tab shows the status hero at the top. In a **Failed** state, a red error strip appears below it with the error message and detail. Click it to copy. - **List tooltips**: in list tables, each row shows a colored status icon. Hovering a red icon displays that entity's error message as a tooltip. - **Parameters / Live Data**: all three fields (error code, error message, error detail) are visible under the **Parameters** tab's **Live Data** section, alongside live values, timestamp, and scan progress. - **Bindings tab (models)**: each binding card turns red and expands to show its own error message and detail inline — the most precise view of _which_ input or output failed. ## Auto-Clear Behavior You never manually acknowledge or dismiss an error. Errors clear on their own: once the underlying issue is resolved, the next successful scan or inference cycle resets the error code to **None** and clears the message and detail. An error code of **0 (None)** means the entity has no active error — you will see this on healthy entities and after a problem resolves. ## Stuck-Entity Checklist If an entity stays failed and does not recover on its own, work through these five steps in order: 1. **Read the error message and detail.** They name the specific failure. Look up the error code in the [master lookup](#master-error-code-lookup) to find the article that covers its cause and fix. 2. **Review the logs at Debug level.** Open the entity's Logs tab and raise the log level for maximum detail. See [System Logs](https://ai-ops.com/docs/system/logs.md) for setting the Debug level and streaming logs. 3. **Verify the configuration.** Check the connection parameters (devices) or protocol settings (tags) on the Configuration tab. 4. **Use Test.** Run a one-time connection or read from the Configuration tab to reproduce the error in isolation, without enabling the entity. 5. **Toggle off and on.** Flip the **Enabled** switch off, then on, to force a fresh start. ## Master Error-Code Lookup Every error code in Koios is listed below, grouped by the entity it belongs to. Each row links to the troubleshooting article that owns the **cause and fix** for that code. This page is the index — the detailed remediation lives in the linked article. Error codes are non-contiguous by design (they band by failure stage), so gaps in the numbering are expected. ### Device Error Codes | Code | Meaning | Where to go | |------|---------|-------------| | 0 | None — operating normally | — | | 1 | Failed to Connect | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 5 | Failed to Read from Device | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 6 | Failed to Write to Device | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 7 | Failed to Read Config from Database | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 11 | Failed to Initialize | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 12 | Failed to Write to Model History | [Stale Data](https://ai-ops.com/docs/troubleshoot/stale-data.md) | | 13 | Failed to Write to Long Term History | [Stale Data](https://ai-ops.com/docs/troubleshoot/stale-data.md) | | 14 | Failed to Update Heartbeat | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 15 | Failed to Cleanup | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 16 | Failed to Validate Tags | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 17 | Failed to Write Executions | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 999 | Unlicensed | [Licensing](https://ai-ops.com/docs/troubleshoot/licensing.md) | ### Tag Error Codes | Code | Meaning | Where to go | |------|---------|-------------| | 0 | None — value is good | — | | 1 | Parent Device Failed | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 2 | Generic Exception | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 100 | Bad: General | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 101 | Bad: Failed to Write | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 102 | Bad: Node Not Found | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 103 | Bad: Not a Number | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 104 | Bad: Configuration Error | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 105 | Bad: No Value | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 106 | Bad: Failed to Read | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 107 | Bad: Read Quality | [Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) | | 108 | Mapping Error | [Expressions & Mapping](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) | | 109 | No Active Device | [Connection](https://ai-ops.com/docs/troubleshoot/connection.md) | | 110 | Bad: Expression | [Expressions & Mapping](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) | | 200 | Failed to Historize | [Stale Data](https://ai-ops.com/docs/troubleshoot/stale-data.md) | | 999 | Unlicensed | [Licensing](https://ai-ops.com/docs/troubleshoot/licensing.md) | ### Model Error Codes | Code | Meaning | Where to go | |------|---------|-------------| | 0 | None — operating normally | — | | 1 | No File Given | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 2 | No File Found | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 3 | Failed to Parse File | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 4 | Failed to Get Model Depth | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 5 | Failed to Get Bindings | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 6 | Bindings Invalid State | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 7 | Failed to Structure History | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 8 | Failed to Get Predictions | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 9 | Binding Prediction Index Missing | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 10 | Failed to Scale Predictions | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 11 | Failed to Write Predictions | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 12 | Thread Error | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 13 | Generic Exception | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 999 | Unlicensed | [Licensing](https://ai-ops.com/docs/troubleshoot/licensing.md) | ### Binding Error Codes | Code | Meaning | Where to go | |------|---------|-------------| | 0 | None — operating normally | — | | 1 | Not Enough Historical Depth | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 2 | Stale History Data | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 3 | No Range Given | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 4 | Invalid Range Given | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 5 | Value Out of Range | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 6 | Failed to Normalize | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 7 | Failed to Structure History | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 8 | Prediction Index Missing | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 9 | Failed to Scale Prediction | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 10 | Failed to Write Prediction | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 11 | Binding Tag Disabled | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 12 | Binding Tag Bad Quality | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 13 | Binding Tag Failed | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 14 | Binding Tag Not Assigned | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 15 | Binding Not in Dictionary | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 16 | Failed to Structure Input Data | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 17 | Upstream Model Failure | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 18 | General Model Failure | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 19 | Rate of Change Exceeded | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 20 | On-Demand Read Failed | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 21 | Invalid Calibration | [Models](https://ai-ops.com/docs/troubleshoot/models.md) | | 999 | Unlicensed | [Licensing](https://ai-ops.com/docs/troubleshoot/licensing.md) | ### Scan Group Error Codes | Code | Meaning | Where to go | |------|---------|-------------| | 0 | None — running normally | — | | 1 | Overscan | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 2 | On-Demand Read Failed | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 3 | On-Demand Write Failed | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | | 99 | Generic Exception | [Services & Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) | > [!NOTE] Scan groups have no license code > Scan groups do not report `999 — Unlicensed`. Their catch-all is `99 — Generic Exception`. ## What's Next - [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md) — the symptom router that points you to the right layer - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) — device and tag connectivity, certificates, network, and the Test button - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) — bad quality, no value, read/write, and configuration errors - [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) — calculated-field and mapping failures - [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) — model and binding inference errors - [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) — historization and trend gaps - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) — services, heartbeats, scan groups, and resource alarms - [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md) — license state and the Unlicensed (999) code - [System Logs](https://ai-ops.com/docs/system/logs.md) — set the Debug log level and stream logs --- Source: https://ai-ops.com/docs/troubleshoot/connection Section: Troubleshoot # Troubleshoot a Connection A connection problem starts at the device and cascades to every tag underneath it. Before you chase individual tag errors, confirm the device can reach its industrial endpoint. This is layer 1: the physical and protocol link between Koios and your PLC, sensor, controller, or OPC-UA server. This page covers the device-level failures, the tag errors they trigger, certificate trust for secure OPC-UA connections, network reachability, and the two different **Test** mechanics for devices and tags (they do not work the same way — see the gotcha below). For the three diagnostic fields (error code, error message, error detail), the full status and quality legend, the auto-clear behavior, and the master error-code lookup, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). This page does not restate those — it goes straight to connection causes and fixes. > [!NOTE] Errors clear on the next good scan > You never acknowledge or dismiss a connection error. Once the underlying issue is fixed, the next successful scan resets the error code to **None** and clears the message and detail automatically. If an error is stuck, work through the checklist in [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). ## Start Here: Is It the Device or the Tag? Look at the status of the device and its tags together: | What you see | Where the problem is | Go to | |--------------|----------------------|-------| | Device **Failed**, all tags show **Parent Device Failed** (code 1) | The device connection — fix this first | [Device won't connect](#device-wont-connect) | | Device **Running**, one or a few tags **Failed** | Those specific tags, not the link | [Tag-level failures](#tag-level-failures) | | Device **Failed** with a certificate message | OPC-UA trust | [OPC-UA certificate trust](#opc-ua-certificate-trust) | | A redundant tag shows **No Active Device** (code 109) | No device in the set is active | [Redundant device sets](#redundant-device-sets) | When every tag on a device shows **Parent Device Failed**, do not troubleshoot the tags — they are just reporting that their parent is down. Fix the device, and the tag errors clear on their own. ## Device Won't Connect A device in the **Failed** state with error code **1, Failed to Connect** means Koios could not establish a link to the industrial endpoint. Work through these causes in order. ### Connection-relevant device error codes | Code | Name | What to do | |------|------|------------| | 1 | **Failed to Connect** | Koios could not open a connection. Check that the device is powered on, reachable on the network, and that the hostname, port, and credentials are correct. | | 11 | **Failed to Initialize** | The connection opened but the device could not complete its startup sequence (loading initial tag state from the cache, preparing for the first scan). Often a transient issue — toggle the device off and on. If it persists, check the logs. | | 16 | **Failed to Validate Tags** | Tag configuration could not be validated before scanning. One or more tags have invalid or missing protocol-specific settings (e.g. a Modbus tag without a register address). See [Fix the offending tag](#failed-to-validate-tags-code-16) below. | | 7 | **Failed to Read Config from Database** | Koios could not read the device's configuration from the configuration database. This is rare and usually points at a database connectivity issue rather than the device. Check service health. | | 5 | **Failed to Read from Device** | The connection was established but a read failed mid-scan. The device may have become unreachable, or a tag references an invalid address. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). | | 6 | **Failed to Write to Device** | An output write failed. Check that output tags have valid addresses and that the device allows writes with the current credentials. | ### Causes of "Failed to Connect" **Wrong hostname or port.** Verify the address on the device's **Configuration** tab. A typo, a stale IP after a DHCP lease change, or the wrong port are the most common causes. Confirm the standard port for the protocol: | Protocol | Default TCP port | |----------|------------------| | OPC-UA | 4840 | | Modbus TCP | 502 | **The device is unreachable on the network.** Use **System > Network > Diagnostics** to prove reachability before you touch the device config: - **Ping** the device's IP to confirm basic connectivity and latency. - **Traceroute** to see where packets are dropped or delayed if ping fails. - **TCP Port Check** to confirm the communication port is actually open — check port 4840 for OPC-UA or port 502 for Modbus TCP. See [Network](https://ai-ops.com/docs/system/network.md) for the full diagnostics toolset. If ping and the port check both fail, the problem is upstream of Koios — a cable, switch, VLAN, or the device being offline — not your device configuration. **A firewall is blocking the port.** If ping succeeds but the TCP port check fails, a firewall (on the device, a network segment, or the host) is blocking the protocol port. Open the port or adjust the rule, then re-test. **Wrong security mode or missing certificate (OPC-UA).** If the device uses Security Mode **Sign** or **Sign & Encrypt** and the server rejects the connection, it is a trust problem, not a network problem. See [OPC-UA certificate trust](#opc-ua-certificate-trust). **Bad credentials.** If the endpoint requires authentication and the connection is refused with an auth-related message, verify the username and password on the Configuration tab. For OPC-UA, confirm whether the server expects anonymous, username/password, or certificate-based authentication. > [!WARNING] host.docker.internal is dev-only > In the local development environment, device connections to QA servers running on the host machine use `host.docker.internal` (e.g. `opc.tcp://host.docker.internal:4840`) instead of `localhost`. **This does not apply to production.** On a deployed Koios container, use the device's real hostname or IP on the plant network. Never leave `host.docker.internal` in a production device configuration — it will not resolve. ### Failed to Validate Tags (code 16) A device that reports **Failed to Validate Tags** connected successfully but has at least one tag whose protocol settings are invalid or incomplete. Koios validates every tag before it starts scanning, so one bad tag blocks the whole device. The corresponding tag error is **Configuration Error** (tag code 104): a Modbus tag without a register address, an OPC-UA tag with a malformed node ID, or a BOSS tag with an invalid variable code. Find the tag with the configuration error, correct its settings on the tag's **Configuration** tab, and the device validation passes on the next attempt. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) for the per-tag configuration fixes. ## Tag-Level Failures When the device is **Running** but individual tags fail, the connection is fine — the problem is specific to those tags. The connection-relevant tag error codes are: | Code | Name | What to do | |------|------|------------| | 1 | **Parent Device Failed** | The parent device is in a failed state, so the tag cannot be collected. Not a tag problem — [fix the device](#device-wont-connect). Clears automatically when the device recovers. | | 104 | **Bad: Configuration Error** | The tag's protocol-specific settings are invalid or incomplete (bad address, malformed node ID, missing register). Review and correct the tag's **Configuration** tab. This is also what drives device code 16. | | 102 | **Bad: Node Not Found** | The addressed node, register, or variable was not found on the device. For OPC-UA, the namespace index or identifier may have changed — use the **Browse** button to re-select the correct node. | | 105 | **Bad: No Value** | No value was returned. The data point may not exist, the register may be empty, or the device returned null. Confirm the tag's protocol settings point at a real data point. | | 106 | **Bad: Failed to Read** | A general read failure. Common causes are invalid addresses, permission issues, or the device disconnecting mid-scan. Check the error detail for the specific exception. | | 109 | **No Active Device** | The tag reads from a device set (redundancy) but no device in the set is active. See [Redundant device sets](#redundant-device-sets). | For bad-quality reads, expression failures, mapping errors, and the range/compression issues that cause missing history, see the deeper layers: [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) and [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md). ### The "Parent Device Failed" cascade Every tag on a failed device inherits **Parent Device Failed** (code 1). This is by design: the device can't be reached, so its tags can't be collected. Do not try to fix these tags individually — navigate to the device's detail page, resolve the device error, and watch every tag clear at once on the next successful scan. If a tag is enabled but its parent device is merely **stopped** (not failed), you'll see an info banner (not an error) telling you the device is stopped and the tag won't update until it is enabled and running. Enable and start the parent device to begin scanning. This is not an error condition. ### Redundant device sets A tag configured for redundancy reads from a **device set** rather than a single device. When it reports **No Active Device** (tag code 109), no device in the set is currently active — every member is disabled, stopped, or failed. To fix it, make sure at least one device in the set is enabled and running. Open each member device and troubleshoot its connection using the [Device won't connect](#device-wont-connect) steps above. As soon as one device comes online, the redundant tag begins reading from it and the error clears. ## OPC-UA Certificate Trust If an OPC-UA device fails to connect with a message like *"Certificate rejected by server"*, the network is fine — the server does not trust Koios's client certificate. Certificates are only involved when the device's Security Mode is **Sign** or **Sign & Encrypt**. With Security Mode **None**, no certificate is used and this is not your problem. The trust flow, in short: 1. In Koios, generate or upload a client certificate on the **OPC-UA protocol detail page > Certificates** tab, and assign it to the device (or leave it on the default certificate). 2. **Download** the Koios client certificate (`.der`) from the certificate's detail drawer. 3. **Import** it into the OPC-UA server's trusted certificates folder. Some servers instead move rejected certificates to a pending folder that you promote to trusted. 4. Trigger a fresh connection — either enable the device or click **Test** on its Configuration tab. Koios connects on the next scan cycle once the server trusts the certificate. > [!WARNING] Regenerating breaks existing trust > If you regenerate or replace a certificate, every OPC-UA server that trusted the old one will reject connections until you import the new certificate into its trust list. Plan certificate changes during a maintenance window. The exact trust process varies by server software (Kepware, Prosys, Unified Automation, Siemens, and others). See [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md) for the full certificate management, generation, upload, and trust workflow. ## Testing a Connection Koios can verify a connection without enabling the device or committing configuration changes. Both devices and tags have a **Test** button on their **Configuration** tab — but they behave differently, and the difference matters. > [!CAUTION] Device Test uses UNSAVED form values; Tag Test uses SAVED config > A **device** test connects using whatever values are currently in the form, even if you haven't saved — so you can try different hostnames, ports, or credentials before committing. A **tag** test uses the tag's **saved** configuration — so you must save any protocol setting change before testing it. Testing a tag right after editing its node ID, without saving, tests the old value. ### Testing a device connection Use this to prove the link is reachable before you enable the device. 1. Open the device's **Configuration** tab. 2. Fill in or edit the connection parameters (hostname, port, credentials, security mode). 3. Click **Test**. Koios attempts a one-time connection using the **current form values**. The button reports the result: | State | Meaning | |-------|---------| | **Test** | Idle, ready to test | | **Testing…** | Connection attempt in progress | | **Success** (green check) | Koios connected successfully | | **Failed** (red X) | Connection failed; an error message appears below the form | The test never modifies the saved configuration. Use it during initial setup, after changing connection parameters, and whenever you need to confirm the device is reachable on the network. ### Testing a tag read Use this to confirm Koios can actually read a value from a data point. 1. Open the tag's **Configuration** tab. 2. **Save** the protocol settings (node ID, register address, expression) — the test reads the saved values, not the form. 3. Click **Test**. Koios performs a one-time read for this tag. | State | Meaning | |-------|---------| | **Test** | Idle, ready to test | | **Testing…** | Read attempt in progress | | **Success** (green check) | A value was read; the result shows the value returned | | **Failed** (red X) | The read failed; an error message appears below the form | > [!TIP] The device must be reachable, but not enabled > A tag test connects to the device in real time using a one-time connection separate from the scan cycle. The device must be powered on and reachable on the network, but it does **not** need to be enabled in Koios. This lets you isolate whether a problem is the tag's configuration or the device link: if the device test succeeds but the tag test fails, the connection is fine and the tag settings are wrong. ## Still Stuck? If a device or tag stays failed after you've corrected the configuration: 1. Read the **error message** and **error detail** on the detail page — they carry the specific exception. Click the red error strip to copy both to your clipboard for searching logs or a support ticket. 2. Open the device's **Logs** tab and set the log level to **Debug** for maximum detail about the connection attempt and per-tag operations. See [Logs](https://ai-ops.com/docs/system/logs.md). 3. Verify reachability independently with **Ping** and **TCP Port Check** in [Network](https://ai-ops.com/docs/system/network.md) — this separates a Koios config problem from a plant-network problem. 4. Toggle the device (or tag) off and on with the **Enabled** switch to force a clean reconnect. 5. If nothing else is running either, check overall service health in [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md): the three diagnostic fields, the status and quality legend, the stuck-error checklist, and the master code lookup - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md): layer 2 — bad quality, no value, read/write, and per-tag configuration fixes - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md): when nothing is running, start here - [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md): generate, upload, assign, and trust client certificates - [Network](https://ai-ops.com/docs/system/network.md): ping, traceroute, DNS lookup, and TCP port check from the Koios server - [Logs](https://ai-ops.com/docs/system/logs.md): set the Debug log level and stream a device's log in real time - [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md): trigger a manual scan outside the normal cycle - [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md): the symptom router if this wasn't your problem --- Source: https://ai-ops.com/docs/troubleshoot/tag-values Section: Troubleshoot # Bad, Missing, or Frozen Tag Values Use this article when a device is **Running** but one of its tags is wrong: the value is missing, flagged bad quality, non-numeric, or clearly incorrect. Because the connection is up, the problem is almost always specific to that one tag's address, data type, or the value it reads back, not the device or the network. If **every** tag on the device is failing, or the device itself is Failed, start one layer up at [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) instead. > [!NOTE] Read the tag > Every tag records an **error code**, **error message**, and **error detail**, plus a **quality** string and a **status**. Those fields tell you what failed and where. This article assumes you already know how to read them — see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) for the shared explainer, the status/quality legend, the full code lookup, and the auto-clear/stuck checklist. ## First: is the device actually stopped? If a tag is enabled but its parent device is stopped, the tag's overview shows a blue **info banner** (rather than a red error) telling you the device is stopped and the tag won't update until the device is enabled and running. This is **not a tag error**. The tag has nothing to read because its device isn't scanning. Enable and start the parent device, and the tag will begin collecting on the next scan. Only continue with the codes below once the device is Running. ## Symptom → cause → code When the device is Running but the tag reads bad, match the symptom to the tag error code. All of these are tag-level codes in the `100`–`110` band; they clear automatically on the next successful scan. | Symptom | Code | Name | What to do | |------|------|------|------------| | Bad OPC-UA quality (server returned a non-Good status) | 107 | **Bad: Read Quality** | The read succeeded but the source reported poor quality (e.g. `Uncertain` or a `Bad_*` OPC-UA status). The value may be stale or unreliable. Check the field device / OPC-UA server health for that node. | | Node / register / variable not found on the device | 102 | **Bad: Node Not Found** | The addressed node ID, register, or variable doesn't exist on the device. Re-select it with the **Browse** button on the tag's **Configuration** tab — a namespace index or identifier may have changed. | | No value / empty register / null response | 105 | **Bad: No Value** | The protocol returned nothing for this tag. The data point may not exist, the register may be empty, or the device returned null. Verify the address and data type on the Configuration tab. | | Value came back but isn't a number | 103 | **Bad: Not a Number** | The device returned text, a special character, or an unexpected type where a numeric value was expected. Fix the configured data type so it matches what the device actually returns. | | Read fails partway through the scan | 106 | **Bad: Failed To Read** | A read operation for this tag failed (invalid address, permission issue, or the device dropped this point mid-scan). The **error detail** carries the underlying exception. | | Output write to the device failed | 101 | **Bad: Failed To Write** | Koios could not write an output value back. Confirm the address is writable, the credentials allow writes, and the value is within the device's accepted range. | | Address, data type, register, bit position, or node ID is wrong | 104 | **Bad: Configuration Error** | The tag's protocol-specific settings are invalid or incomplete (e.g. a Modbus tag with no register or bad bit position, a malformed OPC-UA node ID, an invalid BOSS variable code). Review and correct the **Configuration** tab. This usually surfaces at device initialization. | | General bad-quality condition, no better fit | 100 | **Bad: General** | A catch-all bad-quality state. Read the error detail for specifics. | | Unexpected failure processing the tag | 2 | **Generic Exception** | An unhandled exception occurred while processing the tag. The error detail contains the specific exception. | > [!TIP] Wrong value, not a bad-quality flag? > If the tag reads a *good* value that is simply wrong — off by a factor, inverted, or in the wrong units — the collection is fine and the problem is in a transform. That's a value-mapping or expression issue, not a read error. See [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md). Codes `108` (Mapping Error) and `110` (Bad: Expression) also route there. ## Isolate it with a Test read You can attempt a single read for one tag without enabling it. On the tag's **Configuration** tab, each protocol section has a **Test** button. 1. Open the tag's **Configuration** tab and **save** any changes (Test uses the tag's *saved* configuration, unlike the device connection test which uses the live form values). 2. Click **Test**. Koios performs a one-time read from the device for this tag. | State | Meaning | |-------|---------| | **Test** | Idle, ready to test | | **Testing...** | Read attempt in progress | | **Success** | A value was read; the result message shows the value returned | | **Failed** | The read failed; an error message appears below the form | The device must be powered on and reachable, but it does not need to be enabled in Koios — the test uses a one-time connection separate from the scan cycle. A **Success** here with a **Failed** state during scanning points at scan timing or an intermittent device, not the tag config. ## The device-side view of a bad tag A single misconfigured tag can also raise an error on the **device**, because the device is what performs the read and write: | Code | Name | What it means for the tag | |------|------|---------------------------| | 5 | **Failed To Read from Device** | The connection is up but a tag read failed — often a tag pointing at an invalid address or node. Check which tag is failing and correct its address. | | 6 | **Failed To Write to Device** | An output write failed. Verify the output tag's address is writable and the credentials permit writes. | | 16 | **Failed To Validate Tags** | One or more tags have invalid or missing protocol settings (e.g. a Modbus tag with no register), caught before scanning. Fix the flagged tag's Configuration tab. | If instead the tag shows code `1` **Parent Device Failed**, the device itself is down and the tag can't be collected until it recovers — troubleshoot the device at [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). Code `109` **No Active Device** (redundancy: no device in the set is active) also belongs there. > [!WARNING] Overscanning starves reads > If the device is Running with a **Warning** strip and tags update sluggishly or intermittently, the scan group may be **overscanning** — execution is taking longer than the configured scan rate, so reads fall behind. That's a scan-group timing problem (scan-group error `1`, Overscan), not a per-tag fault. See [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). ## Live value updates but history is flat or gappy If a tag's live value is moving but Trends show flat lines or far fewer points than expected, the read is fine and the issue is historization, usually a mismatch between the tag's **Range Min / Max** and the compression settings. See [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) and [Tag Range and Compression](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression). A code `200` **Failed To Historize** on the tag means the live value is available but that period will have a gap in historical storage. ## If a tag stays stuck Tag errors clear on the next successful read or write — you don't acknowledge them manually. If a tag won't recover once the device is Running: 1. Read the **error message** and **error detail** for the specific cause. 2. Set the device's log level to **Debug** and review its [logs](https://ai-ops.com/docs/system/logs.md) for tag-level detail. 3. Verify the tag's **protocol settings** on the Configuration tab (address, data type, register, bit position, node ID). 4. Use **Test** to attempt a single read and see if the error reproduces. 5. Toggle the tag off and on with the **Enabled** switch. For the shared stuck-tag checklist and how auto-clear works across all entities, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) — the shared diagnostic-fields reference, status/quality legend, and master code lookup - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) — when the device is Failed or every tag reads Parent Device Failed - [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md) — when the value reads good but is transformed wrong (codes 108, 110) - [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) — when live values update but history or Trends don't - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) — overscanning scan groups and service health - [Tag Value Mapping](https://ai-ops.com/docs/tags/value-mapping.md) and [Tag Expressions](https://ai-ops.com/docs/tags/expressions.md) — the transforms that own the mechanics - [System Logs](https://ai-ops.com/docs/system/logs.md) — set Debug level and stream device logs - [Tag Range and Compression](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression) — how the tag range drives historization --- Source: https://ai-ops.com/docs/troubleshoot/expressions-and-mapping Section: Troubleshoot # Expression & Value-Mapping Errors This is the **transformation layer** of tag troubleshooting. The device connection is up and a raw value is arriving, but the step that turns that raw value into the tag's final value is failing. Two error codes live here: | Code | Label | What's failing | |------|-------|----------------| | **110** | Bad: Expression | The tag's calculated expression failed to evaluate | | **108** | Mapping Error | Value mapping could not turn the raw value into an output | There is also an unflagged problem that surfaces only as a warning icon on the tag overview: **multiple sources writing to the same output tag**. It's covered at the end of this page. Before you dig in, confirm the layers below this one are healthy. If the tag also shows a bad-quality read code (100-107) or its parent device has failed (code 1), fix that first. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) and [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). For the shared model of the three diagnostic fields (error code, error message, error detail), the status and quality legend, and the auto-clear behavior, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). > [!NOTE] Where to read the error > On the tag's **Overview** tab the red error strip shows the message and detail — click it to copy both. All three fields are also in the **Parameters** tab under **Live Data**. For expression tags, the **Expression** card on the Overview tab shows the formula and its most recent computed result, if any. ## Expression Error (code 110) A tag with **Source: Expression** computes its value from a formula run by the Expression Evaluator. When that formula can't produce a number, the tag goes to a **Failed** state with error code **110**. The error detail usually names the offending part of the expression. Work through the causes below in order. ### 1. Syntax errors and typos A malformed formula never evaluates. Common shapes: unbalanced parentheses, a stray operator, a misspelled function name (`avg(...)` instead of `mean(...)`), or a reference typed by hand that doesn't match a real tag name. Open the tag's **Configuration** tab and re-check the expression. Rebuild any reference using the `@` autocomplete menu rather than typing it — this guarantees the name and field are spelled correctly and registers a tracked dependency so the expression re-evaluates when that source changes. > [!TIP] Always insert references with @ > Type `@` in the expression editor to search tags, devices, models, and bindings, then pick the field. A hand-typed reference that is one character off will read as a missing tag and fail with code 110. See [Expression Tags](https://ai-ops.com/docs/tags/expressions.md) for the full reference and function catalog. ### 2. Division by zero `a / b` fails the instant `b` evaluates to `0`. This is intermittent by nature — the expression works until a referenced tag momentarily reads zero. Guard the denominator with a conditional: ```text @[Flow:value] / @[Area:value] if @[Area:value] != 0 else 0 ``` The same applies to `log(x)` at or below zero and to `pow()` with an invalid base/exponent pair. ### 3. Missing or failed referenced tags If the expression references a tag, device, model, or binding that has been deleted, disabled, or renamed, the reference can no longer resolve. A referenced source that is itself in a **Failed** state can also propagate a bad value into the calculation. - Confirm every referenced entity still exists and is enabled. - Reference the source's **status** or **error_code** field to build fallback logic instead of failing outright. For example, switch to a backup when the primary isn't running: ```text @[Primary:value] if @[Primary:status] == 1 else @[Backup:value] ``` ### 4. Circular dependencies Expression A references expression B, and B references A (directly or through a chain). Neither can produce a value, so both fail with code 110. Trace the `@` references on each tag in the loop and break the cycle — usually by pointing one expression at the underlying source tag rather than at another expression. ### 5. Disallowed fields Only specific fields are exposed on each reference type: tags expose `value`, `status`, and `error_code`; devices, models, and bindings expose `status` and `error_code` (bindings also expose `value`). Referencing a field that a given type doesn't provide fails to evaluate. Use the `@` menu — it only lists the fields that are valid for the entity you picked. The full field list per reference type is in [Expression Tags](https://ai-ops.com/docs/tags/expressions.md). ### Isolating an expression failure 1. Read the **error detail** on the Overview error strip — it typically points at the specific token or operation that failed. 2. Simplify the formula down to a single reference (`@[Source:value]`), save, and confirm it computes. Add complexity back one piece at a time. 3. Set the Expression Evaluator service to **Debug** log level to see each evaluation. See [Logs](https://ai-ops.com/docs/system/logs.md). Once the formula is corrected, the next successful evaluation clears the error automatically — no manual acknowledgement is needed. ## Value-Mapping Error (code 108) Value mapping runs an ordered list of match rules against each raw value the tag receives; the first matching rule sets the output. Error code **108** means the mapping step failed for this tag. The overwhelmingly common cause is a value that **matched no rule**. Value mapping rules are evaluated top-to-bottom. If the incoming value doesn't satisfy any rule — an unexpected status string, a number outside every configured band — the tag enters an error state. ### The fix: add a catch-all "Any" rule Add a rule with match type **Any (Catch-all)** as the **last** rule in the list. "Any" always matches, so it guarantees every value produces an output instead of erroring. Give it a sentinel output (for example `-1`) so unexpected values are visibly distinct from real ones. | # | Match Type | Pattern | Output | |---|------------|---------|--------| | 1 | Exact | Off | 0 | | 2 | Exact | On | 1 | | 3 | Any | — | -1 | With rule 3 in place, a value like `"Standby"` that matches neither `Off` nor `On` falls through to the catch-all and maps to `-1` rather than failing. > [!WARNING] No catch-all means unmatched values fail > If value mapping is enabled but no rule matches the incoming value, the tag goes to error code 108. Always end the rule list with an **Any** rule unless you deliberately want unmatched values to error. Other things to check when code 108 persists even with a catch-all: - **Numeric rules against non-numeric input.** Greater Than, Less Than, Between, etc. are skipped when the raw value can't be parsed as a number, so a purely numeric rule set with no Exact or Any fallback will miss text values. - **Case sensitivity.** If the device sends `"OFF"` but your Exact rule is `Off`, enable **Case-Insensitive Matching** or add the exact variant. - **Reverse mapping on output tags.** Reverse mapping (numeric output back to a string on write) only works with **Exact Match** rules. If the value being written has no matching Exact rule, the write side has nothing to convert. For rule types, ordering, the lookup key, and reverse mapping mechanics, see [Value Mapping](https://ai-ops.com/docs/tags/value-mapping.md). > [!TIP] Use the lookup key to see what arrived > When mapping is active, the tag's live data shows both the numeric **Value** and the **Lookup Key** (the original raw value, in brackets). If the tag is erroring, the lookup key tells you exactly which raw value none of your rules caught. ## "Multiple sources are writing to this tag" This is a conflict, not an error code — the tag keeps running, but its output may behave unpredictably. It applies only to **output** tags. An output tag is meant to have a single writer. Koios can write to an output tag from three kinds of source: | Source | Meaning | |--------|---------| | **AI Model** | A model binding writes its prediction to the tag | | **Mapping** | A value mapping produces the tag's output | | **Component** | A component (connector) writes the tag | When more than one of these targets the same output tag, the **Output Source** metric card on the tag's Overview tab turns red with a warning triangle and a tooltip warning that multiple sources are writing to the tag. The last writer in a given cycle wins, so the value you see can flip depending on timing. ### How to resolve it 1. On the output tag's **Overview** tab, read the **Output Source** card — it lists every source currently writing the tag. 2. Decide which single source should own the output. 3. Remove the others: delete or repoint the extra model binding, remove the value mapping, or reconfigure the component so it no longer targets this tag. 4. Confirm the Output Source card shows exactly one source and the warning triangle is gone. > [!NOTE] One writer per output tag > A healthy output tag reports a single Output Source. If you intend a model to drive the tag, it should not also carry a value mapping — and vice versa. ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) — the shared three-field diagnostic model, status/quality legend, and stuck-error checklist - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) — fix bad-quality reads before the transformation layer - [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md) — when the AI Model source of an output tag is failing upstream - [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md) — the full symptom router - [Expression Tags](https://ai-ops.com/docs/tags/expressions.md) — authoring reference: operators, functions, and the `@` reference syntax - [Value Mapping](https://ai-ops.com/docs/tags/value-mapping.md) — match-rule types, ordering, lookup key, and reverse mapping - [Logs](https://ai-ops.com/docs/system/logs.md) — set the Expression Evaluator to Debug and stream its output --- Source: https://ai-ops.com/docs/troubleshoot/models Section: Troubleshoot # A Model or Binding Isn't Running A model that won't run almost always fails because of something feeding it, not the model itself. The fastest path to the root cause is to work **down** the chain: model, then bindings, then the tags each binding reads, then the devices those tags live on. This page follows that order. Koios records three diagnostic fields (error code, error message, error detail) at both the **model level** and the **binding level**. For how those fields behave, how errors auto-clear, and the full status and quality legend, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). This page focuses on what the model and binding error codes mean and how to act on them. ## Start with the Bindings Tab When a model fails, the model-level error is often generic — it tells you the model couldn't run but not which input caused it. The binding-level errors tell you the actual cause: a disabled tag, a missing range, stale history, an on-demand read timeout. Where each error appears: - **Model detail, Overview tab** — the status hero shows the current state. When the model is **Failed**, a red strip below the status shows the model error message and detail. - **Model list** — each model shows a colored status icon. Hover the red icon to read the error message. - **Bindings tab** — every input and output binding is a card with a colored left border. A failed binding turns red and expands to show its error message and detail inline. This is the diagnostic view that points at the specific binding that broke the model. > [!TIP] Bindings first, always > The model-level error tells you a binding failed. The binding-level error tells you which one and why. Open the Bindings tab before anything else. ## How the Inference Pipeline Runs Reading the pipeline order helps you read error codes: the code tells you which stage failed. Each inference cycle runs these steps, stopping at the first failure: 1. **Validate bindings** — each input tag is assigned, enabled, and running 2. **Query history** — fetch historical data from the time-series database 3. **Preprocess** — interpolate, check ranges, normalize, assemble the input tensor 4. **Run inference** — execute the ONNX or TFLite model 5. **Write results** — de-normalize predictions, check output ranges, write to output tags For the exact tensor shapes, input depth, and normalization rules the preprocess and inference steps depend on, see [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md). ## Model Error Codes These apply to the model as a whole. When you see one, check the bindings for the more specific cause. An error code of **0 (None)** means no active error. ### File errors | Code | Meaning | What to do | |------|---------|-----------| | 1 | **No File Given** — no model file uploaded | Upload an ONNX or TFLite file on the **Files** tab. | | 2 | **No File Found** — the referenced file is missing from storage | Re-upload the file on the Files tab. | | 3 | **Failed to Parse File** — corrupt, not a valid ONNX/TFLite, or an ONNX IR version above 13 | Verify the file opens in your training environment; if it was exported at a newer IR version, re-export at IR 13 or lower (or annotate it with the model-utils library, which clamps the IR version) and re-upload. | ### Load / binding errors | Code | Meaning | What to do | |------|---------|-----------| | 4 | **Failed to Get Model Depth** — the file's metadata is missing the input depth | Re-upload the model file so the input depth is set correctly. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md). | | 5 | **Failed to Get Bindings** — binding config could not be loaded from the configuration database | Rare; usually a database connectivity issue. Check the model logs. | | 6 | **Bindings Invalid State** — bindings exist but are inconsistent (e.g. an input with no tag assigned, or an output index that doesn't match the file) | Review the bindings on the Bindings tab. | ### Inference errors | Code | Meaning | What to do | |------|---------|-----------| | 7 | **Failed to Structure History** — history could not be organized into the shape the model expects | Usually a data-type issue or an unexpected gap in history. Check the input tags. | | 8 | **Failed to Get Predictions** — the model ran but produced no output | Often the file is incompatible with the input tensor shape. Check that the number of bindings matches the model's expected inputs. | | 9 | **Binding Prediction Index Missing** — an output binding's **Output Index** doesn't match any output position | Reconcile output indices against the model architecture. | | 10 | **Failed to Scale Predictions** — de-normalizing predictions failed | Check that output bindings have valid normalization ranges. | | 11 | **Failed to Write Predictions** — results could not be written to the live data cache | Rare; usually a cache connectivity issue. | ### System errors | Code | Meaning | What to do | |------|---------|-----------| | 12 | **Thread Error** — the execution thread hit an internal error | Usually resolves on the next scan cycle. If it persists, check the predict engine service logs. | | 13 | **Generic Exception** — an unclassified error; the detail carries the exception | Check the model logs for the full stack trace. | | 999 | **Unlicensed** — the license does not cover this model | See [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md). | ## Binding Error Codes These apply to individual input or output bindings and are the most actionable diagnostics. A binding can fail at any pipeline stage; the groups below follow the chain from tag state outward. Code **0 (None)** means the binding is healthy. ### Tag-state errors — fix at the tag or device, not the model | Code | Meaning | What to do | |------|---------|-----------| | 11 | **Binding Tag Disabled** — the bound tag is stopped | Enable the tag or its parent device. | | 12 | **Binding Tag Bad Quality** — the tag read, but the source reported poor quality | The value may be stale or unreliable. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). | | 13 | **Binding Tag Failed** — the bound tag is in a failed state | Fix the tag's own error. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). | | 14 | **Binding Tag Not Assigned** — no tag selected for this binding | Assign a tag on the Bindings tab. | | 17 | **Upstream Model Failure** — this input is written by another model whose output is currently failing | Fix the upstream model first. This binding recovers automatically. | ### On-demand read timeout | Code | Meaning | What to do | |------|---------|-----------| | 20 | **On-Demand Read Failed** — the device did not respond to the on-demand read within the timeout | Confirm the device is online and reachable, then raise the **On-Demand Timeout** on the model or scan group. The read timeout is frequently caused by batch-window latency (see below). | > [!WARNING] Batch window adds latency before the device is even read > On a device configured for on-demand scanning, the batch window can delay a read by up to its full duration before the device is polled. The model's on-demand timeout must cover **batch window + device read time**, or you'll see On-Demand Read Failed even on a healthy device. See [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md) for the batch-window mechanics and [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md) for the model-side timeout. ### Historical-depth and staleness errors — the tag works, the history doesn't | Code | Meaning | What to do | |------|---------|-----------| | 1 | **Not Enough Historical Depth** — not enough samples to fill the model's input window | Common right after a model is enabled. Wait for enough scan cycles to accumulate the required depth; the detail shows how much more is needed. | | 2 | **Stale History Data** — the most recent point is too old to use | The tag's device has stopped collecting or data is arriving late. The detail shows how far outside the allowed window the data is. | > [!NOTE] New models need to warm up > When you first enable a model, its input bindings show **Not Enough Historical Depth** until the device has collected enough scan cycles to fill the sample window (depth × sample rate). This is normal — the model starts running on its own once enough data accumulates. The window size comes from the model file; see [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md). If a binding shows **Stale History Data** but the tag itself looks live, the gap is in historization, not collection. See [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md). ### Range, normalization, and calibration errors | Code | Meaning | What to do | |------|---------|-----------| | 3 | **No Range Given** — a normalization range is required but not configured | Set **Range Min** and **Range Max** on the tag, or enable **Custom Range** on the binding. For Z-Score, set **Custom Mean** and **Custom Std Dev**. | | 4 | **Invalid Range Given** — the range is invalid (min ≥ max, or Z-Score std dev is zero) | Correct the range values on the tag or binding. | | 5 | **Value Out of Range** — an input or output value exceeded the configured failure bounds | The detail shows the value and the bound it crossed. Review the failure range, or widen it if the value is expected. | | 6 | **Failed to Normalize** — the normalization calculation errored (e.g. divide-by-zero from an invalid range) | Check the normalization type and range values. | | 21 | **Invalid Calibration** — the calibration gain is zero or produced an invalid value | A zero gain divides by zero on write-back. Set a non-zero gain on the Bindings tab. | ### Rate-of-change error | Code | Meaning | What to do | |------|---------|-----------| | 19 | **Rate of Change Exceeded** — the value changed faster than the configured threshold | A safety check. The detail shows the actual rate, threshold, and direction. If the rate is expected, raise the ROC threshold on the binding's Configuration tab. | ### Data-structuring errors | Code | Meaning | What to do | |------|---------|-----------| | 7 | **Failed to Structure History** — the binding's history could not be interpolated or organized | Often inconsistent timestamps or unexpected values in the history. | | 16 | **Failed to Structure Input Data** — the preprocessed data could not be assembled into a valid input tensor | Usually a mismatch between the data shape and what the model expects. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md). | ### Output and write errors — after inference | Code | Meaning | What to do | |------|---------|-----------| | 8 | **Prediction Index Missing** — the model output has no value at this binding's **Output Index** | Verify the output index matches the model architecture. | | 9 | **Failed to Scale Prediction** — the predicted value could not be de-normalized to the tag's scale | Check the output binding's normalization range. | | 10 | **Failed to Write Prediction** — the output could not be written to the live data cache | Rare; usually a cache connectivity issue. | | 18 | **General Model Failure** — the model produced no prediction, so this output has no value | The root cause is in the input bindings or the model-level error. Check those first. | ### Other | Code | Meaning | What to do | |------|---------|-----------| | 15 | **Binding Not in Dictionary** — internal lookup miss; should not occur in normal operation | Check the model logs; report it if it persists. | | 999 | **Unlicensed** — the license does not cover this binding | See [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md). | ## Common Scenarios ### All inputs show "Tag Disabled" Every input binding is code 11. The model depends on tags that have been stopped, individually or because their parent device was disabled. Re-enable the tags or the device. ### All inputs show "Not Enough Historical Depth" Normal right after enabling a model or restarting a device. Wait for the device to complete enough scan cycles to fill the window (depth × sample rate). No action needed. ### One input shows "Upstream Model Failure" That binding reads a tag written by another model's output, and the upstream model is failing. Fix the upstream model; this binding recovers on its own. ### Running, but an output shows "Value Out of Range" Inference produced a prediction that exceeded the output's failure bounds. Likely causes: - Input data has drifted outside the range the model was trained on - Failure bounds are set too tightly for the expected output - The normalization range doesn't match the training data's range Review the output binding's failure range on its Configuration tab. ### "On-Demand Read Failed" The model or its scan group is on-demand, but the device didn't answer in time. Confirm the device is powered and reachable (see [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md)), then confirm the **On-Demand Timeout** covers the batch window plus device read time. See [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md). ### "Input tensor shape mismatch" The number of input bindings doesn't match what the model file expects, usually after uploading a file with a different architecture. Reconcile the bindings on the Bindings tab to match the new input/output structure. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md). ### A scan group fails and every model in it shows "On-Demand Read Failed" When a scan group's shared on-demand read fails, all models in the group fail together. The group-level error (**On-Demand Read Failed**, scan-group code 2) appears on the scan group's detail page. Fix the shared device connection; every model in the group recovers on the next cycle. For scan-group health more broadly, see [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). ## If a Model Stays Stuck Errors clear automatically once the next inference cycle succeeds — no manual acknowledgment. If a model won't recover: 1. Read the **Bindings** tab for per-binding errors; they are more actionable than the model-level error. 2. Set the model's log level to **Debug** on the [Logs](https://ai-ops.com/docs/system/logs.md) tab and watch each pipeline stage. 3. Confirm every input tag is **enabled and running** — one disabled or failed tag blocks the whole model. 4. Check the tag devices — a down device fails all its tags, which cascades to every model using them. 5. Toggle the model off and on with the **Enabled** switch. If none of that clears it, gather logs before opening a ticket. See [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md). ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) — the shared error-field reference, status/quality legend, and stuck-error checklist - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md) — input/output tensor shapes, input depth, normalization - [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md) — model-side on-demand cycle and timeout - [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md) — device-side freshness and batch-window latency - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md) — when a binding's tag is the problem - [Data Is Stale, Frozen, or Has Gaps](https://ai-ops.com/docs/troubleshoot/stale-data.md) — when history is stale but the tag is live - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md) — when the device feeding a tag is unreachable - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md) — scan-group and predict-engine health - [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md) — the Unlicensed (999) code - [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md) — what to gather before a ticket --- Source: https://ai-ops.com/docs/troubleshoot/stale-data Section: Troubleshoot # Data Is Stale, Frozen, or Has Gaps This article covers the family of "my data isn't moving" symptoms: - A tag's **live value looks frozen** and never changes - **Trends** show flat lines, big gaps, or far fewer points than expected - **History isn't recording** for a tag, device, or the whole system - A **model complains** that its input data is old or stale These symptoms fall into two very different buckets, and the fix depends on which one you have: | Symptom | Likely bucket | Where to look | |---------|---------------|---------------| | Live value frozen, or trends completely empty | **Collection stopped** upstream (device/tag not scanning) | [Collection stopped](#collection-has-stopped-nothing-is-being-recorded) | | Live value updates fine, but trends are flat or sparse | **Historization is dropping points** (compression/range) | [Tag is not historizing properly](#tag-is-not-historizing-properly) | > [!TIP] Watch the live value first > The single fastest diagnostic is: does the **live value** on the tag's Overview tab change over time? If it never moves, collection has stopped upstream. If it moves but Trends stay flat, the problem is compression, not collection. ## Collection Has Stopped: Nothing Is Being Recorded If the live value is frozen and Trends are empty, the tag isn't being collected at all. History can only record what collection produces, so fix collection first. Work outward from the tag: 1. **Is the tag failed?** A failed tag isn't producing values. Check its error code and error message. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). 2. **Is the parent device failed or stopped?** If the device is down, every tag on it stops. A tag whose device is stopped shows an info banner telling you the device is stopped and the tag won't update until it is enabled and running. See [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). 3. **Is the value a calculated or mapped value?** An expression or value-mapping failure freezes the output even when the source tags are fine. See [Expression & Value-Mapping Errors](https://ai-ops.com/docs/troubleshoot/expressions-and-mapping.md). The three diagnostic fields (error code, error message, error detail), the status/quality legend, and the auto-clear behavior are all documented once in [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). Start there if you need to interpret a code or status color. ### History-Write Failure Codes A tag can be collected successfully and still fail to *write* to history. In that case the live value is current, but a gap appears in Trends for that period. These are the codes that signal a history-write failure specifically: | Entity | Code | Name | What it means | |--------|------|------|---------------| | Tag | 200 | **Failed To Historize** | The tag's value could not be written to history. The tag is still being scanned and its live value is available, but historical data has a gap for this period. | | Device | 13 | **Failed To Write To Long Term History** | Tag values could not be written to the time-series database. The device is still scanning and live values are available, but historical data will have a gap. | | Device | 12 | **Failed To Write To Model History** | Tag values could not be written to the model (in-memory / AI) history store. The device is still scanning, but model predictions may be affected. | > [!NOTE] These usually self-heal > History-write failures typically clear on the next successful scan and often point at a transient storage or resource condition. If code 200 or device code 13 persists, check disk usage and service health in [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). ### Tag is not historizing properly If a tag's live value is updating but Trends show flat lines or far fewer recorded points than expected, the cause is almost always a mismatch between the tag's **Range Min / Max** and the compression settings — **not** a collection problem. Koios uses **Swinging Door Trending (SDT)** to compress historical data. SDT maintains a tolerance band (a "door") around the last recorded point and discards new values that fall inside the band, because the trend line already represents them. The width of that band is calculated as a **percentage of the tag's configured range**, not of the actual value. The default tag range is **0–100**. If a tag only moves between **0 and 1** but its range is left at 0–100, the tolerance band is wider than the entire signal, so almost nothing passes the filter. The result is silent data loss: the live value updates, but Trends look flat or empty. **How to fix it:** 1. Set the tag's **Range Min** and **Range Max** to match the actual expected value range (for example **0–1**, not 0–100). 2. Review the global **Compression Deviation**. A deviation of **1–2%** is a good starting point for most process data. 3. If only this tag needs special treatment, enable **Override global compression settings** on the tag's Configuration tab and set a tighter deviation, or disable compression for this tag alone. 4. To disable compression globally, turn off the **Compression Enabled** toggle on the Retention page. > [!WARNING] Check the range on every tag > The default range of 0–100 causes silent data loss for tags with narrow value bands (0–1, 4–20 mA, 0.0–5.0). This is the most common cause of missing historical data. The actual settings and a full explanation of how SDT interacts with the tag range live in [Tag Range and Compression](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression). ## Trends Are Flat or Gappy If Trends look wrong but the live value is fine, run through these in order: - **Flat line with almost no points** → compression is discarding everything. See [Tag is not historizing properly](#tag-is-not-historizing-properly). - **A gap for a specific time window** → collection or history-write stopped during that window. Check the tag/device error history and the [history-write failure codes](#history-write-failure-codes) above. - **Older data disappeared entirely** → retention cleanup deleted it. History older than the configured **History Database Retention** period is permanently removed. Review the period in [Data Retention](https://ai-ops.com/docs/system/retention.md). - **Everything stopped at the same moment across many tags** → a device outage or a service/resource problem. See [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). > [!WARNING] Reducing retention deletes data > When you reduce a retention period, existing data older than the new limit is permanently deleted. This is a common cause of "old trends vanished" reports. See [Data Retention](https://ai-ops.com/docs/system/retention.md). ## A Model Complains About Old or Stale Data Models read from history, so historization problems surface as binding errors. Check the model's **Bindings** tab for these two codes: | Code | Name | What it means | What to do | |------|------|---------------|------------| | 1 | **Not Enough Historical Depth** | There isn't enough historical data to fill the model's input window. Common right after a model is first enabled or a device is restarted. | Wait for enough scan cycles to accumulate the required depth. The error detail shows how much more data is needed. | | 2 | **Stale History Data** | The most recent data point is too old — the tag's device has stopped collecting, or the data is arriving with significant delay. | Fix collection on the bound tag's device, then the binding recovers automatically. | > [!NOTE] New models need time to warm up > When you first enable a model, input bindings show **Not Enough Historical Depth** until the device has collected enough scan cycles to fill the sample window (depth × sample rate). This is normal — the model starts running automatically once enough data accumulates. Both codes point back at historization: **Stale History Data** almost always means collection stopped on an upstream device, and **Not Enough Historical Depth** can be aggravated by aggressive compression starving the history. If the depth error won't clear even after waiting, confirm the bound tag is actually recording points — a compression/range mismatch can prevent history from ever filling the window. See [Tag is not historizing properly](#tag-is-not-historizing-properly) and the model [inference requirements](https://ai-ops.com/docs/models/inference-requirements.md) for how depth is calculated. For the full model and binding error catalog, see [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md). ## Still Stuck? If a tag records live values but history stays empty even after correcting the range and compression: 1. Confirm the tag's live value is genuinely changing — SDT correctly stores nothing for a truly constant signal until **Maximum Time Between Samples** forces a sample. 2. Set the device's log level to **Debug** and watch for historization errors during a scan. See [Logs](https://ai-ops.com/docs/system/logs.md). 3. Check disk space and service health — a full disk or a stalled service stops all writes. See [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md). 4. If you're preparing a support ticket, gather the details in [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md). ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md): the shared reference for the three diagnostic fields, the status/quality legend, and the master error-code lookup - [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md): upstream causes when a live value never moves - [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md): device-level outages that stop collection - [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md): stale-history and depth binding errors in full - [Service Health & Resource Alarms](https://ai-ops.com/docs/troubleshoot/services-and-alarms.md): disk, service, and resource problems that stop writes - [Tag Range and Compression](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression): the SDT and compression settings that own historization - [Data Retention](https://ai-ops.com/docs/system/retention.md): compression, retention periods, and storage monitoring - [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md): tensor shape and history depth --- Source: https://ai-ops.com/docs/troubleshoot/services-and-alarms Section: Troubleshoot # Service Health & Resource Alarms This is the platform layer. When a specific device, tag, model, or scan group looks wrong, start with the layer that owns it. But when *many* things fail at once, or the whole server slows down, the cause is usually one layer beneath them all: a background service has stopped, or the host is out of CPU, memory, or disk. This page covers how to read the System Alerts banners, diagnose unhealthy services and their heartbeats, respond to resource alarms, and interpret scan-group execution errors. > [!NOTE] Whole app is blank or won > If nothing renders at all (blank page, login won't submit, GraphQL errors on every request), this is an outage, not a health alarm. Go to [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md). For the shared status colors, the three diagnostic fields, and the auto-clear vs. stuck checklist, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). This page does not repeat those. --- ## Start with the System Alerts banners Koios continuously checks four platform signals and surfaces them as alert banners. Read the banners first — they tell you which layer to investigate and link straight to the tool that owns it. | Banner | Severity | What it means | Where it links | |--------|----------|---------------|----------------| | **Unhealthy Services** | Warning, or Error if *every* service is down | One or more background services are not sending healthy heartbeats | [Services](https://ai-ops.com/docs/system/services.md) | | **Performance Alarm** | Warning | A CPU, Memory, Disk, or Network alarm threshold is currently exceeded | [System Health](https://ai-ops.com/docs/system/performance.md) | | **Failed Devices / Tags / Models / Scan Groups** | Error | One or more entities of that type are in a failed state | The matching list page | | **License** (No License / Invalid / Grace Period) | Warning or Error | Licensed functionality is gated by license state | [License](https://ai-ops.com/docs/system/license.md) | Two of these also pin a persistent bar at the bottom of the app until resolved: the **license grace period** warning and the **unhealthy services** banner, which names the services that aren't running. > [!TIP] Route by the banner, not the symptom > A single failed service can cascade into dozens of failed tags and models. If you see an Unhealthy Services banner *and* failed-entity banners together, fix the service first — the entity failures often clear on their own once the service recovers. The failed-entity and license banners are the entry points to other layers. Follow them to [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md), [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md), or [Licensing Problems](https://ai-ops.com/docs/troubleshoot/licensing.md). The rest of this page covers services and resource alarms. --- ## Unhealthy or stopped services Open **System > Service Status** to see every service. Services are split into two tables: - **Application Services** — Data Collector, Predict Engine, Expression Evaluator, Parameter Mapping, Performance Monitoring, and Component Engine. These do the platform's real work, and they report heartbeats. - **Infrastructure** — Celery Worker, the configuration database, the time-series database, the in-memory cache, the web proxy, and the metrics agent. These support the application services. Each row shows status, CPU, memory, PID, and uptime. ### How heartbeats decide health Application services report a heartbeat on a regular cadence. The status badge combines that heartbeat with the process state: | Status | Color | Meaning | What to do | |--------|-------|---------|------------| | **Running** | Teal | Healthy and reporting normally | Nothing | | **Stopped** | Gray | Not running | Start it from the detail drawer | | **Failed** | Red | Crashed or exited with an error | Read the error, then Start or Restart | | **Starting** | Yellow | In the process of starting | Wait for the transition to finish | | **Stopping** | Yellow | In the process of stopping | Wait for the transition to finish | | **Unresponsive** | Orange | Process is alive but **not sending healthy heartbeats** | Restart it; if it keeps going unresponsive, check the logs and resource alarms | | **Standalone** | Orange | Heartbeats are healthy but the process is **not managed by the service manager** | Usually a dev/manual-launch artifact; restart to bring it back under management | **Unresponsive** is the key heartbeat state: the process didn't crash, so it isn't Failed, but it stopped checking in. A service that pins the host CPU or runs out of memory will often go Unresponsive rather than Failed. Hover any badge for a plain-language explanation. ### Recover a service Click a service row to open its detail drawer. The **Overview** tab shows the description, live metrics (CPU, memory, thread count, PID, uptime), **Last Heartbeat** (when it last reported in), and any reported **Error Info** message and detail. Action buttons appear in the footer based on the current state: | Current state | Available actions | |---------------|-------------------| | Stopped / Failed | Start | | Running / Unresponsive | Restart, Stop | | Starting / Stopping | None — wait for the transition | Start and Restart run immediately; Stop asks for confirmation. The list refreshes automatically afterward. > [!WARNING] Some services have no action buttons > The configuration database, the in-memory cache, and the web proxy cannot be started, stopped, or restarted from the UI — no action buttons appear for them. If one of those is down, the app itself usually can't run: treat it as an outage and see [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md) or [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md). ### When a service keeps going Unresponsive or Failed 1. Open the drawer's **Diagnostics** tab (application services only). It shows the service's live workload: **Pressure** (thread-pool utilization as a rolling average), **In-Flight** (tasks executing now), and **Queued** (tasks waiting). A badge turns yellow at 70% pressure and red at 90%. Sustained high pressure means the service is overloaded, not broken — reduce its workload or scan rate rather than just restarting it. 2. For the Predict Engine, the Diagnostics tab lists **Top Contributors** — the AI models putting the most load on the service. Click a model to open it and check whether one model is starving the rest. 3. Stream the service's log for the actual traceback. See [Logs](https://ai-ops.com/docs/system/logs.md), and set the log level to Debug there if the default output isn't detailed enough. 4. Check whether a resource alarm is active (next section). A service that keeps dying is often a symptom of the host running out of memory or disk. --- ## Resource alarms: CPU, memory, disk, network A **Performance Alarm** banner, or a red dot on a tab in **System > Health**, means a hardware threshold has been crossed. The Health page has four tabs, each with a live chart, an alarm limit, and display options. The alarm state is re-evaluated every 10 seconds; a red dot on the tab means that metric's alarm is currently active. | Alarm | Threshold setting | Fires when | First things to check | |-------|-------------------|------------|-----------------------| | **CPU** | CPU Alarm Limit (%) | Overall CPU usage exceeds the limit | Which service is consuming it — the chart's per-service **Service Processes** breakdown shows the culprit. A hot Predict Engine or Data Collector usually means scan rates are too aggressive for the hardware. | | **Memory** | RAM Alarm Limit (%) | Memory usage exceeds the limit | Per-service memory in the chart legend. Sustained high memory is the most common cause of a service going Unresponsive or Failed. Switch the axis to bytes with **Show in Bytes** for absolute numbers. | | **Disk** | Storage Alarm Limit (%) | Disk usage exceeds the limit | The live display shows free space, daily change rate, and a projected **time-to-full**. If it's filling fast, history is the usual cause — tighten retention and compression. | | **Network** | Network Alarm Limit (MB/s) | Throughput exceeds the limit, or (if **Alarm on Packet Drops** is on) packet drops are detected | The interface selector — confirm you're watching the right interface. Packet drops point at a physical link or driver problem, not Koios. | Each tab's **Show Setpoint** option draws the threshold as a dashed red line so you can see how close you are. Thresholds save automatically the moment you change them — there's no Save button. > [!TIP] Set thresholds to your normal operating range > A CPU alarm at 90% catches sustained overload without false positives from brief spikes. A storage alarm at 85% gives you time to act before the disk fills. Tune every limit to what "normal" looks like on your deployment. ### Disk alarm won't clear Disk pressure rarely resolves itself. The largest consumer is almost always historical storage. Lower retention windows and enable/tune compression (see the retention settings, below), then confirm the projected time-to-full estimate on the Disk tab is trending back up. Backups also accumulate — old pre-migration and manual dumps in the media volume can be pruned. ### A resource alarm caused a service failure If a resource alarm was active at the same time a service went Unresponsive or Failed, treat the alarm as the root cause. Relieve the resource pressure (reduce scan rates, tighten retention, add capacity), then restart the affected service. Restarting without relieving the pressure just repeats the cycle. --- ## Device housekeeping failures (codes 14, 15, 17) A running device can report a platform-side failure that isn't about the connection or a tag read — it's the Data Collector failing to complete background work for that device. These surface as device error codes and usually clear on the next cycle once the underlying service or resource pressure eases. | Code | Meaning | What to do | |------|---------|------------| | **14 — Failed to Update Heartbeat** | The device's availability heartbeat could not be written | Check the Data Collector service and the in-memory cache; typically transient under high load. | | **15 — Failed to Cleanup** | Resource cleanup after a device operation failed | Usually transient; if it persists, restart the Data Collector and check for an active resource alarm. | | **17 — Failed to Write Executions** | Scan/execution records could not be written to the database | Check the configuration database health and free disk space, and relieve any active resource alarm. | These are symptoms of service or host pressure, not a device fault. If one recurs, work the services and resource-alarm sections above — the fix is almost always there. --- ## Scan-group errors: Overscan and On-Demand Read/Write A scan group runs its members on a shared schedule. When the scan group itself is Failed or shows a warning, the error code identifies what went wrong at the group level (distinct from any per-tag or per-binding errors underneath it). | Code | Meaning | What to do | |------|---------|------------| | **0 — None** | Running normally | Nothing | | **1 — Overscan** | Execution exceeded the configured scan rate — the group could not finish one cycle before the next was due | Slow the scan rate, or reduce the number of members. Overscan surfaces as a running-with-warning (amber) state, not a hard failure: the group still works, it just can't keep up. Persistent overscan also drives CPU. | | **2 — On-Demand Read Failed** | The group's shared on-demand read failed | Trace it to the underlying device or tag — this is a device-layer failure surfacing at the group. See [Troubleshoot a Connection](https://ai-ops.com/docs/troubleshoot/connection.md). | | **3 — On-Demand Write Failed** | The group's shared on-demand write failed | Confirm the target tag is writable and the device accepts the write. See [Bad, Missing, or Frozen Tag Values](https://ai-ops.com/docs/troubleshoot/tag-values.md). | | **99 — Generic Exception** | An unexpected exception during scan-group execution | Read the group's error detail and the service logs for the traceback. | > [!WARNING] Overscan is a capacity signal > Overscan means the work assigned to a scan group is more than the host can complete in the allotted time. Increasing the scan rate (running less often) or splitting members across groups is the fix — not restarting. Left unaddressed, a chronically overscanning group keeps CPU high and can starve other services. On-demand read/write behavior is configured per device and per scan group; see [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md) and [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md). The On-Demand Read/Write failures here are the group-level view. When a *model binding* reports an on-demand read failure (binding code 20), diagnose it from the model side in [A Model or Binding Isn't Running](https://ai-ops.com/docs/troubleshoot/models.md). --- ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md): the shared status legend, the three diagnostic fields, and the master error-code lookup - [Services](https://ai-ops.com/docs/system/services.md): the full Service Status page — heartbeats, diagnostics, and start/stop/restart - [System Health](https://ai-ops.com/docs/system/performance.md): the CPU, memory, disk, and network charts and every alarm setting - [Logs](https://ai-ops.com/docs/system/logs.md): stream a service's log and raise its log level to Debug - [Data Retention](https://ai-ops.com/docs/system/retention.md#tag-range-and-compression): tighten history and compression to relieve a disk alarm - [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md): when the whole platform is down, not just one service - [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md): what to gather before opening a ticket --- Source: https://ai-ops.com/docs/troubleshoot/licensing Section: Troubleshoot # Licensing Problems The license is the platform gate. When it is missing, invalid, or expired, licensed functionality is restricted and every device, tag, model, and binding falls back to an **Unlicensed** state. This page explains each license condition, the grace-period countdown, why entities report code `999`, and what to do when upload or activation fails. The current license state lives at **System > License**. Koios also raises a system alert (and, during a grace period, a persistent footer banner) the moment a license problem appears. --- ## License States at a Glance The **System > License** page shows a status banner reflecting the current condition: | Status | Meaning | |--------|---------| | **Active** | License is valid and licensed features are available | | **Grace Period** | License has expired, but the platform keeps running for up to 30 days | | **No License** | No license file has been uploaded — activation is required | | **Invalid** | License is expired, corrupted, or does not match the current hardware | Only the **Active** state runs the platform normally. In the other three, licensed functionality is restricted until you resolve them. --- ## No License Found If no license file has been uploaded, Koios raises the **No License Found** alert and runs in a limited state: you can log in and configure devices, tags, and models, but licensed functionality stays unavailable until a valid license is present. This is the expected state on a fresh install before activation, and after a skip during the first-login onboarding flow. **To fix it**, activate a license: 1. Go to **System > License**. 2. Follow the activation wizard (enter your license key, submit the request file to the portal, upload the returned `koios.lic`). 3. On success, the banner returns to **Active** and the platform resumes normal operation. The full walkthrough lives in [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md). The **System > License** page runs the same wizard shown on first login — see [License](https://ai-ops.com/docs/system/license.md). > [!NOTE] Need a license key? > Contact your Ai-OPs representative to obtain a license key for your deployment. The key is what you paste in the first step of the activation wizard. --- ## License Invalid or Expired When a license is present but not valid, Koios raises the **License Invalid** alert (an error-severity condition) and shows the license's own error text where available. A license is invalid when it is expired past its grace period, corrupted, or bound to different hardware than the current machine. Because the Koios license is tied to the hardware it was activated on, moving the container to a new server or VM invalidates the existing license file. **To fix it:** 1. Open **System > License** and read the **License Details** card — check the **Expires** date and confirm the **Hardware ID** matches the machine Koios is running on. 2. If the license expired, obtain a renewed `koios.lic` from the portal and re-upload it. 3. If you moved Koios to different hardware, start a re-activation to generate a fresh activation request file for the current hardware, submit it to the portal, and upload the new license. > [!WARNING] Hardware-tied license > The license is bound to the hardware fingerprint it was activated on. Moving Koios to different hardware invalidates the existing license file — you must generate a new activation file and obtain a new license from the portal. See [Re-Activation](https://ai-ops.com/docs/system/license.md). --- ## Grace Period Countdown When a license expires, Koios does not stop immediately. It enters a **30-day grace period** — the platform keeps running for those 30 days so you have time to renew without an outage. During this window the license page banner shows the grace-period state, a **License Grace Period** alert appears, and a persistent footer banner with a **Renew License** link stays visible across the app. The banner counts down the days remaining and prompts you to upload a renewed license before the grace period ends. > [!WARNING] Renew before the countdown ends > When the grace period reaches zero, the license becomes **Invalid** and licensed functionality stops until you renew. Upload your renewed license before then to avoid an interruption — click **Renew License** on the footer banner, or go to **System > License**. --- ## Why Entities Show "Unlicensed" (Code 999) When there is no valid license, individual entities do not simply go idle — they report a dedicated **Unlicensed** error code, `999`. This is the per-entity signal that the platform gate, not the entity's own configuration, is the problem. The code appears identically across devices, tags, models, and bindings: | Entity | Code | Label | Meaning | |--------|------|-------|---------| | Device | `999` | Unlicensed | The device is not covered by a valid license. | | Tag | `999` | Unlicensed | The tag is not covered by a valid license. | | Model | `999` | Unlicensed | The model is not covered by a valid license. | | Binding | `999` | Unlicensed | The binding is not covered by a valid license. | While an entity is Unlicensed, it does not operate — devices stop connecting and polling, tags stop updating, models stop running inference, and bindings stop feeding their models. The exact scope of what a license covers depends on your deployment. > [!TIP] One fix clears all of them > Code `999` is never an entity-level misconfiguration. Do not troubleshoot the individual device, tag, or model — restore a valid license (activate, renew, or re-activate on the correct hardware) and every `999` clears once the platform resumes. Scan groups have no `999` code; they use a generic exception (`99`) instead, so a scan group is not the place to look for a license problem. For the master error-code lookup and how the three diagnostic fields, status, and quality legend work, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). --- ## Upload or Activation Failures If activation fails at the final step (uploading `koios.lic`), work through the wizard in order — most failures come from a mismatch between the request file, the portal, and the machine: 1. **Wrong or stale request file.** The `.req` file you submit to the portal carries this machine's hardware fingerprint. If you generated it on a different machine, or re-used an old one after moving Koios, the returned license will not validate here. Generate a fresh request file from **System > License** on the machine that will run Koios. 2. **Hardware ID mismatch.** Open the **License Details** card and confirm the **Hardware ID** on the (rejected) license matches the machine. If it differs, you activated against the wrong hardware — re-activate from the current machine. 3. **Corrupted or truncated file.** Re-download `koios.lic` from the portal and upload it again without editing or renaming its contents. 4. **Expired license.** A license that is already past its date will upload but immediately report **Invalid**. Confirm the **Expires** date and request a renewed file if needed. The **License ID**, **Request ID**, and **Hardware ID** fields on the license page are copyable — copy the **Request ID** and **Hardware ID** when contacting support so they can match your activation against the portal record. See [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md). > [!CAUTION] Keep your license across upgrades and restores > The license lives on its own volume and is included in backup and restore. When you back up, restore, or move a deployment, keep the license volume with the others so activation survives — otherwise the platform comes back up in the **No License Found** state. See [Backup & Restore](https://ai-ops.com/docs/system/backup.md). --- ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md): the shared reference for the three diagnostic fields, the status and quality legend, and the master error-code lookup (including `999`) - [License](https://ai-ops.com/docs/system/license.md): view license status and details, and run the re-activation wizard - [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md): the detailed step-by-step activation walkthrough - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): keep the license volume with your backups - [Collecting Diagnostics for Support](https://ai-ops.com/docs/troubleshoot/collecting-diagnostics.md): what to gather before opening a support ticket - [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md): the symptom router for every other class of problem --- Source: https://ai-ops.com/docs/troubleshoot/server-startup Section: Troubleshoot # Server Won't Start If the sign-in screen shows **"Starting up..."** and never advances to the login form, the web interface has loaded but the server behind it has not finished starting — or it failed to start. The page keeps checking in the background and recovers on its own the moment the server is ready, so a slow first start or a large database update can simply take a few minutes. If it stays on this screen longer than that, use the steps below to find out why. > [!NOTE] What this screen means > The interface you see is served independently of the application server. Reaching "Starting up..." confirms the machine is reachable and the web layer is running — the part still coming up is the application server that handles logins and data. --- ## Check the container status Open a terminal on the machine running Koios (or connect to it over SSH), then check whether the container is running or restart-looping: ```bash docker ps ``` Find the `koios` container. A healthy server shows a status like `Up 2 minutes (healthy)`. A status that keeps resetting to `Restarting`, or shows `(unhealthy)`, means startup is failing repeatedly. If Koios runs as a service, check it directly: ```bash sudo systemctl status docker.koios ``` --- ## Read the startup logs The container's log stream shows the startup sequence — applying database updates, seeding, then starting services. This is where a failed start reports why. ```bash docker logs --tail 200 koios ``` To watch it live while it retries: ```bash docker logs -f koios ``` To read a specific service's log file inside the container: ```bash docker exec koios tail -n 200 /var/www/koios/logs/services/django.log ``` > [!TIP] What to look for > Scroll to the end of the output and read upward to the first error or traceback. The last error before the container exits or restarts is almost always the real cause. --- ## Common causes ### A database update failed On startup Koios applies any pending updates to the configuration database before it begins serving. If one fails, the server stops before the login screen is available and the container restarts, retrying the same failing step. The log shows the update step that failed followed by an error. Capture the full error and contact support. Do not delete data or force the container past this step — that can leave the database in an inconsistent state. ### Schema version incompatible If you recently changed the Koios version, the startup log may show: ```text FATAL: Schema version incompatible ``` This happens when a **newer** version of Koios previously upgraded the database, and an **older** version is now trying to run against it. The older version cannot safely read the upgraded database, so it refuses to start. > [!CAUTION] Downgrades are not supported > Once a version has upgraded the database, you cannot run an older version against it. To recover, run the newer version again, or restore a backup taken **before** the upgrade. See [Backup & Restore](https://ai-ops.com/docs/system/backup.md) and [Upgrading Koios](https://ai-ops.com/docs/updates/general.md). ### The machine is out of resources A full disk or exhausted memory can stall startup. Check available space: ```bash df -h ``` If the volume holding Koios data is full, free up space or expand the disk, then restart. --- ## Restart the server After addressing the cause, restart Koios: ```bash sudo systemctl restart docker.koios ``` If Koios was started manually rather than as a service, see [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md). Watch the logs as it comes back up: ```bash docker logs -f koios ``` The **"Starting up..."** screen advances to the login form automatically once the server is ready — there's no need to reload. --- ## Still stuck? If the server keeps failing after a restart, capture the startup logs and contact support: ```bash docker logs --tail 500 koios > koios-startup.log ``` Attach `koios-startup.log` so the cause can be diagnosed quickly. ## What's Next - [Logs](https://ai-ops.com/docs/system/logs.md): stream service logs and browse archived log files once the server is running - [Services](https://ai-ops.com/docs/system/services.md): view and control individual service status - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): restore from a backup if a startup issue can't be resolved --- Source: https://ai-ops.com/docs/troubleshoot/collecting-diagnostics Section: Troubleshoot # Collecting Diagnostics for Support When you open a support case, the fastest resolutions come from tickets that already include the version, the logs, and the exact error. This page is the checklist to run through before you reach out. Other troubleshooting pages link here instead of re-describing how to set Debug or dump logs. > [!TIP] Gather everything in one pass > Work top to bottom and collect each item into a single folder or message. A ticket with all five items attached skips a full round-trip of back-and-forth questions. --- ## 1. Koios version Support needs to know exactly which build you are running. Find the version in the interface under **System**, or read it from the container: ```bash docker exec koios cat /var/www/koios/VERSION ``` If you recently upgraded, note the version you upgraded **from** as well — many issues trace back to the upgrade step. --- ## 2. Container status Confirm whether the `koios` container is healthy or restart-looping. On the machine running Koios (or over SSH): ```bash docker ps ``` Find the `koios` container. A healthy server shows a status like `Up 2 minutes (healthy)`. A status that keeps resetting to `Restarting`, or shows `(unhealthy)`, means the server is failing to start — capture that too. If Koios runs as a service, check it directly: ```bash sudo systemctl status docker.koios ``` > [!NOTE] If the server won > A container stuck on `Restarting`, or a sign-in screen frozen on "Starting up...", is an outage, not a per-entity fault. Follow [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md) — it walks through the startup logs and recovery — then attach what you find here. --- ## 3. Logs Logs are where the failure actually reports itself. There are two useful sources. ### Set Debug and capture the affected service Before reproducing the problem, raise the log level of the relevant service to **Debug** for maximum detail, reproduce the issue, then stream or download the log. This is all done from the interface — see [Logs](https://ai-ops.com/docs/system/logs.md) for selecting a service, setting the level, streaming live output, and downloading archived log files. Return the service to **Info** or **Warning** afterward to reduce noise. > [!TIP] Match the service to the symptom > Set Debug on the service that owns the failing entity: the data collector for device and tag reads, the predict engine for models and bindings, the expression or mapping service for value transforms. Debug reverts on its own after the configured timer, so you won't leave a service verbose by accident. ### Dump the container logs to a file For startup problems or when the interface isn't reachable, write the container's log stream straight to a file you can attach: ```bash docker logs --tail 500 koios > koios-diagnostics.log ``` To read a specific service's log file from inside the container instead: ```bash docker exec koios tail -n 200 /var/www/koios/logs/services/django.log ``` When reading through a dump, scroll to the end and read upward to the first error or traceback — the last error before a restart is almost always the real cause. --- ## 4. The error Code, Message, and Detail Every failing entity surfaces three diagnostic fields — a numeric **Code**, a short **Message**, and a longer **Detail**. Copy all three verbatim from the affected device, tag, model, binding, or scan group. The code alone tells support which layer failed and which service log to read. For what each field means, the full status and quality legend, the auto-clear behavior, and the master code lookup, see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md). A few of the most common codes to have on hand when you write the ticket: | Entity | Code | Meaning | |--------|------|---------| | Device | 1 — Failed To Connect | The device could not reach the industrial endpoint | | Tag | 104 — Bad: Configuration Error | The tag has a bad address, type, or settings | | Tag | 105 — Bad: No Value | No value was returned for the tag | | Binding | 1 — Not Enough Historical Depth | The bound tag lacks enough history for the model's lookback | | Model | 3 — Failed To Parse File | The model file is invalid or corrupt | | Scan group | 1 — Overscan | Execution could not keep up with the configured scan rate | | Any | 999 — Unlicensed | The entity is not covered by a valid license | Include the entity's name and status alongside the three fields so support can locate it. --- ## 5. A recent backup If the issue may require restoring or inspecting configuration and data, take a backup before you make any changes, and note whether one already exists from before the problem started. See [Backup & Restore](https://ai-ops.com/docs/system/backup.md) for how to create and download one. > [!WARNING] Back up before you change anything > Do not delete data, force a container past a failing startup step, or downgrade the version to "try something" before support has looked. A backup taken now preserves the failing state so the cause can still be diagnosed. --- ## Diagnostics checklist | Item | Where to get it | |------|-----------------| | Koios version (and prior version if upgraded) | System page, or `docker exec koios cat /var/www/koios/VERSION` | | Container status | `docker ps` / `systemctl status docker.koios` | | Service log at Debug for the failing service | [Logs](https://ai-ops.com/docs/system/logs.md) | | Container log dump (`koios-diagnostics.log`) | `docker logs --tail 500 koios > koios-diagnostics.log` | | Error Code, Message, and Detail from the affected entity | The entity's detail panel — see [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md) | | A recent backup | [Backup & Restore](https://ai-ops.com/docs/system/backup.md) | --- ## What's Next - [Reading Status, Quality & Errors](https://ai-ops.com/docs/troubleshoot/reading-status-and-errors.md): the three diagnostic fields, the status and quality legend, and the master error-code lookup - [Troubleshooting Koios](https://ai-ops.com/docs/troubleshoot/introduction.md): the symptom router for finding the right layer to investigate - [Server Won't Start](https://ai-ops.com/docs/troubleshoot/server-startup.md): recover a container that won't finish starting - [Logs](https://ai-ops.com/docs/system/logs.md): set the Debug log level, stream live output, and download archived log files - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): create a backup to attach or to protect the failing state --- Source: https://ai-ops.com/docs/updates/general Section: Upgrading # Updating Koios Koios updates are delivered as new Docker image versions. Your data is stored in Docker volumes, so it is preserved across updates. > [!TIP] Back Up First > Before upgrading, create a backup in case you need to roll back. The easiest way is from **System > Backup** in the web interface (see [Backup & Restore](https://ai-ops.com/docs/system/backup.md)). For command-line backups, see [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md). > [!WARNING] Check the Migration Guide > Major version upgrades (e.g. v0.10.x to v1.0.0) may require changes to your service file or Docker run command. If a migration guide exists for your target version, check it before upgrading. ## Pull the New Image ```bash docker pull aiopinc/koios:latest ``` Or pull a specific version: ```bash docker pull aiopinc/koios:v1.0.0 ``` ## Update: Systemd Service If you're running Koios as a systemd service, pull the new image first, then restart the service: ```bash sudo systemctl restart docker.koios.service ``` The service will automatically stop the old container and start a new one with the updated image. ## Update: Manual Docker Run If you're running Koios manually, stop and remove the old container, then start a new one: ```bash docker stop koios docker rm koios ``` Then re-run the same `docker run` command from [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md). Your data persists in the Docker volumes. ## Downgrade to a Previous Version To roll back to a specific version, pull that version's tag and restart: ```bash docker pull aiopinc/koios:v1.0.0 ``` Then update the service file or `docker run` command to reference the specific tag instead of `latest`. > [!WARNING] Database Migrations > Newer Koios versions may include database migrations that run automatically on startup. After downgrading, the database schema may be newer than the software expects. If the version gap is too large, the container will log a "Schema version incompatible" error and exit. Restore from a backup taken before the upgrade to resolve this. ## Verify the Update After restarting, check that the new version is running: ```bash docker ps ``` You can also verify the version from the Koios web interface under **System > Overview**. ## What's Next - [Migrating to v1.0.0](https://ai-ops.com/docs/updates/v1-0-0.md): breaking changes and migration steps for upgrading from v0.10.x - [Backup & Restore](https://ai-ops.com/docs/system/backup.md): create a backup before upgrading and restore if you need to roll back - [v1.1.0 Release Notes](https://ai-ops.com/docs/release-notes/v1-1.md): what's new in the latest release --- Source: https://ai-ops.com/docs/updates/v1-1-0 Section: Upgrading # Upgrading to v1.1.0 Koios v1.1.0 supports a direct upgrade from both **v1.0.x** and **v0.10.x**. Database migrations run automatically the first time the new container starts, and the entrypoint takes an automatic backup before migrating. Before you begin, follow the general [update procedure](https://ai-ops.com/docs/updates/general.md) to pull the new image and restart the service. > [!TIP] Back up first > The entrypoint saves a pre-migration database backup automatically, but a full [volume backup](https://ai-ops.com/docs/installation/backup-restore.md) before any upgrade is still the safest practice. ## From v1.0.x This is a drop-in upgrade. No volume or configuration changes are needed: 1. Pull the new image and restart the service, following [Updating Koios](https://ai-ops.com/docs/updates/general.md). 2. Migrations run automatically on first boot. 3. Confirm the new version under **System > Overview**. Your existing devices, tags, models, and bindings carry forward. Binding calibration is off by default, so existing bindings behave exactly as before until you set a gain or bias. ## From v0.10.x A v0.10.x upgrade needs the same one-time change introduced in v1.0.0: the `koios_secrets` volume must be mounted so runtime secrets are generated and preserved across restarts. Complete the [v1.0.0 migration steps](https://ai-ops.com/docs/updates/v1-0-0.md) to add the seventh volume mount to your service file, then proceed with the standard update. Your existing credentials are detected and preserved. > [!WARNING] The secrets volume is required > Starting with v1.0.0, the container refuses to start if any of its seven volume mounts is missing and logs `FATAL: Required Docker volume mounts missing`. Make sure `koios_secrets` is mounted before you start the new image. See [Migrating to v1.0.0](https://ai-ops.com/docs/updates/v1-0-0.md) for the exact mount. ## After Upgrading 1. Confirm the version under **System > Overview**. 2. Check **System > Service Status** to verify every service is running. 3. Review the [v1.1.0 release notes](https://ai-ops.com/docs/release-notes/v1-1.md) for new features. ## What's Next - [Updating Koios](https://ai-ops.com/docs/updates/general.md): the general update procedure for any version. - [v1.1.0 Release Notes](https://ai-ops.com/docs/release-notes/v1-1.md): everything new in this release. - [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md): back up before you upgrade. --- Source: https://ai-ops.com/docs/updates/v1-0-0 Section: Upgrading # Migrating to v1.0.0 This guide covers the breaking changes and required steps when upgrading from any **v0.10.x** release to **v1.0.0**. > [!TIP] Back Up First > Always create a backup before a major version upgrade. Use **System > Backup** in the web interface or see [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md). ## Breaking Changes ### New `koios_secrets` Volume Koios v1.0.0 moves runtime credentials out of the Docker image and onto a dedicated volume. This affects how the container is started. | Change | Details | |--------|---------| | **New volume** | `koios_secrets` stores database passwords, the application secret key, and the time-series database token | | **Automatic migration** | On first boot with an existing database, Koios writes the legacy credential values to the new volume automatically. No manual credential changes needed | | **Service file update required** | Your systemd service file or `docker run` command must include the new volume mount | ### Update the Service File Open your service file: ```bash sudo nano /etc/systemd/system/docker.koios.service ``` Add the `koios_secrets` volume mount to the `ExecStart` line, after the `koios_license` mount: ```text --mount source=koios_secrets,target=/var/www/koios/secrets \ ``` Your `ExecStart` should now include **seven** `--mount` lines. See [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md) for the complete service file. Then reload and restart: ```bash sudo systemctl daemon-reload sudo systemctl restart docker.koios.service ``` ### Update a Manual Docker Run Command If you use `docker run` directly, add the same mount flag. See [Manually Starting Koios](https://ai-ops.com/docs/installation/manually-starting-koios.md) for the complete command. > [!WARNING] The secrets volume is mandatory > Without the `koios_secrets` volume the container refuses to start. The entrypoint validates all seven volume mounts, and if any are missing it logs "FATAL: Required Docker volume mounts missing" and exits. Add the secrets mount before starting v1.0.0. ## Database Migrations v1.0.0 includes database migrations that run automatically on first startup. These migrations: - Add tables for components, scan groups, expression tags, dashboards, roles, and API clients - Add new fields to existing device, tag, and model tables - Create the `koios_schema_meta` table for version compatibility tracking All migrations are **forward-compatible**: your existing devices, tags, models, and configuration are preserved without modification. > [!WARNING] Pre-Migration Backup > The v1.0.0 entrypoint automatically takes a database backup before running migrations, saved to the media volume at `/var/www/koios/media/backups/pre-migrate-backup.sql`. This is a safety net. You should still create your own backup before upgrading. ## New Features For a complete list of what's new in v1.0.0, see the [v1.0.0 Release Notes](https://ai-ops.com/docs/release-notes/v1-0.md). ## Verification After upgrading, confirm the new version is running: 1. Open the Koios web interface 2. Navigate to **System > Overview** 3. Verify the version shows **1.0.0** If the container fails to start, check the logs: ```bash # Systemd service journalctl -u docker.koios.service -f # Manual run docker logs koios ``` Common issues: - **"Schema version incompatible"**. You're running a version older than what the database expects. Restore from backup and try again with the correct image. - **Services failing to authenticate**. The `koios_secrets` volume mount is missing. Add it and restart. ## What's Next - [v1.0.0 Release Notes](https://ai-ops.com/docs/release-notes/v1-0.md) - [Backup & Restore](https://ai-ops.com/docs/system/backup.md) - [Updating Koios](https://ai-ops.com/docs/updates/general.md) --- Source: https://ai-ops.com/docs/release-notes/v1-2 Section: Release Notes # Koios 1.2 - [Serial and GPIO device access](#serial-and-gpio-device-access): attach host hardware to Koios > [!NOTE] Under active development > Koios 1.2 has not been released yet. This page previews changes that have already landed and will grow as the release comes together, so details may still change before general availability. --- ## Serial and GPIO device access `Upcoming` Koios can now reach serial, GPIO, I2C, and SPI hardware attached to the host without a world-writable device node or a privileged container. Expose a device node with `--device`, and Koios grants its services access through the node's owning group. Standard serial devices (the `dialout` group) work with no configuration. For other peripherals, the new `KOIOS_EXTRA_GROUPS` variable takes a comma-separated list of group names and/or numeric group IDs. Numeric IDs are the reliable choice, because a device's group ID varies between hosts. Root (group ID `0`) is refused, and unresolvable entries are skipped rather than blocking startup. See [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md) for `KOIOS_EXTRA_GROUPS` and the setup steps. --- Source: https://ai-ops.com/docs/release-notes/v1-1 Section: Release Notes # Koios 1.1 - [v1.1.0](#v110) — feature release - [Helm chart 1.1.1 and 1.1.2](#helm-chart-111-and-112) — chart-only releases, no image changes - [v1.1.3](#v113) — Kubernetes hotfix - [v1.1.4](#v114) — OPC-UA hotfix --- ## v1.1.0 `July 16, 2026` The first minor release on top of the v1.0 line. This release focuses on the canvas and AI model experience: calibrate bindings without retraining, deploy flat (rank-2) models alongside time-series models, and wire components against any live entity, not just tags. The canvas itself gets per-instance pin layouts, custom wire routing, and end-to-end type validation that paints invalid connections red before save. This release also debuts the **Koios Admin Console**, a separate companion app for managing many Koios instances from one place. > [!TIP] Drop-in upgrade > v1.1.0 is fully compatible with v1.0.x. No service file changes, no new volumes, no manual migration steps. Pull the new image and restart. See [Updating Koios](https://ai-ops.com/docs/updates/general.md). > [!WARNING] Custom component authors > The Component Builder SDK base version bumped from 2 to 3 to support the new pin layout API. Components built against SDK v2 continue to load, but to use [per-instance pin layouts](https://ai-ops.com/docs/components/canvas.md) on a component type you must rebuild with the latest `koios-component-builder` package. See [Building Components](https://ai-ops.com/docs/components/building-components.md) for the new `inputs_layout` / `outputs_layout` API. --- ### Koios Admin Console v1.1.0 introduces the **Koios Admin Console**, a separate companion app for managing many Koios instances from one place. Instead of signing into each box individually, you get a single fleet view of service health and failures across every instance, plus license state and remote `.lic` upload. It ships as its own small image (`aiopinc/koios-admin`), runs alongside your boxes on the same network, and connects to each one read-only through a scoped access token. The console is optional and does not change how an individual Koios box runs. See the [Admin Console documentation](https://ai-ops.com/docs/admin-console/introduction.md) to install it, run it as a service, and connect your fleet. --- ### AI Models #### Gain and Bias Calibration Every model binding now has dedicated **gain** and **bias** fields for linear calibration. Apply a slope-intercept transform directly on a binding to correct sensor drift, convert engineering units, or fine-tune a model's response without retraining or redeploying the ONNX file. Calibration applies in addition to the existing normalization settings. Gain and bias are applied to the raw tag value before interpolation and normalization, so the rest of the binding pipeline works in the calibrated value space. If you set a non-default gain or bias while using Min-Max or Symmetric normalization, the normalization source must be Custom, since Tag Range bounds describe the raw value rather than the calibrated one. Defaults are identity (`gain=1.0`, `bias=0.0`), so existing bindings see no change after upgrade. See [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md) for the full configuration guide. #### Support for Flat (Rank-2) Models Koios now accepts both **flat** (rank-2) and **time-series** (rank-3) models from ONNX and TFLite. Flat models (scikit-learn classifiers, single-step reinforcement-learning policies, and other models that take one observation per inference) no longer require padding tricks or a fake time dimension. - **Automatic shape detection**: the platform reads the model graph at upload time and detects rank, input count, and observation depth. A checksum catches metadata drift before the model goes live. - **Clearer shape labels**: model lists and detail pages now show "5 inputs, depth 1" for a flat model versus "5 inputs, depth 6" for a time-series model. - **Faster inference for flat models**: the predict engine skips historical buffer queries and reads fresh values directly from the live cache, lowering scan-cycle latency at fast scan rates. See [Model Inference Requirements](https://ai-ops.com/docs/models/inference-requirements.md) for shape details and [Training a Model](https://ai-ops.com/docs/models/training-a-model.md) for export guidance. #### Broader ONNX Compatibility The platform's ONNX runtime was upgraded, raising the highest ONNX **IR version** Koios can load from 11 to **13** and adding support for newer operator sets (opsets). Files exported by recent versions of PyTorch, TensorFlow, or the `onnx` exporter, which v1.0.x rejected at upload for targeting a too-new IR version, now upload and run without re-exporting to an older format. Upload validation runs against the **same runtime** used for inference, so any file Koios accepts at upload is guaranteed to load in the predict engine. Files above IR 13 are still rejected at upload with a clear message. Re-export at a compatible IR version, or annotate the model with the Koios model-utils library, which clamps the IR version to a safe value automatically. #### Live Prediction Cycle Visualization The model spine in the navigation now shows a radial progress ring animated around the brain icon over the model's scan rate. The ring is anchored to the server clock, so it stays in sync with what the predict engine is actually doing, and pulses briefly each time a new prediction lands. This signals that a model is alive and on schedule. #### Scan Rate and Sample Rate Linking In the model configuration form, scan rate and sample rate are now linked when they match (the case for nearly every forecasting model). Edit one and the other follows. A chain toggle lets you unlink for controllers that need a faster execution cadence than their training data. The chain is automatically hidden when the model belongs to a scan group, since the group controls execution. #### Tag-to-Binding Visibility Tag detail pages now show every model binding that references the tag, with the model name, binding direction, and ordinal. Helpful when you're about to disable or delete a tag and need to know what depends on it. --- ### Canvas and Components #### Wire Anything, Not Just Tags Component input connectors now read from **any live entity** in Koios (devices, AI models, model bindings, and scan groups) in addition to tags and component outputs. Each entity exposes a curated set of fields (e.g., a device exposes status, last-seen, error code; a model exposes its current prediction; a binding exposes the live value flowing through it). This lets you build components that react to system state, not just sensor data. Each connector type only exposes fields that make sense for that entity, so you cannot wire incompatible data into a component input. #### Per-Instance Pin Layouts Pin order, gaps, and visibility are now configurable **per instance**, not just per component type. Open the pin layout editor from any instance to: - Drag pins to reorder them - Insert gaps for visual grouping - Hide pins that you don't need on this particular instance Hidden pins are kept in a side tray and can be dragged back at any time. Layouts persist across canvas saves, environment clones, and copy/paste operations. The component definition still provides the default. Overrides are layered on top. #### Custom Wire Routing Click any wire to reveal a midpoint handle, then drag perpendicular to de-stack parallel wires or reshape a route for readability. Double-click resets the wire to its default path. Routing is saved with the canvas and survives copy/paste. #### Structured Type Validation Wire validation has been rebuilt to give you immediate, specific feedback: - **Invalid wires paint red** with a tooltip explaining why (e.g., "string output cannot connect to numeric input") - **Save errors are scoped**: when a save fails, the offending instance, connector, or wire is highlighted directly on the canvas rather than buried in a generic error toast - **The wire contract is now part of the GraphQL schema**: the canvas, the engine, and the builder all consume the same coercion rules and source-field allowlists, eliminating cases where validation behaved differently in different surfaces The same validation runs in the engine: if a malformed wire ever slips through, the affected instance enters an ERROR state with the offending pin called out in the diagnostics. #### Pin Type Mismatch Detection The component engine now detects pin-type mismatches at runtime and surfaces them in the UI. Wires that pass UI validation but produce a type mismatch downstream (e.g., an upstream component changes type after a library upgrade) put the instance into ERROR with a clear diagnostic rather than producing silently wrong outputs. #### Live Output Publishing Component instances now publish a tag-value notification on every successful output write, not just when the value changes. Downstream consumers (expression tags, AI bindings, history) react immediately to fresh values without falling back to a 10-second poll. This eliminates the workaround of setting `EE_IN_MEMORY_SCAN_RATE=1` to get timely sampling on in-memory inputs. #### Component Builder SDK v3 The Component Builder package gains a canonical pin layout API: ```python class MyComponent(Component): class Meta: inputs_layout = ["input_a", Gap(), "input_b", "input_c"] outputs_layout = ["primary", "secondary"] ``` This replaces the `FieldDescriptor(order=...)` convention, which is now deprecated. The SDK also gains a shared `wire_contract` module that lets custom components participate in the same type system the canvas and engine use. See [Building Components](https://ai-ops.com/docs/components/building-components.md) for the full API reference. --- ### Reliability and Performance #### No More Duplicate Toasts The event relay that powers live UI notifications used to be started inside the web server's startup hook, which spawned one relay per worker process. The result was duplicate WebSocket frames and the same toast firing two or four times in a row. The relay now runs as a single dedicated process, so each event is delivered exactly once. #### Out-of-Range Debounce No Longer Oscillates Models with rate-of-change or range-check diagnostics could enter a sawtooth where the diagnostic flipped between triggered and recovered on every cycle. The debounce counter now stays triggered until a real recovery condition is observed, eliminating the noise. #### Live IN_MEMORY Tag Relay Expression tags and AI models that consume in-memory tags (component outputs, expression results, model predictions) now receive updates via direct event dispatch instead of polling. The previous 10-second polling fallback has been demoted to a 60-second heartbeat that exists purely as a safety net to detect stale producers. You can tune the heartbeat with the new `EE_IN_MEMORY_HEARTBEAT_INTERVAL` environment variable; the legacy `EE_IN_MEMORY_SCAN_RATE` is still honored for backward compatibility. #### Stopped Service Alert A persistent footer banner now appears when a critical platform service (predict engine, datacollector, expression evaluator, component engine) is stopped or failing. The banner is severity-aware (red when everything is down, amber when only some services are affected) and can be dismissed for the session. #### Server Clock Anchoring Live timers (prediction rings, "last updated" tickers) and chart x-axes now read from a server-anchored clock instead of the browser clock. Hosts with misaligned wall time no longer cause UI drift that makes charts look broken or live values appear stale. #### Restore-Safe Time-Series Bucket Lifecycle Time-series bucket creation, renaming, and deletion now happen after the database transaction commits. This eliminates a class of race conditions where a model rename in one tab could land in the time-series database before the configuration database knew about it, producing orphaned buckets. --- ### Security #### Component Upload Hardening `.kcl` (component library) uploads are now subject to additional safety checks: - **500 MiB upload cap** enforced before the file is read into memory - **Safe zip extraction** rejects archives with path-traversal entries (zip slip) or malformed member names - **AST analyzer** in the Component Builder now catches dangerous calls made via attribute access (e.g., `builtins.eval(...)`) in addition to direct calls - **Library name validation** restricts names to lowercase letters, digits, hyphens, and underscores - **`data_files` path validation** prevents `setup.py` from packaging files outside the wheel directory These checks apply to both uploaded libraries and the Component Builder CLI used by component authors. --- ### UI Polish - **Tab count badges**: detail page tabs that own collections (bindings, instances, libraries) now show a neutral count badge on the right, with an optional red notification dot when items are in an issue state. - **Canvas selection preservation**: selection survives drag, arrow-key nudge, and other mutations. Arrow-key moves are now part of the undo history. - **Add Models to Scan Group modal**: fixed a double-toggle bug where clicking a row checkbox cancelled itself out. --- ### Upgrading To upgrade from v1.0.x to v1.1.0: 1. **Back up your data**: use **System > Backup**, or follow [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md). 2. **Pull the new image:** ```bash docker pull aiopinc/koios:v1.1.0 ``` 3. **Restart the service:** ```bash sudo systemctl restart docker.koios.service ``` The first startup runs additive schema migrations (gain/bias on bindings, input rank tracking, per-instance pin layouts). No service file or volume changes are required. See [Updating Koios](https://ai-ops.com/docs/updates/general.md) for general upgrade guidance. --- ### Service Manifest | Service | Notable Change | |---|---| | Webapp | Calibration fields, multi-entity connectors, per-instance pin layouts, custom wire routing, wire contract API, structured canvas validation, dedicated event relay process | | UI | Calibration controls, pin layout editor, wire routing, live prediction ring, scan/sample rate linking, stopped-service banner, server-clock anchoring, tab count badges | | Predict engine | Rank-2 model graph support, fresh-value read path for flat models, per-cycle output publish, debounce fix, cleaner binding error diagnostics, upgraded ONNX runtime (loads IR 13 / newer opsets) | | Datacollector | Generic EtherNet/IP tag-grouping fix | | Expression evaluator | Event-driven IN_MEMORY relay, configurable heartbeat | | Component engine | Pin type mismatch detection, multi-entity dispatch, thread-safety hardening | | Component builder | SDK v3 pin layout API, shared wire contract, expanded AST analyzer, name and path validation | | Utility | Calibration schema, input rank, multi-entity connector enum, safe zip extraction helper | | _All others_ | Unchanged from v1.0.2 | --- ## Patch releases ### Helm chart 1.1.1 and 1.1.2 `July 21, 2026` Chart-only releases; no image changes. Starting with the 1.1 line, a Helm chart release accompanies every Koios release, and the chart's default image is the Koios version it shipped with — upgrading on Kubernetes is now just a chart version bump, with no image tag to manage in your values file. - **Chart 1.1.1** fixed the persistent volume layout that prevented Koios v1.1.0 from starting on Kubernetes. Existing data is preserved on upgrade. - **Chart 1.1.2** validates persistence configuration at install time (all persistent volumes are required and can no longer be disabled), and every chart release is now boot-tested on a live cluster before publishing. ### v1.1.3 `July 21, 2026` Hotfix release for Kubernetes deployments. Docker deployments are unaffected. - Fixed the container failing its startup volume check and refusing to boot on Kubernetes when persistent volumes are mounted at a parent path (the layout used by Helm chart versions before 1.1.1). The check now recognizes any persistent backing for the required paths. ### v1.1.4 `August 8, 2026` Hotfix release for OPC-UA connections and client certificates. > [!TIP] Certificates issued before v1.1.4 > If an OPC-UA server rejects a certificate Koios generated on an earlier version, regenerate it from [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md) and trust the new certificate on the server. Existing certificates keep working where the server already accepts them. - **Slow servers now connect.** Devices on an OPC-UA server that takes longer than a second to open a session previously failed with a generic connection error, no matter how high the device timeout was set. The device timeout is now honoured throughout the connection sequence. - **Uploaded client certificates work.** An uploaded certificate and key pair is now stored in a form the device can actually use — previously an upload was accepted but the device could never connect with it. If your private key is passphrase-protected, there is now a **Key Passphrase** field on the upload dialog; leave it blank for an unencrypted key. A key stored by an earlier version is repaired automatically the first time v1.1.4 starts, with no need to re-upload. - **Generated certificates meet server requirements.** Certificates issued by Koios now carry the client authentication extension that OPC-UA servers check for, and become valid a day before they are issued so a clock difference between Koios and the server cannot make a brand-new certificate appear invalid. - **Uncertain readings keep their value.** A tag read that the server marks uncertain — a value it will supply but not guarantee, such as a stale or substituted reading — is now recorded with its value and its reported quality, instead of being discarded as a failed read. --- Source: https://ai-ops.com/docs/release-notes/v1-0 Section: Release Notes # Koios 1.0 - [v1.0.0](#v100) — GA release - [v1.0.1](#v101) — scheduling fix - [v1.0.2](#v102) — model-history and upload fixes --- ## v1.0.0 `April 17, 2026` **Koios v1.0.0** adds the component engine, expression tags, a rebuilt single-page UI, backup and restore, network diagnostics, and per-installation secrets. It also expands AI model configuration, redesigns value mapping, and adds an offline in-app help system. > [!TIP] Upgrading from v0.10.x? > Koios v1.0.0 is fully backward-compatible with existing v0.10.x deployments. Your devices, tags, models, and configuration will be automatically migrated during the upgrade. See [Migrating to v1.0.0](https://ai-ops.com/docs/updates/v1-0-0.md) for the step-by-step upgrade guide. --- ### Component Engine Deploy your own custom Python logic directly into the Koios runtime. No external services or infrastructure required. **Components** are reusable Python packages that execute in real-time alongside your devices and models. Wire them together to build processing pipelines for control algorithms, data transformations, state machines, and custom protocol adapters. - **Visual wiring**: connect component inputs and outputs to tags, models, or other components through the UI - **Configurable scan rates**: execute components from every 100ms to once per hour - **Multiple environments**: organize components into independent execution environments with separate scan rates - **Component libraries**: upload packaged component libraries (`.kcl` files) and manage versions - **Component Builder**: build your own components using the published Python library with typed inputs, outputs, and configuration fields - **Full audit trail**: every component execution and configuration change is logged > [!NOTE] Getting Started with Components > The Component Builder provides base classes, field descriptors, and a CLI tool for packaging your components into uploadable libraries. Contact your Koios representative for access and documentation. See [Components](https://ai-ops.com/docs/components/introduction.md) for the full guide to libraries, environments, and wiring. --- ### Expression Tags Create calculated data points using formulas and logic. No code required. Expression tags let you define computed values that reference real-time data from across your entire Koios deployment. They evaluate continuously at configurable scan rates and their results are available everywhere: in dashboards, as model inputs, or as inputs to other expressions. - **Cross-entity references**: combine values from tags, devices, and AI models in a single expression - **Arithmetic and logic**: full support for math operators, conditionals (`if`/`then`/`else`), and boolean logic (`AND`/`OR`/`NOT`) - **Configurable precision**: set decimal places per expression for clean display - **Historical tracking**: expression results are stored in the time-series database for trending and analysis - **Safe evaluation**: expressions run in a sandboxed evaluator with no risk of code injection ```text Example: if(tag:30:status == 1, tag:10:value * 0.85 + tag:20:value, 0) ``` See [Expression Tags](https://ai-ops.com/docs/tags/expressions.md) for the full syntax reference. --- ### AI Model Enhancements Major improvements to how you configure, run, and monitor AI models. #### Scan Groups Group related models for synchronized, batched execution. Scan groups share on-demand read/write settings, ensuring all models in a group see the same fresh data snapshot. This improves throughput and consistency when running multiple models against the same set of devices. See [Scan Groups](https://ai-ops.com/docs/models/scan-groups.md) for details. #### Memory-Only Mode Run models in ultra-low-latency mode by skipping historical storage of inference results. Ideal for real-time control loops where you need sub-10ms scan rates and don't need to retain every output value. Memory-only models still write live values for dashboards and downstream consumption. See [Configuring a Model](https://ai-ops.com/docs/models/configuring-a-model.md) for details. #### Advanced Normalization Expanded normalization options give data scientists precise control over how input values are prepared for inference: | Normalization Type | Description | |---|---| | **None** | Raw values passed directly | | **Min/Max** | Scale to 0–1 range using tag or custom bounds | | **Symmetric** | Scale to -1 to 1 range | | **Z-Score** | Standardize using mean and standard deviation | Each binding can use either the tag's configured range or custom values, giving you full control over normalization parameters without modifying the model file. See [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md) for configuration details. #### Rate-of-Change Detection Configure per-binding thresholds that flag when input values change too quickly. Supports both absolute and percentage-based thresholds with configurable detection windows and direction filtering. Useful for catching anomalous spikes, equipment failures, or sensor drift before they impact inference quality. See [Assigning Bindings](https://ai-ops.com/docs/models/assigning-bindings.md) for configuration details. #### Reset from Metadata When uploading a new model file version, use **Reset from File** to automatically apply settings embedded in the model's metadata (sample rate, model type, normalization parameters) while preserving your existing tag assignments. This streamlines the model update workflow for data scientists iterating on model versions. See [Managing Model Files](https://ai-ops.com/docs/models/model-files.md) for details. #### On-Demand Inference Models and scan groups can now trigger fresh device reads before each inference cycle and write outputs back to devices immediately after. This ensures models always operate on the latest data and can close control loops in a single scan cycle. See [On-Demand Inference](https://ai-ops.com/docs/models/on-demand-inference.md) for configuration details. --- ### Redesigned User Interface The entire Koios frontend has been rebuilt as a modern single-page application. #### What Changed - **Instant navigation**: page transitions are immediate with no full-page reloads - **Faster live updates**: optimized polling and cache-based merging for smoother real-time device values, tag status, and model outputs - **Responsive layout**: works across desktop, tablet, and large monitoring displays - **Consistent design**: unified card layouts, status indicators, and action patterns across all pages - **Keyboard navigation**: full keyboard support for accessibility and power users #### New Pages | Page | Description | |---|---| | **System Health** | Real-time CPU, memory, and disk monitoring with configurable alarm thresholds | | **Live Log Viewer** | Stream service logs in real-time with color-coded output levels and pause/resume | | **Scan Groups** | Manage model execution groups with shared scan rates and on-demand settings | | **Component Environments** | Configure and monitor component execution environments | | **Component Libraries** | Browse, upload, and manage component library packages | #### Improved Tables All data tables now support: - **Bulk actions**: enable, disable, or delete multiple items at once with a single click - **CSV import and export**: bulk import devices, tags, and model configurations from spreadsheets - **Column sorting and filtering**: find what you need quickly in large deployments - **Progress indicators**: visual feedback during bulk operations #### Trend Customization The trend viewer now supports deep customization that is saved and persisted per trend: - **Per-trace styling**: assign a custom color to each trace and pin it to a specific Y-axis - **Multiple Y-axes**: add left and right axes with custom labels, colors, and independent min/max bounds - **Line style controls**: adjust line width, point radius, curve tension (sharp to smooth), and area fill with opacity - **Data aggregation**: choose between automatic or manual windowing with aggregation functions (mean, median, min, max, sum, first, last) - **Gap filling**: optionally fill missing data points for a continuous view - **CSV export**: export trend data for offline analysis All customizations are saved to the trend and available the next time you open it. #### Dashboard Improvements The dashboard has been overhauled with a flexible widget system for building custom monitoring views. - **Multiple dashboards**: create and switch between different dashboard layouts, each tailored to a specific role or process area - **Drag-and-drop grid**: reposition and resize widgets freely on a responsive 12-column grid - **8 widget types**: Tag Value, Tag Chart, Device Status, Device Uptime, Device Execution, Model Status, Model Uptime, and Model Execution - **Widget configuration**: customize each widget's appearance (font size, colors, decimal places, chart time range, line styles, and more) - **Live updates**: all widgets poll for live data automatically - **Default dashboard**: mark a dashboard as your default so it loads on login See [Dashboard](https://ai-ops.com/docs/dashboard/introduction.md) for the full guide. #### Event Storm Detection When many events fire in rapid succession (e.g., enabling hundreds of tags at once), the UI now groups them into a single summary notification instead of flooding your screen. High-frequency event storms are detected automatically and displayed as a consolidated alert. --- ### In-App Documentation Koios now ships with a complete help system built directly into the application. No external website or internet connection required. - **80+ help pages** covering installation, devices, tags, models, system administration, and more - **Full-text search** across all documentation - **Always in sync**: documentation updates ship with each Koios release - **Available offline**: accessible on air-gapped deployments with no internet access Access documentation at any time from the help menu in the navigation bar. --- ### Security and Deployment #### Unique Per-Installation Secrets Every Koios installation now generates its own unique internal credentials on first boot: database passwords, session signing keys, and service authentication tokens are all created automatically. No two installations share the same secrets. Upgrades from previous versions require no manual action. #### Schema Version Compatibility A new compatibility check runs on every startup to prevent accidental data loss. If you attempt to run an older Koios version against a database that has been migrated to a newer schema, the system will block startup with a clear error message and instructions. A pre-migration backup is also created automatically before each upgrade. #### Multi-Architecture Support Koios Docker images are now built for both **x86_64 (AMD64)** and **ARM64** architectures. Deploy on standard servers, AWS Graviton instances, or ARM-based edge devices using the same image tag. #### Flexible TLS Configuration New environment variables (`ENABLE_TLS`, `HTTP_PORT`, `HTTPS_PORT`) let you configure TLS behavior to match your deployment topology. Run HTTPS directly, or disable TLS when Koios sits behind a load balancer that handles certificate termination. See [Environment Variables](https://ai-ops.com/docs/installation/environment-variables.md) for the full configuration reference. #### Improved Rate Limiting API rate limits have been increased and tuned per endpoint to better support dashboards with many simultaneous data streams while still protecting against abuse. --- ### Data Collection Improvements - **On-demand reads and writes**: request fresh values from devices on demand, outside the normal scan cycle. See [On-Demand Scanning](https://ai-ops.com/docs/devices/on-demand-scanning.md) for configuration. - **Tag value notifications**: real-time push notifications when tag values change, enabling faster dashboard updates - **Circuit breaker patterns**: automatic backoff and recovery when devices become unreachable, preventing cascading failures - **OPC-UA certificate management**: manage client certificates for secure OPC-UA connections directly from the UI. See [OPC-UA Certificates](https://ai-ops.com/docs/protocols/opc-ua-certificates.md) for details. --- ### Value Mapping Tag value mapping has been completely redesigned. The previous "Lookup Table" feature only supported exact string matching against a fixed dictionary. The new **Value Mapping** system introduces a rules-based engine with ordered evaluation, multiple match types, and flexible options. #### Match Types | Match Type | Description | Example | |---|---|---| | **Exact** | Value equals pattern | `"Off"` → `0` | | **Greater than / Greater or equal** | Numeric comparison | `> 100` → `1` | | **Less than / Less or equal** | Numeric comparison | `<= 0` → `0` | | **Between** | Numeric range (inclusive) | `10,50` → `1` | | **Glob** | Wildcard pattern (`*` any chars, `?` single char) | `"Error*"` → `-1` | | **Any** | Catch-all default (always matches) | `*` → `0` | Rules are evaluated in order from top to bottom. The first matching rule wins. Reorder rules using the arrow buttons in the editor, and use the **Any** match type as a fallback at the end. #### New Options - **Case-insensitive matching**: exact and glob matches ignore letter case - **Reverse mapping on write**: when writing values back to a device, automatically converts numeric outputs back to their original string representation #### Migration Existing lookup tables are automatically converted to the new rules format during upgrade. Simple key/value pairs become **Exact** match rules, and wildcard (`*`) entries become **Any** rules. No manual action is required. See [Value Mapping](https://ai-ops.com/docs/tags/value-mapping.md) for the full configuration guide. --- ### Backup and Restore A new built-in backup system lets you protect your Koios deployment directly from the UI at **System > Backup**. No SSH or Docker CLI required. - **Two backup tiers**: **Config** backups capture devices, tags, users, models, and settings in seconds. **Full** backups also include historical time-series data. - **Scheduled backups**: configure automatic daily or weekly backups at 2:00 AM with a configurable retention policy (1–50 backups kept) - **One-click restore**: upload a backup file, preview its contents, and restore with a single click. Full backups let you optionally include or exclude historical data. - **Download backups**: download backup archives to your local machine for off-site storage See [Backup & Restore](https://ai-ops.com/docs/system/backup.md) for the full guide. --- ### Network Diagnostics A new **System > Network** page gives you visibility into the server's network configuration and built-in tools for troubleshooting device connectivity, all from the browser. - **Interface overview**: see every network interface with its IP addresses, MAC address, link speed, and status - **Ping**: test basic connectivity and measure round-trip latency to any host - **Traceroute**: trace the network path to identify where packets are dropped or delayed - **DNS lookup**: query A, AAAA, MX, NS, TXT, CNAME, and other record types - **TCP port check**: verify that a device's communication port is reachable before configuring a connection (e.g., port 4840 for OPC-UA, port 502 for Modbus TCP) Results stream in real time to a terminal-style output panel with auto-scroll, pause/resume, and clear. See [Network Diagnostics](https://ai-ops.com/docs/system/network.md) for details. --- ### System Administration - **Service health monitoring**: real-time status of all platform services with category-based organization. See [Services](https://ai-ops.com/docs/system/services.md). - **Configurable alarm thresholds**: set warning and critical limits for CPU, memory, and disk usage. See [System Health](https://ai-ops.com/docs/system/performance.md). - **User and role management**: create users, define custom roles, and assign granular permissions. See [Users](https://ai-ops.com/docs/system/users.md) and [Roles & Permissions](https://ai-ops.com/docs/system/roles-permissions.md). - **API client management**: generate and manage credentials for external system integrations. See [API Clients](https://ai-ops.com/docs/system/endpoints.md). - **Data retention policies**: configure automatic cleanup rules for historical data and storage monitoring. See [Data Retention](https://ai-ops.com/docs/system/retention.md). --- ### Upgrading To upgrade from v0.10.x to v1.0.0: 1. **Back up your data**: use the in-app backup at **System > Backup**, or follow [Backing Up Docker Volumes](https://ai-ops.com/docs/installation/backup-restore.md) 2. **Update the service file**: v1.0.0 introduces a new `koios_secrets` volume for storing per-installation secrets (database password, Django secret key, etc.). Your existing service file from v0.10.x does not include this volume, so you need to add it before starting the new version. Open your service file: ```bash sudo nano /etc/systemd/system/docker.koios.service ``` Add the following line to the `ExecStart` section, after the existing volume mounts: ```text --mount source=koios_secrets,target=/var/www/koios/secrets \ ``` Then reload the service configuration: ```bash sudo systemctl daemon-reload ``` See [Running Koios as a Service](https://ai-ops.com/docs/installation/running-as-a-service.md#create-the-service-file) for the complete service file with all seven volume mounts. > [!NOTE] Existing secrets are preserved > On first startup, Koios detects that your database already exists and writes the legacy secret values to the new secrets volume. Your existing data and sessions continue to work, and no manual secret migration is needed. 3. **Pull the new image:** ```bash docker pull aiopinc/koios:v1.0.0 ``` 4. **Restart the service:** ```bash sudo systemctl restart docker.koios.service ``` The first startup will run database migrations and generate per-installation secrets automatically. This may take a few minutes on large deployments. See [Migrating to v1.0.0](https://ai-ops.com/docs/updates/v1-0-0.md) for the full upgrade guide. --- ## Patch releases ### v1.0.1 `May 11, 2026` Patch release fixing a scheduling defect that could cause duplicate device polls and duplicate model executions after rapid enable/disable toggling. > [!TIP] Drop-in upgrade > v1.0.1 is fully compatible with v1.0.0 — no service file changes, no database migrations beyond the standard startup checks. Just pull the new image and restart. See [Updating Koios](https://ai-ops.com/docs/updates/general.md). --- #### Fixed ##### Duplicate scheduling chains after rapid enable/disable Rapidly toggling a device or model's enabled state could leave behind orphaned scheduling chains in the data collector and predict engine. Each orphan would continue polling its device (or executing its model) on the next scan cycle, producing duplicate writes to the time-series database and inflating CPU usage. The fix attaches a generation counter to every scheduling chain. When a chain restarts (via enable, configuration change, or service reload), older generations are detected and cancelled instead of being allowed to run alongside the new chain. Affects both the data collector (device polling) and the predict engine (model execution). No user action required after upgrade. --- #### Service manifest Only two services advanced between v1.0.0 and v1.0.1. All other services are byte-identical to the v1.0.0 build. | Service | Change | |---|---| | Data collector | Scheduler-dedup fix | | Predict engine | Scheduler-dedup fix | | _All others_ | Unchanged | ### v1.0.2 `May 20, 2026` Patch release fixing model-history gaps for in-memory inputs, hardening model upload validation, and tightening up a handful of UI rough edges. > [!TIP] Drop-in upgrade > v1.0.2 is fully compatible with v1.0.0 and v1.0.1: no service file changes, no migrations beyond the standard startup checks. Pull the new image and restart. See [Updating Koios](https://ai-ops.com/docs/updates/general.md). --- #### Fixed ##### Model-history gaps for in-memory inputs AI models with inputs sourced from in-memory tags (e.g. component outputs, expression results) were not writing entries to the per-model history bucket. Long-term history was unaffected. The gap only existed in the model-bucket history that powers per-model prediction views. The expression evaluator now writes per-model `ai_history` entries for in-memory tag inputs the same way it always did for device-sourced inputs. A periodic safety net also catches any AI-binding-changed events that the pub/sub channel missed (e.g. during evaluator restart), so configuration changes always settle within one refresh cycle. ##### Predict engine bucket creation no longer fails after a restore After restoring a backup, the predict engine could fail to start models whose time-series database buckets already existed, logging `bucket with name model__predictions already exists` and refusing to run. Bucket creation is now idempotent: if the bucket is already present, the predict engine adopts it instead of erroring. ##### Model upload rejects incompatible ONNX files at upload time ONNX files whose IR version exceeds what the platform's ONNX runtime can load (e.g. files produced by `onnx>=1.21` defaulting to IR 13 when the runtime caps at IR 11) are now rejected at the upload step with a clear message. Previously these files uploaded successfully but failed later in the predict engine with `Failed to load interpreter`. ##### UI polish - **Component library tray**: long component names no longer cause horizontal overflow in the canvas side drawer. - **Binding rows**: bindings sourced from in-memory tags now correctly display "In Memory" instead of being mislabeled as "Expression". - **Bulk export**: exporting all tags from the tag table no longer fails when no filters are applied. --- #### Changed ##### Model upload now uses the official `koios-model-utils` parser The webapp's ONNX metadata extraction now consumes the canonical `koios-model-utils` library (the same library data scientists use to embed metadata into their models) instead of a hand-rolled parser. This eliminates a class of subtle wire-format drift bugs and lets the library's strict validators catch malformed metadata at upload instead of letting it produce blank rows or silent misconfiguration later. No user-facing behavior change for correctly-formed models. --- #### Service manifest | Service | Change | |---|---| | Webapp | Model-utils consumer, idempotent bucket setup, upload-time runtime gate | | UI | Library overflow, IN_MEMORY binding label, bulk export fix | | Expression evaluator | In-memory model-history writes + periodic binding refresh | | Component builder | Relicense to Apache 2.0 (no behavior change) | | _All others_ | Unchanged from v1.0.1 | --- Source: https://ai-ops.com/docs/admin-console/introduction Section: Admin Console # Admin Console The **Koios Admin Console** is a lightweight, on-prem web app for managing many Koios instances from one place. Instead of logging into each box individually, you get a single fleet view of service health and failures, plus license state and remote `.lic` upload for every instance you register. It ships as its own small Docker image (`aiopinc/koios-admin`), separate from the main Koios container, and runs alongside your instances on the same network. ## What it gives you - **Fleet overview:** reachability, service state, active alarms, and failing devices, tags, models, and scan groups for every box, refreshed live. - **License management:** each instance's license state and days remaining, plus the ability to push a `.lic` file to a box remotely. - **One place to look:** a single sign-in and a single dashboard for as many Koios boxes as you run. ## How it works - **Backend proxy:** the browser never holds a box's credentials. Every call to an instance is proxied through the console's backend, which connects using a scoped, read-only access token minted on that box. - **Single poller:** one background process checks each registered instance on a tiered schedule and caches the results, so the dashboard stays fast and the boxes aren't hammered. - **Sealed credentials:** each instance's connection secret is encrypted under a master key kept on a dedicated volume, separate from the configuration data. The Admin Console is for fleet-level monitoring and licensing: connecting instances, watching health, and pushing licenses. To configure a specific box's devices, tags, or models, use that box's own Koios interface. The rest of this documentation covers the platform running on each instance. ## When to use it Reach for the Admin Console when you operate more than one or two Koios boxes and want a consolidated view of their health and licensing, for example across a site, a plant, or several customers. To run several boxes on one host, see [Running Multiple Instances](https://ai-ops.com/docs/installation/running-multiple-instances.md). ## What's next - [Installing the Admin Console](https://ai-ops.com/docs/admin-console/installation.md): pull the image and run it - [Running as a Service](https://ai-ops.com/docs/admin-console/running-as-a-service.md): start it automatically on boot - [Managing Instances](https://ai-ops.com/docs/admin-console/managing-instances.md): connect boxes and manage licenses --- Source: https://ai-ops.com/docs/admin-console/installation Section: Admin Console # Installing the Admin Console The Admin Console runs as a single Docker container. Docker Engine must be installed first. See [Installing Docker Engine](https://ai-ops.com/docs/installation/installing-docker.md) if you haven't done this yet. ## Run the Container Start the console with a single command: ```bash docker run -d --name koios-admin \ -p 443:443 -p 80:80 \ -v koios_admin_data:/var/lib/koios-admin \ -v koios_admin_secrets:/var/lib/koios-admin-secrets \ -e ENABLE_TLS=true \ aiopinc/koios-admin:latest ``` This pulls the image, creates the two data volumes if they don't exist, and serves the console over HTTPS on port 443 (plain HTTP on port 80 redirects to it). Using `:latest` is convenient for evaluation; for production, pin a specific version tag such as `aiopinc/koios-admin:1.0.0` so upgrades are intentional. ## First Access Open a browser and navigate to the host: ```text https:// ``` Your browser will show a warning for the self-signed certificate generated on first boot. This is expected. Accept it to proceed, then log in with the default credentials: - **Username:** `admin` - **Password:** `koios` > [!CAUTION] Change the default password > You are prompted to set a new password on first login. Do this immediately. ## Data Volumes The console stores everything in two named volumes that persist independently of the container: | Volume | Contents | |--------|----------| | `koios_admin_data` | Configuration database and TLS certificate | | `koios_admin_secrets` | Master encryption key | Docker creates them automatically on first start. > [!WARNING] The secrets volume must persist > The `koios_admin_secrets` volume holds the master key that seals every registered instance's connection credentials. If it is lost or recreated, the console can no longer decrypt those credentials and each instance must be reconnected. Always keep this volume, and include it in your backups. ## What's next - [Running as a Service](https://ai-ops.com/docs/admin-console/running-as-a-service.md): start the console automatically on boot - [Managing Instances](https://ai-ops.com/docs/admin-console/managing-instances.md): connect your first Koios box --- Source: https://ai-ops.com/docs/admin-console/running-as-a-service Section: Admin Console # Running as a Service For production, run the Admin Console as a systemd service so it starts automatically on boot and restarts on failure. ## Create the Service File Create the unit file: ```bash sudo nano /etc/systemd/system/docker.koios-admin.service ``` Paste the following: ```ini [Unit] Description=Koios Admin Console After=docker.service network-online.target Requires=docker.service Wants=network-online.target [Service] Restart=always RestartSec=5 ExecStartPre=-/usr/bin/docker rm -f koios-admin ExecStart=/usr/bin/docker run --rm --name koios-admin \ -p 443:443 -p 80:80 \ -v koios_admin_data:/var/lib/koios-admin \ -v koios_admin_secrets:/var/lib/koios-admin-secrets \ -e ENABLE_TLS=true \ aiopinc/koios-admin:latest ExecStop=/usr/bin/docker stop koios-admin [Install] WantedBy=multi-user.target ``` For production, replace `:latest` with a specific version tag so upgrades are intentional. ## Enable and Start ```bash sudo systemctl daemon-reload sudo systemctl enable docker.koios-admin.service sudo systemctl start docker.koios-admin.service ``` `Restart=always` ensures the container comes back automatically if it exits or the host reboots. ## Check Status and Logs ```bash sudo systemctl status docker.koios-admin.service ``` The console's application logs are written inside the container. Follow them with: ```bash docker logs -f koios-admin ``` Press `Ctrl+C` to stop following. ## Behind a Reverse Proxy To serve the console under a sub-path of an existing reverse proxy, such as a `/wfwd/koios-admin/` junction, set `KOIOS_ADMIN_BASE_PATH`. Add an `Environment=` line and pass it through in `ExecStart`: ```ini Environment=KOIOS_ADMIN_BASE_PATH=/wfwd/koios-admin/ ``` ```bash -e KOIOS_ADMIN_BASE_PATH=${KOIOS_ADMIN_BASE_PATH} \ ``` > [!WARNING] The proxy must strip the prefix > The console's web server always serves at the root, so the reverse proxy is expected to strip the sub-path prefix before forwarding requests. Leave `KOIOS_ADMIN_BASE_PATH` unset (the default) to serve at the root. ## Updating To move to a newer version, pull the image and restart the service: ```bash docker pull aiopinc/koios-admin:latest sudo systemctl restart docker.koios-admin.service ``` Your data and encryption key persist in the two volumes across the update. ## What's next - [Managing Instances](https://ai-ops.com/docs/admin-console/managing-instances.md): connect boxes and manage licenses --- Source: https://ai-ops.com/docs/admin-console/managing-instances Section: Admin Console # Managing Instances Once the console is running, you connect your Koios boxes to it and monitor them from the fleet dashboard. ## Connect an Instance From the **Instances** page, choose **Connect a Koios** and provide the box's address and an administrator login for it. The console then: 1. Connects to the box and pins its certificate. 2. Mints a scoped, read-only access token on the box for ongoing polling. 3. Seals that token under the master key and begins tracking the instance. The credentials step also has an **Allow remote license upload** switch, on by default. Leave it on to push `.lic` files to the box from the console later. Turn it off to keep the instance status-only, in which case the later license push is unavailable. The box appears in the fleet within a few seconds. You can optionally assign it to a **group** to organize instances by site, customer, or role. If several boxes run on the same host, see [Running Multiple Instances](https://ai-ops.com/docs/installation/running-multiple-instances.md) for how to set them up on distinct ports. > [!NOTE] Read-only by default > Registered instances are monitored read-only. Actions that change a box, such as pushing a license, are only available when that box has been opted into remote license upload. ## The Fleet Dashboard The Instances page lists every registered box with its live status: - **Status:** reachability refined by health. A box reads as one of *Online*, *Degraded* (a service down, an alarm firing, or failing devices/tags/models), *Unreachable*, *Auth failed*, or *Version unsupported* (the box version is outside the supported range). - **Version**, **License**, and **Last seen**. The summary tiles across the top (Total, Online, Degraded, Offline, License issues) double as filters, so selecting one narrows the list, and the search box filters by name or host. The whole view refreshes automatically. ## Inspect an Instance Select a row to open its detail page, which shows: - **Services:** each Koios service and whether it is running, stopped, or failed. - **Alarms and failures:** active CPU, RAM, storage, or network alarms, and counts of failing devices, tags, models, and scan groups. - **License:** state, days remaining, and the licensed hardware. ## Manage Licenses For any instance whose license you can see, the detail page shows its current state and days remaining. Where a box is opted into remote upload, you can push a new `.lic` file to it directly from the console: select the license upload control on the instance's detail page and choose the file. The box applies it without needing a separate sign-in. The **License issues** filter on the Instances page surfaces every box whose license is expired, in a grace period, expiring soon, or invalid, which is a quick way to catch renewals before they lapse. ## What's next The console manages boxes running the full Koios platform. To work inside an instance, see: - [Licensing Koios](https://ai-ops.com/docs/installation/licensing.md) for the on-box license activation flow behind the remote push. - [Getting Started](https://ai-ops.com/docs/getting-started/introduction.md) for the platform each instance runs.