Skip to content
GitHub

Integrations

An integration is how you point HotLoop at a kind of device you know the address of, answer a few questions, see what is actually on it, and keep the points you want. It makes the device and its tags. Entities follow from the tags the way they do for every tag, so the new points are on the entity API, in automations and on dashboards a minute later.

There are three ways a device gets into HotLoop, and they are meant to sit side by side:

Details Who starts it What it needs
MQTT discovery The device, by announcing itself on a broker A publisher that speaks one of the formats
Network discovery The network, by being listened to Nothing from the device; it tells you what it heard and how HotLoop could talk to it
Integrations (this page) You, with an address A device that answers its own protocol

An integration never writes to the device, and nothing it makes is armed. A point that was found is a point nobody has yet decided may be commanded, so every tag a setup creates is read-only until someone arms it, one at a time, in the tag editor, the same as a tag from any other source.

Integration Protocol Verified against
OPC UA server (opcua) OPC UA Microsoft’s opc-plc 2.12.48
SNMP device (snmp) SNMP net-snmp’s snmpd 5.9.4, v1, v2c and v3
BACnet/IP device (bacnet) BACnet/IP bacpypes3 0.0.110, an independent BACnet stack
CODESYS PLC (codesys) CODESYS CODESYS Control for Linux SL 4.22.0.0, running HotLoop’s lab program and a second, much larger program

More are added on this framework as they can be proven against a real server.

An integration brings a device in. To send HotLoop’s readings and events out to a Kafka broker, see the Kafka API event stream under historian targets: Apache Kafka and Redpanda, TLS and SASL, readings on one topic and the system log on another. To send them as OPC UA PubSub (UADP over UDP), or to read a publisher’s, see OPC UA PubSub: reading one is a device with the protocol opcua-pubsub, with no setup flow, since a datagram carries field positions and no names.

For a switch, a UPS, a PDU, a power meter, or anything running an SNMP agent. The questions follow the version: v2c asks for a community, v3 asks for a user and only the passphrases its security level needs. There is no default community.

The probe walks the system group, the interface tables, host resources, the load table and net-snmp’s extend outputs, the objects HotLoop can name, and shows each with what the agent said it holds right now. It suggests the ones a person pointing at a new device wants: the device’s name, location and uptime (shown in seconds, not the agent’s hundredths), each interface’s operational state and error counts, its byte counters (the 64 bit ones where the agent has them), the load averages, and any extend rows. It says in its notes how many suggested points are counters, because a counter on a chart wants a rate.

Anything else the agent has is still readable: set it up by hand as a tag whose address is the OID. See the SNMP driver for what a tag becomes, what a missing object does, and why a wrong v2c community looks like a dead device.

SNMP is read-only here, always. HotLoop does not send SET.

For a building automation controller, a meter, a thermostat: anything on the IP network that speaks BACnet. The questions are the device’s address, the device instance if you know it (and then HotLoop refuses a different device answering at that address), and which network card to send from if the machine has two.

The probe asks the device who it is, reads its object list, and reads every analog, binary and multi-state object it finds (and the integer, large analog, accumulator and character string values): name, description, units, present value and status flags. It shows each with what it read right now, and suggests the first hundred. Units come across as a label and, where they mean one, a device class, so a degrees-celsius input is a °C temperature.

It says in its notes how many objects report a fault (they read bad until the device clears it) and how many are out of service (they read uncertain, because the value is what was written to them). A multi-state object’s description lists its states, and its sample shows the state as well as the number.

BACnet is read-only here, always. HotLoop does not write a property, and does not reach a device behind a BACnet router: see the BACnet/IP driver for what is and isn’t covered.

For a PLC that runs a CODESYS Control runtime. The questions are the OPC UA ones (address, security, a user name and password if the PLC’s user management is on) and, only if you need them, the part of the application to list, the PLC and application names, and how many elements of an array to list.

