Connect a device or system
Every machine has its own username and password, issued by your Kealink administrator. A machine can send readings over MQTT, which suits gateways and PLCs that stay connected, or over HTTP, which suits devices that wake up and post. Other software can read data back with an API key.
The easiest way: the Kealink node for Node-RED
If the gateway runs Node-RED, install the Kealink node and wire your values into it. It needs only the machine's id and password: no topic, no broker settings and no payload format. In the Node-RED user directory, usually ~/.node-red, run:
npm install https://app.kaynannexus.co.nz/downloads/node-red-contrib-kealink-0.4.0.tgz
- Restart Node-RED. The kealink node appears under network, with an example flow under Import, Examples.
- Feed it either
{"spindle_temp": 41.2, "running": true}, or one tag per message with the tag name inmsg.topic, as most PLC nodes send. Tag names become keys (Temp 1becomestemp_1). - By default it sends the latest value of each tag every 30 seconds; it can also send every message as it arrives.
- If Kealink cannot be reached it holds readings, with their times, for up to 24 hours, through a restart or a power cut, and sends them when it is back.
- The status under the node says whether it is connected, when it last sent, or that the password was refused.
Needs Node-RED 3 or later and Node.js 18 or later. The sections below are for any other gateway, PLC or software.
1. Send readings over MQTT
- Server
- mqtt.kealink.co.nz
- Port
- 50607, TLS on. A standard Let's Encrypt certificate: no CA file needed.
- WebSockets (optional)
- wss://ws.kealink.co.nz on port 443
- Username and client ID
- the machine id
- Password
- the machine's password
- Topic
- kealink/<machine-id>/data
- QoS
- 1, retain off, clean session, keepalive 60 s
Payload
One JSON object per message, usually every 30 seconds. Keys are the reading keys set up for the machine; values are numbers, except for a reading whose kind is Text, which takes text such as the program or tool loaded (up to 200 characters).
{"ts": 1790000000000, "spindle_temp": 41.2, "hydraulic_pressure": 118.5, "running": 1}tsis optional: Unix time in milliseconds. Without it, arrival time is used. A time more than 24 hours old or 5 minutes ahead is replaced by arrival time.- Keys are matched without regard to case, so a PLC tag named
Temp1orOIL_Pneeds no renaming in your flow. Keys that match no reading are not stored; they are listed back to you over HTTP, and shown on the machine's setup page with a button to add each one. true and false are stored as 1 and 0. - Readings may also be nested under
values, as some gateways send them:{"ts": 1790000000000, "values": {"spindle_temp": 41.2}}. - To send buffered readings after a connection drop, send an array of up to 200 such objects, each with its own ts.
- Up to 16 KB per message. A burst of up to 120 messages is accepted, then about one a second.
- A machine can only publish to its own topic.
Test from a terminal
mosquitto_pub -h mqtt.kealink.co.nz -p 50607 --capath /etc/ssl/certs -q 1 \
-i <machine-id> -u <machine-id> -P '<password>' \
-t kealink/<machine-id>/data -m '{"spindle_temp": 40.1}'Node-RED without the Kealink node
Use an mqtt out node with the server and port above, Use TLS ticked with the default TLS configuration, and the username and password on the Security tab. Build the payload in a function node:
msg.topic = "kealink/<machine-id>/data";
msg.payload = { ts: Date.now(), spindle_temp: global.get("spindle_temp") };
return msg;2. Send readings over HTTP
The same payload, posted with HTTP Basic authentication. The username is the machine id itself, the long string that also appears in the address, and the password is the machine's MQTT password. The reply says what was accepted.
curl -u '<machine-id>:<password>' -H 'content-type: application/json' \
-d '{"spindle_temp": 40.1, "running": true}' \
https://app.kaynannexus.co.nz/api/v1/machines/<machine-id>/dataNode-RED over HTTP
Three nodes: inject, then a function that builds the payload, then http request. Put a debug node on the output to read the reply, which is where the server says what it accepted.
The http request node carries no data of its own. Set it to POST, put the address above in the URL, tick Use authentication and choose basic, with the machine id as the username and its password, and set Return to a parsed JSON object. The body it sends is whatever msg.payload holds, which the function node builds:
msg.payload = {
ts: Date.now(),
spindle_temp: 40.1,
running: true
};
return msg;Send the keys your flow already produces. Anything matching no reading comes back in unknownKeys, with a hint where the server can work out what was meant, so one message is usually enough to settle the names.
- 202
- Accepted. Body: {"accepted": 2, "unknownKeys": [], "nonNumericKeys": [], "duplicateKeys": [], "timestampsReplaced": 0}. unknownKeys lists anything that matched no reading, which is the quickest way to see what your flow actually sends.
- 400
- The body is not valid JSON, or is not an object or an array of objects
- 401
- Wrong username or password. The reply says which of the two, and what the username should be
- 413
- Larger than 16 KB
- 422
- None of the keys are points of this machine; the reply lists them
- 503
- Temporarily unable to accept; retry after a few seconds
3. Read data with the API
Ask your Kealink administrator for an API key. It reads one company's machines and cannot send data. Send it on every request:
Authorization: Bearer kl_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- GET /api/v1/machines
- Every machine with its status, points, limits and each point's latest reading
- GET /api/v1/machines/{id}/readings
- ?point=<key>&from=<ISO time>&to=<ISO time>&resolution=raw|hour|day. Raw covers up to 31 days per request, hour and day up to 400. Hourly and daily rows include min, max and count.
- GET /api/v1/alerts
- Alerts, active first. Add ?open=true for active ones only.
curl -H 'Authorization: Bearer <api key>' \ 'https://app.kaynannexus.co.nz/api/v1/machines/<machine-id>/readings?point=spindle_temp&resolution=hour&from=2026-09-01T00:00:00Z'
Times are UTC in ISO 8601. Responses are JSON. Up to 50,000 rows per request; a larger range says truncated: true.