web
You’re offline. This is a read only version of the page.
close
Support Portal

WebSocket Event API (/apievents)

Subscribe to real-time push events from the device over a persistent WebSocket connection instead of polling the REST API.
Related Products
picoScan100

Table of Contents

Firmware Requires picoScan100 firmware V2.3.0 or later. Always use the latest available firmware.
OpenAPI Full endpoint reference and subscribable event list are in the OpenAPI specification.
Overview

1 - Overview

The device exposes a WebSocket server on port 80 that lets a client subscribe to state changes in real time. Instead of polling the REST interface, the client opens one persistent connection, registers the events it cares about, and the device pushes a JSON frame on every change.

Relationship to the REST API: Every WebSocket event has a matching REST endpoint of the same name. For example, the DeviceStatus event corresponds to GET /api/DeviceStatus. The payload in the WebSocket data field is identical to the data field in the corresponding REST response. Refer to the OpenAPI specification for full data schemas.

Push vs. poll: Use WebSocket subscriptions when you need low-latency notification of state changes, such as field evaluation results, I/O port switching, or temperature alarms. Use the REST interface for one-shot reads or configuration writes.


Connection

2 - Endpoint and Connection

Connect to:

ws://<device-ip>/apievents

Port 80. No authentication is required to open the connection. The device does not require periodic ping/keep-alive frames.

WebSocket compression - permessage-deflate required The device sends frames with the permessage-deflate extension (RSV1 = 1). Your WebSocket library must negotiate this extension during the handshake. Without it the device closes the connection with protocol error 1002.

The following are illustrative examples only; many other WebSocket libraries exist with varying compression support:

Library (example) Behaviour
C++ httplib::WebSocketClient Negotiates permessage-deflate automatically - works out of the box
Python websocket-client (WebSocketApp) Does not negotiate permessage-deflate by default - connection closes with protocol error 1002. Use a library that auto-negotiates, or enable compression explicitly.

Protocol

3 - Message Format

All messages are JSON text frames. Five message types are used:

3.1  Register - client → device

Send one registration message per event after the connection is open. The clientId is a caller-chosen integer echoed back in every device response for that registration.

{
  "type":     "register",
  "event":    "temperatureAlarmStatus",
  "clientId": 1
}
Field Type Description
type string Always "register"
event string Exact event name - case-sensitive
clientId integer Caller-chosen correlation ID, unique per registration on this connection
options object Optional - see §6 (throttle and queue)

3.2  Registration confirmation - device → client

On a successful registration the device immediately sends the current value in data. A status of 0 means success. Dispatch this message to your event handler exactly as a live event push - it is the first data point.

{
  "type":     "register",
  "event":    "temperatureAlarmStatus",
  "clientId": 1,
  "status":   0,
  "data":     { "AlarmState": "NoAlarm" }
}

3.3  Event push - device → client

Whenever the subscribed value changes, the device sends:

{
  "type":     "event",
  "event":    "temperatureAlarmStatus",
  "clientId": 1,
  "status":   0,
  "data":     { "AlarmState": "OverTemp" }
}

The data schema is identical to the data field of the matching GET /api/<EventName> response. Refer to the OpenAPI specification for full schema definitions.

3.4  Error response - device → client

If the event name is unknown or not available on this firmware, the device sends a registration response with status != 0. The connection stays open and other registrations on the same connection are not affected.

{
  "type":     "register",
  "event":    "nonExistentEvent",
  "clientId": 2,
  "status":   1,
  "error":    "Failed to register event for this connection due to an internal error. Does the event exist?"
}

3.5  Deregister - client → device

To stop receiving an event, send:

{
  "type":     "deregister",
  "event":    "temperatureAlarmStatus",
  "clientId": 1
}

No response is sent on deregistration.


Walkthrough

4 - Step-by-Step

200 ms inter-registration delay - required Send registration messages one at a time with at least 200ms between consecutive frames. The device resets the connection if multiple registration frames arrive in a tight burst. This delay is only required during the initial registration sequence.
1
Open the WebSocket connection

Connect to ws://<device-ip>/apievents. Ensure your library negotiates permessage-deflate (see §2).

2
Register your events

Send one register message per event. Use a unique clientId for each. Leave at least 200ms between registrations.

{ "type": "register", "event": "DeviceStatus",          "clientId": 0 }  // wait 200 ms
{ "type": "register", "event": "FieldEvaluationResult", "clientId": 1 }  // wait 200 ms
{ "type": "register", "event": "temperatureAlarmStatus","clientId": 2 }  // ...
3
Receive the initial values