The probe connects to the runtime’s OPC UA server, finds the PLC and its application, and lists the variables the application exports (its Symbol Configuration) by the names the programmer wrote, with their types and whether each can be written. It suggests the application’s own variables, not the elements of its buffers, and says in its notes how many arrays it listed in part. A PLC with nothing exported is told how to export something.

Set up with "dashboard": true in the request and the points you keep also get a dashboard named for the device: a heading, a trend of the numbers that move, the device’s alarms, and a value card for each point under a heading for its variable list. It is a first screen made from the program as it is, and it is edited like any dashboard. Nothing on it commands anything, and every tag is still read-only until armed.

A PLC with a restarting runtime or a new program downloaded is picked up again by itself: see the CODESYS driver.

Three calls, in order, and the first two save nothing.

  1. Ask. GET /api/integrations lists every integration and its questions. Each question has a kind (text, number, bool, choice or secret), a default, whether it is required, and, when it only matters after another answer, showWhen. A screen is drawn from that and nothing else, which is why a new integration needs no new screen.
  2. Look. POST /api/integrations/{id}/probe takes the answers, checks them, connects to the real device with the integration’s own driver, and reports what it is and what it has: a suggested name, what it says about itself, notes worth reading, and every point it found as a tag-shaped record with a sample of what it read, so you can compare it with the number on the machine’s own display.
  3. Keep. POST /api/integrations/{id}/setup takes the same answers and the names of the points to keep (none named keeps the ones marked suggested), creates the device and its tags and reloads the runtime. The device is enabled and polling. An integration that can lay out a first dashboard (CODESYS) does when the request has "dashboard": true, and answers with the dashboard’s id.

Setup looks at the device again instead of trusting the probe. A client’s idea of what it found a minute ago is a claim, and the points are checked against the device as it is when the device is made. A name that isn’t on it is a 400, not a point skipped, because somebody asked for it by name.

A setup that fails part way (the device saved, the tags didn’t) removes the device it just made. A device that already exists is refused with a 400 rather than overwritten: to add points to a device you have, use its Browse and Import.

Answers are checked before anything is tried

Section titled “Answers are checked before anything is tried”

The framework checks every answer against its question before an integration sees it, and reports every problem at once, so a form is fixed once:

  • a required question that is blank is “X is required”;
  • a number must be a whole number inside the question’s range, a choice must be one of its choices, a bool must be a bool;
  • an answer to a question the integration doesn’t ask is refused, not ignored, because a misspelled pasword dropped without a word is a device that fails to log in with no hint why;
  • a secret may not be the [redacted] placeholder the API shows in place of a stored one. Sending it back would store the placeholder as the password;
  • a question that isn’t showing (showWhen) is ignored, and isn’t required.

Credentials are held the way a device’s are: sealed at rest when HotLoop has a sealing key, and hidden from every API response and every error. A probe never saves what it was given.

502, with what went wrong: “could not reach the device: …” when nothing connected, “connected, but could not list its points: …” when it did and then didn’t answer. That is the device’s answer to read, not a fault in HotLoop and not a bad request. A closed port, a wrong community or a firewall all end up here, and the message is the driver’s own.

Probe and setup reach across the network from the HotLoop box, so both need devices.write, the same as saving a device. Listing needs devices.read. Every product carries them. The routes are in API.md.

An integration is a Go type in internal/integration with three methods and a Register call in its init:

  • Info() says what it is: id, name, the driver’s protocol, how to ask for the address, and the questions;
  • Configure() turns checked answers into an address and the driver’s own configuration block, and refuses what a question can’t express;
  • Discover() reaches the real device and reports what is on it.

The framework refuses, at start, an integration that can’t be a catalog entry: a duplicate id, a protocol the model doesn’t declare, a question with no label, a choice with no choices, a default that isn’t a valid answer, or a showWhen that names a question that isn’t there. A test also holds every integration to a protocol with a driver compiled in.

An integration doesn’t get merged until a test has had it talk to a real server for that protocol, running in the test lab (test/services/up.sh). Where there is no real server to run, there is no integration, and the roadmap says which ones are waiting on hardware.