For each successful registration the device replies with "type":"register", "status":0, and the current value in "data". Dispatch this to your handler the same way as a live event - it is the first data point.

4
Handle incoming events

Keep reading from the connection. When a value changes, the device pushes a frame with "type":"event". Use the "event" field to identify the source and "data" for the new value.

5
Handle errors and reconnect

Log any registration error ("status" != 0) and continue - remaining registrations still work.


Implementation

5 - Dispatch Pattern

Incoming frames must be dispatched based on both type and status.

connection = websocket_connect("ws://<device-ip>/apievents")

// Register events one at a time with 200 ms gap
for each (clientId, eventName) in enumerate(events):
    connection.send({ "type": "register", "event": eventName, "clientId": clientId })
    sleep(200 ms)

// Receive loop
while connection is open:
    message = connection.receive()
    obj     = json_parse(message)

    type   = obj["type"]
    status = obj["status"]
    event  = obj["event"]

    if type == "event"  OR  (type == "register" AND status == 0):
        dispatch(event, obj["data"])      // live update OR initial value on registration

    elif type == "register" AND status != 0:
        log_error(event, obj["error"])    // registration rejected — other events unaffected

Advanced

6 - Advanced Options - Throttle and Queue

Pass an optional options object when registering to control delivery behaviour.

6.1  Throttle

Limits how frequently event messages are delivered. Excess events are dropped before entering the queue.

{
  "type":     "register",
  "event":    "LSPdatetime",
  "clientId": 7,
  "options": {
    "throttle": {
      "minOutputIntervalMs": 5000
    }
  }
}

6.2  Queue

Each registered event has its own per-event queue on the shared connection.

"options": {
  "queue": {
    "priority":      "HIGH",
    "maxSize":       10,
    "discardIfFull": "OLDEST"
  }
}
Field Values Default Description
priority HIGH, MID, LOW MID Processing priority relative to other events on this connection
maxSize integer 1 Maximum number of buffered events
discardIfFull OLDEST, NEWEST OLDEST Which event to drop when the queue is full

Throttle is applied before queuing: excess events are discarded and never enter the queue.


Reference

7 - Subscribable Events

Event names are case-sensitive. The full data schema for each event is defined in the OpenAPI specification under the corresponding GET endpoints.

Event name REST counterpart Typical trigger
ContaminationData GET /api/ContaminationData Lens contamination state changes per segment
ContaminationResult GET /api/ContaminationResult Evaluated contamination result changes
CurrentTempDev GET /api/CurrentTempDev Internal device temperature changes (°C)
DeviceStatus GET /api/DeviceStatus Device operation state changes
FieldEvaluationResult GET /api/FieldEvaluationResult Object enters or leaves a detection field
InputState GET /api/InputState Digital input state changes
LSPdatetime GET /api/LSPdatetime Fires every second (device clock tick)
OutputState GET /api/OutputState Digital output state changes
perpendicularDistanceResult GET /api/perpendicularDistanceResult Perpendicular distance measurement result
PortState GET /api/PortState I/O port switching state changes
temperatureAlarmStatus GET /api/temperatureAlarmStatus Temperature alarm threshold crossed
UpdateState GET /api/UpdateState Firmware update progress changes

Reliability

8 - Reconnect Strategy

The device may close the connection on network interruption or a firmware restart. There is no session state preserved across connections - all subscriptions must be re-registered after reconnection.


Troubleshooting

9 - Common Issues

Symptom Likely cause Fix
Connection refused Wrong IP or device not reachable Ping the device. Check firewall and network settings.
Connection resets after first registration Registration frames sent in a tight loop Add at least 200 ms between successive register messages.
Connection closes immediately (protocol error 1002) permessage-deflate not negotiated by the client library Use a library that negotiates permessage-deflate, or configure compression explicitly.
Registration error: event not found Wrong event name (case-sensitive) or feature absent on this firmware Check the exact event name from the table in §7. Confirm firmware version.
No events received after registration Value has not changed - events are change-driven Expected behaviour. The initial-value confirmation is sent immediately on registration regardless.
Application state stale at startup Dispatch filter only accepts type == "event" Also dispatch when type == "register" and status == 0 (see §5).
Connection drops frequently Read timeout too short Set the read timeout to at least 300 s. Events may be infrequent.
Tip - Wireshark To inspect raw WebSocket traffic, capture on the interface connected to the device and apply the display filter tcp.port == 80 && websocket.
Keywords:
WebSocket, apievents, event push, real-time, permessage-deflate, subscribe, event registration, scan events, encoder events, reconnect, REST alternative, async events