Normal Framework API Documentation (3.10.5-2)

Download OpenAPI specification:Download

ApplicationService

GetApplications

  • Lists all installed applications with their hooks, files, status, and configuration options. Filter by name to get a single application. Applications that fail to load are silently skipped.
query Parameters
name
string
pageSize
string
pageCount
string

Responses

Response samples

Content type
application/json
{
  • "applications": [
    ],
  • "totalCount": "string"
}

CreateApplication

  • Creates a new application sandbox. The ID is auto-generated by slugifying the name. Installation (git clone, npm install, layer creation) runs asynchronously in the background; poll GetApplications to check status. Returns ALREADY_EXISTS if the slugified name collides.
Request Body schema: application/json
object (normalgw.automation.v1.ApplicationAuth)
compatibilityDate
string
description
string
gitAuthToken
string
gitUrl
string
id
string
object (normalgw.hpl.v1.Layer)
minNfVersion
string
name
string

human name for the application

Array of objects (normalgw.platform.v1.ConfigurationOption)
runtime
integer <enum>

Responses

Request samples

Content type
application/json
{
  • "auth": {
    },
  • "compatibilityDate": "string",
  • "description": "string",
  • "gitAuthToken": "string",
  • "gitUrl": "string",
  • "id": "string",
  • "layer": {
    },
  • "minNfVersion": "string",
  • "name": "string",
  • "options": [
    ],
  • "runtime": 0
}

Response samples

Content type
application/json
{
  • "id": "string"
}

DeleteFile

  • Deletes a file from the application's app/ directory.
path Parameters
applicationId
required
string
query Parameters
path
string

Responses

Response samples

Content type
application/json
{ }

ReadFile

  • Reads a file from the application's app/ directory. The path is resolved safely to prevent directory traversal. Returns the full file contents and byte count.
path Parameters
applicationId
required
string
query Parameters
path
string
offset
string
count
string

Responses

Response samples

Content type
application/json
{
  • "data": "string",
  • "totalCount": "string"
}

WriteFile

  • Writes a file to the application's app/ directory, creating parent directories as needed. Overwrites any existing file at the path. The path is resolved safely to prevent directory traversal.
path Parameters
applicationId
required
string
query Parameters
path
string
Request Body schema: application/json
Schema not provided

Responses

Response samples

Content type
application/json
{ }

DeleteApplication

  • Deletes an application and all its hooks, source files, logs, and runtime state. This is irreversible.
path Parameters
applicationId
required
string

Responses

Response samples

Content type
application/json
{ }

InstallDependencies

  • Runs npm install inside the application's chroot environment to install package.json dependencies. The container must have network access to npm registries. Also re-validates and finalizes application configuration afterward.
path Parameters
applicationId
required
string

Responses

Response samples

Content type
application/json
{ }

GitCommit

  • Commits all changes in the application's working directory to its local git repository. Returns the new commit hash.
path Parameters
applicationId
required
string
Request Body schema: application/json
applicationId
string
author
string
email
string
message
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "author": "string",
  • "email": "string",
  • "message": "string"
}

Response samples

Content type
application/json
{
  • "commitHash": "string"
}

GitFetch

  • Fetches remote refs and objects from the application's configured git remote. Does not modify the working tree.
path Parameters
applicationId
required
string
Request Body schema: application/json
applicationId
string
gitAuthToken
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "gitAuthToken": "string"
}

Response samples

Content type
application/json
{ }

GitCheckout

  • Checks out an existing or new branch in the application's git repository.
path Parameters
applicationId
required
string
Request Body schema: application/json
applicationId
string
branch
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "branch": "string"
}

Response samples

Content type
application/json
{ }

GitStatus

  • Returns the current branch, commit hash, dirty flag, per-file status, and number of unpushed commits for the application's git repository.
path Parameters
applicationId
required
string

Responses

Response samples

Content type
application/json
{
  • "branch": "string",
  • "commit": "string",
  • "dirty": true,
  • "files": [
    ],
  • "pendingCommits": 0
}

UpdateHook

  • Creates or updates a hook definition. For new hooks, generates an ID from the name if not provided. For existing hooks, merges the provided fields using proto.Merge (but replaces points, labels, and schedule wholesale). Automatically restarts the hook after update.
path Parameters
applicationId
required
string
Request Body schema: application/json
object

if not blank, running the hook will create a command context with the following expiration duration. Each time the hook is run, the context will be extended by this amount.

entryPoint
string

the name of the file containing the hook definition

object (normalgw.automation.v1.RuntimeError)
id
string
object

timeout for calling StartHook. if the timeout expires before the hook run finishes, the runtime will be killed and restarted.

object

the results of the last time the hook was run.

mode
integer <enum>

run mode

name
string

name for what this does

Array of objects (normalgw.automation.v1.Label)
object

bindings to input points

requiredClasses
Array of strings
Array of objects (normalgw.automation.v1.Label)

maybe we can extract these from the source in some cases

object (normalgw.automation.v1.HookRuntimeConfiguration)
object

when to run the program. If set to nil, the hook will not run on a schedule.

status
integer <enum>

Responses

Request samples

Content type
application/json
{
  • "commandExpiration": {
    },
  • "entryPoint": "string",
  • "error": {
    },
  • "id": "string",
  • "invokeTimeout": {
    },
  • "lastRun": {
    },
  • "mode": 0,
  • "name": "string",
  • "optionalLabels": [
    ],
  • "points": {
    },
  • "requiredClasses": [
    ],
  • "requiredLabels": [
    ],
  • "runtimeConfig": {
    },
  • "schedule": {
    },
  • "status": 0
}

Response samples

Content type
application/json
{ }

DeleteHook

  • Deletes a hook definition, terminates its runtimes, removes Redis state, and deletes the hook file. Does not remove source code files from the application directory.
path Parameters
applicationId
required
string
hookId
required
string

Responses

Response samples

Content type
application/json
{ }

GetHook

  • Returns a single hook definition including its last run result, status, and error state.
path Parameters
applicationId
required
string
hookId
required
string

Responses

Response samples

Content type
application/json
{
  • "hook": {
    }
}

StartHook

  • Triggers a hook invocation and returns a PID for tracking. Optionally filters to specific groups. Runtime errors are returned in the reply (not as gRPC errors), so always check StartHookReply.error.
path Parameters
applicationId
required
string
hookId
required
string
query Parameters
groups
Array of strings

if present, only run these groups. If empty, runs all groups.

scheduledTime.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

scheduledTime.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

Request Body schema: application/json
key
string
value
string

Responses

Request samples

Content type
application/json
{
  • "key": "string",
  • "value": "string"
}

Response samples

Content type
application/json
{
  • "error": {
    },
  • "groups": [
    ],
  • "pid": "string"
}

GetHookData

  • Returns the hook's structural metadata: list of group names, per-group variable UUIDs, and global variable UUIDs. Does not return point metadata or values -- use GetHookPoints for that.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
hookId
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "hookId": "string"
}

Response samples

Content type
application/json
{
  • "globalVariables": [
    ],
  • "groupVariables": {
    },
  • "groups": [
    ]
}

EvaluateHookPoints

  • Dry-run evaluation of a PointSelector against the point database. Returns the resolved points and group assignments without modifying the hook. Useful for previewing how a query/grouping configuration would resolve before saving it via UpdateHook. Set include_metadata to get full point attributes.
path Parameters
applicationId
required
string
hookId
required
string
query Parameters
includeMetadata
boolean
Request Body schema: application/json
Array of objects (normalgw.hpl.v1.Annotation)

annotations to be added to the point query.

equipmentTypeId
string
Array of objects (normalgw.automation.v1.Variable)

program variables which are created once for the hook

groupFunction
string

alternatively, a JavaScript function which performs the grouping. the function must have the following prototype: function groupFn(attrs : Map<string, string>): string each distinct value the function returns will form a group

Array of objects (normalgw.automation.v1.Variable)

program variables which are created for each group

object

list of attribute names making up the group key

labelAttribute
string

name of the attribute containing point labels. points withough this attribute will be dropped

layer
string

layer to execute the query against

noPoints
boolean

indicates whether hook has points

object

query for input points

queryTemplate
string
siteRef
Array of strings
uuids
Array of strings

explicit list of point UUIDs (pin-points mode). when set, points are loaded by UUID instead of by query.

Responses

Request samples

Content type
application/json
{
  • "annotations": [
    ],
  • "equipmentTypeId": "string",
  • "globalVariables": [
    ],
  • "groupFunction": "string",
  • "groupVariables": [
    ],
  • "groups": {
    },
  • "labelAttribute": "string",
  • "layer": "string",
  • "noPoints": true,
  • "query": {
    },
  • "queryTemplate": "string",
  • "siteRef": [
    ],
  • "uuids": [
    ]
}

Response samples

Content type
application/json
{
  • "groups": [
    ],
  • "points": [
    ]
}

GetHookRunEvents

  • Returns structured events emitted by the hook during a specific run, identified by pid and optionally filtered by group.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
group
string
hookId
string
pid
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "group": "string",
  • "hookId": "string",
  • "pid": "string"
}

Response samples

Content type
application/json
{
  • "events": [
    ]
}

GetHookGlobalVariables

  • Returns global (non-grouped) variable points for a hook, loaded from the automation layer. Filter by labels to get specific variables. Supports pagination.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
hookId
string
labels
Array of strings
pageOffset
string
pageSize
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "hookId": "string",
  • "labels": [
    ],
  • "pageOffset": "string",
  • "pageSize": "string"
}

Response samples

Content type
application/json
{
  • "totalCount": "string",
  • "variables": [
    ]
}

GetHookGroupsStatus

  • Returns the last execution result for each group. If groups is empty in the request, returns status for all groups. Groups that have never executed will have executed=false.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
groups
Array of strings
hookId
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "groups": [
    ],
  • "hookId": "string"
}

Response samples

Content type
application/json
{
  • "results": {
    }
}

GetHookLogs

  • Server-streaming RPC that tails hook console logs (stdout/stderr) from a Redis stream. Sends LEVEL_KEEPALIVE messages every few seconds to detect disconnected clients. Pass version to resume from a specific position; omit to stream only new messages. Also accessible at /api/v1/apps/{application_id}/logs for application-level logs.
path Parameters
applicationId
required
string
hookId
required
string
query Parameters
version
string

Responses

Response samples

Content type
application/json
{
  • "level": 0,
  • "message": "string",
  • "ts": "2019-08-24T14:15:22Z",
  • "version": "string"
}

GetHookPoints

  • Returns the resolved input points for a hook, optionally filtered by group and an additional query. Points are loaded from the Point service with the hook's layer and annotations applied. Supports pagination.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
group
string
hookId
string
pageOffset
string
pageSize
string
object (normalgw.hpl.v1.Query)

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "group": "string",
  • "hookId": "string",
  • "pageOffset": "string",
  • "pageSize": "string",
  • "query": {
    }
}

Response samples

Content type
application/json
{
  • "points": [
    ],
  • "totalCount": "string",
  • "values": {
    }
}

ResetVariables

  • Resets hook variables back to their default_value. Specify global_variables and/or group_variables by label to reset selectively; if both are empty, resets all variables for the hook.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
globalVariables
Array of strings
groupVariables
Array of strings
hookId
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "globalVariables": [
    ],
  • "groupVariables": [
    ],
  • "hookId": "string"
}

Response samples

Content type
application/json
{ }

GetHookResults

  • Returns paginated per-group execution results (HookResult), which are finer-grained than runs. Filterable by state, time range, pid, and group.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
endTime
string <date-time>
group
string
hookId
string
pageOffset
string
pageSize
string
pid
string
startTime
string <date-time>
state
integer <enum>

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "endTime": "2019-08-24T14:15:22Z",
  • "group": "string",
  • "hookId": "string",
  • "pageOffset": "string",
  • "pageSize": "string",
  • "pid": "string",
  • "startTime": "2019-08-24T14:15:22Z",
  • "state": 0
}

Response samples

Content type
application/json
{
  • "results": [
    ],
  • "totalCount": "string"
}

StopHook

  • Stops a running hook invocation. If pid is empty, stops all scheduled/enqueued/running invocations for this hook. Marks affected runs and results as STATE_STOPPED in the database.
path Parameters
applicationId
required
string
hookId
required
string
query Parameters
pid
string

the PID of the hook to stop, if empty, all runs of the hook will be stopped.

Responses

Response samples

Content type
application/json
{ }

GetHookRuns

  • Returns paginated hook run history with filtering by state and time range. Set include_results to get per-group results, or include_logs to get in-flight events for running hooks.
path Parameters
applicationId
required
string

these are filters for finding hook runs

hookId
required
string
Request Body schema: application/json
applicationId
string

these are filters for finding hook runs

endTime
string <date-time>
hookId
string
includeLogs
boolean
includeResults
boolean
pageOffset
string
pageSize
string
startTime
string <date-time>
state
integer <enum>
states
Array of integers <enum> [ items <enum > ]

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "endTime": "2019-08-24T14:15:22Z",
  • "hookId": "string",
  • "includeLogs": true,
  • "includeResults": true,
  • "pageOffset": "string",
  • "pageSize": "string",
  • "startTime": "2019-08-24T14:15:22Z",
  • "state": 0,
  • "states": [
    ]
}

Response samples

Content type
application/json
{
  • "runs": [
    ],
  • "totalCount": "string"
}

GetRuntimesStatus

  • Returns detailed runtime diagnostics for a hook: per-runtime process metrics (state, PID, request counts, current request), scheduler status, queue depth, forwarder status, retry state, and when points were last updated.
path Parameters
applicationId
required
string
hookId
required
string
Request Body schema: application/json
applicationId
string
hookId
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "hookId": "string"
}

Response samples

Content type
application/json
{
  • "error": {
    },
  • "forwarder": {
    },
  • "pointsUpdatedTime": "2019-08-24T14:15:22Z",
  • "queue": {
    },
  • "retry": {
    },
  • "runtimes": [
    ],
  • "scheduler": {
    },
  • "status": 0,
  • "totalCount": "string",
  • "variablesForwarder": {
    }
}

GetHookLogs

  • Server-streaming RPC that tails hook console logs (stdout/stderr) from a Redis stream. Sends LEVEL_KEEPALIVE messages every few seconds to detect disconnected clients. Pass version to resume from a specific position; omit to stream only new messages. Also accessible at /api/v1/apps/{application_id}/logs for application-level logs.
path Parameters
applicationId
required
string
query Parameters
hookId
string
version
string

Responses

Response samples

Content type
application/json
{
  • "level": 0,
  • "message": "string",
  • "ts": "2019-08-24T14:15:22Z",
  • "version": "string"
}

RestartApplication

  • Restarts the application to pick up source code or configuration changes. If runtimes_only is true, only the runtime processes are restarted (faster); otherwise the full application reload runs including re-evaluating points and hooks.
path Parameters
applicationId
required
string
query Parameters
runtimesOnly
boolean

Responses

Response samples

Content type
application/json
{ }

GetApplicationTimeSeries

  • Returns time-series data of hook execution outcomes (success, error, stopped, aborted counts) stored in Redis TimeSeries. If hooks list is empty, returns data for all hooks in the application. Supports resampling via ResampleOptions.
path Parameters
applicationId
required
string
Request Body schema: application/json
applicationId
string
from
string <date-time>
hooks
Array of strings
object (normalgw.hpl.v1.ResampleOptions)
to
string <date-time>

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "from": "2019-08-24T14:15:22Z",
  • "hooks": [
    ],
  • "resample": {
    },
  • "to": "2019-08-24T14:15:22Z"
}

Response samples

Content type
application/json
{
  • "hooks": [
    ]
}

UpgradeApplication

  • Fetches from the remote and performs a hard reset to the remote branch HEAD -- any local uncommitted or unpushed changes will be lost. Then asynchronously re-installs dependencies, migrates layers, and reloads hooks.
path Parameters
applicationId
required
string
Request Body schema: application/json
applicationId
string
gitAuthToken
string

Responses

Request samples

Content type
application/json
{
  • "applicationId": "string",
  • "gitAuthToken": "string"
}

Response samples

Content type
application/json
{ }

UpdateApplication

  • Updates application settings using an update_mask to select which fields to change. Supports configuration values, git_url, layer, auth, options, and min_nf_version. Layer changes trigger an async migration. Configuration values are validated against the option definitions before saving.
path Parameters
id
required
string
Request Body schema: application/json
object (normalgw.automation.v1.ApplicationAuth)
object

these set configuration values to no-default

gitUrl
string
id
string
object (normalgw.hpl.v1.Layer)
minNfVersion
string
Array of objects (normalgw.platform.v1.ConfigurationOption)
updateMask
Array of strings

Responses

Request samples

Content type
application/json
{
  • "auth": {
    },
  • "configuration": {
    },
  • "gitUrl": "string",
  • "id": "string",
  • "layer": {
    },
  • "minNfVersion": "string",
  • "options": [
    ],
  • "updateMask": [
    ]
}

Response samples

Content type
application/json
{ }

GetApplications

  • Lists all installed applications with their hooks, files, status, and configuration options. Filter by name to get a single application. Applications that fail to load are silently skipped.
path Parameters
name
required
string
query Parameters
pageSize
string
pageCount
string

Responses

Response samples

Content type
application/json
{
  • "applications": [
    ],
  • "totalCount": "string"
}

AuthService

DeleteApplication

  • Deletes an API application by client_id. Returns NotFound if the application does not exist.
query Parameters
clientId
string

Responses

Response samples

Content type
application/json
{ }

GetApplications

  • Lists all registered API applications. The hashed_client_secret field is cleared in the response for security.

Responses

Response samples

Content type
application/json
{
  • "applications": [
    ]
}

CreateApplication

  • Creates an API application with a generated client_id and client_secret. Requires at least one valid scope. The client_secret is returned only once; it is stored as a bcrypt hash.
Request Body schema: application/json
isInternal
boolean
name
string
scopes
Array of strings

Responses

Request samples

Content type
application/json
{
  • "isInternal": true,
  • "name": "string",
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "clientId": "string",
  • "clientSecret": "string"
}

RegenerateApplicationSecret

  • Generates a new client_secret for an existing application, invalidating the old one. Returns the new plaintext secret (only returned once).
query Parameters
clientId
string

Responses

Response samples

Content type
application/json
{
  • "clientSecret": "string"
}

GetScopes

  • Returns the hardcoded list of available API scopes (e.g. normalgw.hpl.v1.readonly). Each scope includes a read_only flag.

Responses

Response samples

Content type
application/json
{
  • "scopes": [
    ]
}

IssueToken

  • Issues a JWT access token using client_credentials grant. Accepts application/x-www-form-urlencoded or application/json via raw_body. Requires TOKEN_SIGNING_SECRET to be configured. Does not require auth (validates client_id/client_secret itself).
query Parameters
grantType
string
clientId
string
clientSecret
string
Request Body schema: application/json
string

Responses

Request samples

Content type
application/json
"string"

Response samples

Content type
application/json
{
  • "access_token": "string",
  • "expires_in": "string",
  • "token_type": "string"
}

BACnet

The BACnet V2 service provides full access to the BACnet confirmed-service application layer. All services defined in BACnet-2020 are supported, and are compiled directly from the specification, including types for standard objects and enumerations. This allows the sophisticated user to interact with nearly any standards compliant BACnet device using the ConfirmedService endpoint.

GetAlarms

  • Query persisted alarm notifications from Redis with time-range filtering, server-side filters (device/event-type/notify-type/state/priority), and cursor-based pagination. Results are returned in reverse chronological order. Defaults to 100 results per page.
Request Body schema: application/json
deviceInstances
Array of integers <uint32> [ items <uint32 > ]

Filters

eventTypes
Array of integers <enum> [ items <enum > ]
from
string <date-time>
limit
integer <int32>

Pagination

notifyTypes
Array of integers <enum> [ items <enum > ]
pageToken
string
priorityMax
integer <uint32>
priorityMin
integer <uint32>
to
string <date-time>
toStates
Array of integers <enum> [ items <enum > ]

Responses

Request samples

Content type
application/json
{
  • "deviceInstances": [
    ],
  • "eventTypes": [
    ],
  • "from": "2019-08-24T14:15:22Z",
  • "limit": 0,
  • "notifyTypes": [
    ],
  • "pageToken": "string",
  • "priorityMax": 0,
  • "priorityMin": 0,
  • "to": "2019-08-24T14:15:22Z",
  • "toStates": [
    ]
}

Response samples

Content type
application/json
{
  • "nextPageToken": "string",
  • "notifications": [
    ]
}

AcknowledgeAlarm

  • Acknowledge a gateway-persisted alarm notification in Redis. If send_to_device is true, also sends a BACnet AcknowledgeAlarm to the originating device asynchronously (fire-and-forget). Returns the updated alarm with ack state.
Request Body schema: application/json
acknowledgedBy
string
alarmId
string
sendToDevice
boolean

If true, also send BACnet AcknowledgeAlarm to the originating device

Responses

Request samples

Content type
application/json
{
  • "acknowledgedBy": "string",
  • "alarmId": "string",
  • "sendToDevice": true
}

Response samples

Content type
application/json
{
  • "notification": {
    }
}

ObserveAlarms

  • Server-streaming RPC that delivers alarm notifications from the gateway's WAL. Supports version-based resume for catching up after disconnects, optional wait for new entries, server-side filtering by device/event-type/notify-type/state/priority, and a limit on the number of entries returned.
query Parameters
version
string

WAL version token for resume. Empty string = from beginning, "$" = from latest.

limit
integer <int32>
wait
boolean
deviceInstances
Array of integers <uint32> [ items <uint32 > ]

Filters

eventTypes
Array of integers <enum> [ items <enum > ]
notifyTypes
Array of integers <enum> [ items <enum > ]
toStates
Array of integers <enum> [ items <enum > ]
priorityMin
integer <uint32>
priorityMax
integer <uint32>

Responses

Response samples

Content type
application/json
{
  • "notification": {
    },
  • "version": "string"
}

ConfirmedService

  • Send a confirmed service request to a remote BACnet device and wait for the reply. The reply oneof contains either a ComplexACK, SimpleACK, Error, Abort, or Reject. If the request is a ConfirmedEventNotification with no device_address, it is injected locally into the alarm subsystem and returns SimpleACK without hitting the network.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

object (normalgw.bacnet.v2.ConfirmedServiceRequest)

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "options": {
    },
  • "request": {
    }
}

Response samples

Content type
application/json
{
  • "SimpleAck": true,
  • "abort": 0,
  • "ack": {
    },
  • "error": {
    },
  • "reject": 0
}

GetDeviceAlarmSummary

  • Intended to send GetAlarmSummary to a remote device, but actually sends GetEventInformation due to the proto lacking support for parameterless services. The response ACK type won't match, so this always returns an empty summaries list. Use GetDeviceEventInformation instead.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "options": {
    }
}

Response samples

Content type
application/json
{
  • "summaries": [
    ]
}

GetDeviceEventInformation

  • Send GetEventInformation to a remote BACnet device and return all event summaries. Automatically paginates using more_events / last_received_object_identifier up to 100 pages. This is the working alternative to GetDeviceAlarmSummary.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "options": {
    }
}

Response samples

Content type
application/json
{
  • "eventSummaries": [
    ]
}

ListEventSubscriptions

  • List all managed event subscriptions from the local persistent store. Includes subscriptions in any state (ACTIVE, ERROR, etc.).

Responses

Response samples

Content type
application/json
{
  • "subscriptions": [
    ]
}

CreateEventSubscription

  • Subscribe the gateway to a remote device's notification class by writing to its recipient-list via AddListElement (with WriteProperty read-modify-write fallback). If the same device+NC already has a subscription, it is updated in place. On BACnet failure the subscription is persisted in ERROR state and the error is returned.
Request Body schema: application/json
confirmed
boolean
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v2.EventTransitionBits)
notificationClassInstance
integer <uint32>

Responses

Request samples

Content type
application/json
{
  • "confirmed": true,
  • "deviceAddress": {
    },
  • "eventTransitions": {
    },
  • "notificationClassInstance": 0
}

Response samples

Content type
application/json
{
  • "subscription": {
    }
}

BatchCreateEventSubscriptions

  • Create event subscriptions for multiple notification classes on the same device in one call. Each NC is subscribed independently; per-NC results (including errors) are returned in the reply. Subscriptions are persisted even on partial failure.
Request Body schema: application/json
confirmed
boolean
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v2.EventTransitionBits)
notificationClassInstances
Array of integers <uint32> [ items <uint32 > ]

Responses

Request samples

Content type
application/json
{
  • "confirmed": true,
  • "deviceAddress": {
    },
  • "eventTransitions": {
    },
  • "notificationClassInstances": [
    ]
}

Response samples

Content type
application/json
{
  • "results": [
    ]
}

DeleteEventSubscription

  • Delete a managed event subscription and remove the gateway from the remote device's NC recipient-list via RemoveListElement (with WriteProperty fallback). The local subscription is deleted even if the remote device is unreachable.
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{ }

GetNotificationClassInfo

  • Read notification class properties from a remote device, including recipient-list, monitored object references, priority, and device metadata (name, model, vendor). If no NC instances are specified, auto-discovers them from the device's object-list.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

notificationClassInstances
Array of integers <uint32> [ items <uint32 > ]

If empty, reads all NC objects from the device's object-list.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "notificationClassInstances": [
    ],
  • "options": {
    }
}

Response samples

Content type
application/json
{
  • "deviceInstance": 0,
  • "deviceModel": "string",
  • "deviceName": "string",
  • "deviceVendor": "string",
  • "notificationClasses": [
    ]
}

Snoop

  • Server-streaming RPC that delivers decoded BACnet PDUs seen on the network. Useful for protocol debugging. PDUs that fail to decode are silently dropped.

Responses

Response samples

Content type
application/json
{
  • "dst": {
    },
  • "pdu": {
    },
  • "src": {
    }
}

UnconfirmedHandler

  • Server-streaming RPC that delivers unconfirmed requests received by the gateway. The stream stays open until the client disconnects; each message contains the source device address and the unconfirmed service request PDU.

Responses

Response samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "request": {
    }
}

Bacnet

BACnet Service, version 1

The BACnet Service provides access to certain popular BACnet services at a low level of abstraction. However, unlike the BACnet V2 service, certain operations may be executed using equivalent operations in order to improve network performance. For instance, ReadProperty requests may be merged and executed using the ReadProperty-Multiple service if the underlying device support it.

AtomicReadFile

  • Reads a file from a remote BACnet device using AtomicReadFile, streaming back chunks of up to max_apdu size. Only stream access mode is supported. The client must concatenate the chunks in order to reconstruct the file.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

length
integer <uint32>

set to zero to read to the end of the file from the starting offset

object (normalgw.bacnet.v1.ObjectId)
offset
integer <uint32>

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "length": 0,
  • "objectId": {
    },
  • "offset": 0
}

Response samples

Content type
application/json
{
  • "data": "string",
  • "end": true,
  • "error": {
    }
}

ReadProperty

  • Reads a single property from a BACnet device. Internally converted to a v2 ConfirmedRequest; may be merged with other concurrent reads into a ReadPropertyMultiple if the device supports it. Supports priority-based scheduling and device-level locking via OperationOptions.
query Parameters
deviceAddress.mac
string <bytes>
deviceAddress.net
integer <uint32>
deviceAddress.adr
string <bytes>
deviceAddress.maxApdu
integer <uint32>
deviceAddress.deviceId
integer <uint32>

if this is null we will use the wildcard

deviceAddress.bbmd
string <bytes>
deviceAddress.portId
integer <uint32>

the id of the network port the device is on. 0 = the default port (usually BACnet/IP)

objectId.objectType
integer <enum>
objectId.instance
integer <uint32>
propertyId
integer <enum>

property name

arrayIndex
integer <uint32>

array index, or null if not included.

options.timeout.seconds
string

Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. Note: these bounds are computed from: 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

options.timeout.nanos
integer <int32>

Signed fractions of a second at nanosecond resolution of the span of time. Durations less than one second are represented with a 0 seconds field and a positive or negative nanos field. For durations of one second or more, a non-zero value for the nanos field must be of the same sign as the seconds field. Must be from -999,999,999 to +999,999,999 inclusive.

options.unmergeable
boolean

certain operations (reads) may be merged; set to false if you don't want this to happen.

options.priority
integer <int32>

priority level for scheduling. higher number is lower priority (like nice values)

options.continueOnError
boolean

if an operation has multiple components (like a ReadPropertyMultiple), wheather to return partial results and try on error.

options.blockLowerPriority
boolean

if true, cause other lower-priority operations to fail while this operation is being executed.

useFutureValues
boolean

Responses

Response samples

Content type
application/json
{
  • "error": {
    },
  • "futureValue": {
    },
  • "property": {
    },
  • "value": {
    }
}

ReadProperty

  • Reads a single property from a BACnet device. Internally converted to a v2 ConfirmedRequest; may be merged with other concurrent reads into a ReadPropertyMultiple if the device supports it. Supports priority-based scheduling and device-level locking via OperationOptions.
Request Body schema: application/json
arrayIndex
integer <uint32>

array index, or null if not included.

object

if device_address is null, we'll attempt to look it up using Who-Is.

object

object type and instance

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

propertyId
integer <enum>

property name

useFutureValues
boolean

Responses

Request samples

Content type
application/json
{
  • "arrayIndex": 0,
  • "deviceAddress": {
    },
  • "objectId": {
    },
  • "options": {
    },
  • "propertyId": 0,
  • "useFutureValues": true
}

Response samples

Content type
application/json
{
  • "error": {
    },
  • "futureValue": {
    },
  • "property": {
    },
  • "value": {
    }
}

ReadPropMultiple

  • Reads multiple properties from a single device. Requests are enqueued with priority-based scheduling and may be merged with other pending reads to the same device. Automatically splits large requests based on learned APDU limits and falls back to individual ReadProperty if the device rejects ReadPropertyMultiple.
query Parameters
deviceAddress.mac
string <bytes>
deviceAddress.net
integer <uint32>
deviceAddress.adr
string <bytes>
deviceAddress.maxApdu
integer <uint32>
deviceAddress.deviceId
integer <uint32>

if this is null we will use the wildcard

deviceAddress.bbmd
string <bytes>
deviceAddress.portId
integer <uint32>

the id of the network port the device is on. 0 = the default port (usually BACnet/IP)

options.timeout.seconds
string

Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. Note: these bounds are computed from: 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

options.timeout.nanos
integer <int32>

Signed fractions of a second at nanosecond resolution of the span of time. Durations less than one second are represented with a 0 seconds field and a positive or negative nanos field. For durations of one second or more, a non-zero value for the nanos field must be of the same sign as the seconds field. Must be from -999,999,999 to +999,999,999 inclusive.

options.unmergeable
boolean

certain operations (reads) may be merged; set to false if you don't want this to happen.

options.priority
integer <int32>

priority level for scheduling. higher number is lower priority (like nice values)

options.continueOnError
boolean

if an operation has multiple components (like a ReadPropertyMultiple), wheather to return partial results and try on error.

options.blockLowerPriority
boolean

if true, cause other lower-priority operations to fail while this operation is being executed.

useFutureValues
boolean

Responses

Response samples

Content type
application/json
{
  • "error": {
    },
  • "values": [
    ]
}

ReadPropMultiple

  • Reads multiple properties from a single device. Requests are enqueued with priority-based scheduling and may be merged with other pending reads to the same device. Automatically splits large requests based on learned APDU limits and falls back to individual ReadProperty if the device rejects ReadPropertyMultiple.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

Array of objects (normalgw.bacnet.v1.ObjectPropertyReference)

a list of object and property referneces we want to read. in the BACnet RPM spec these are nested; but we flatten them out for simplicity.

useFutureValues
boolean

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "options": {
    },
  • "readProperties": [
    ],
  • "useFutureValues": true
}

Response samples

Content type
application/json
{
  • "error": {
    },
  • "values": [
    ]
}

ReadRange

  • Performs a ReadRange request, typically against the Log_Buffer property of a Trend Log object. Only BY_POSITION and BY_SEQUENCE methods are supported; BY_DEFAULT reads from the beginning.
Request Body schema: application/json
arrayIndex
integer <uint32>
count
integer <int32>

number of entries to read

object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

method
integer <enum>
object (normalgw.bacnet.v1.ObjectId)
propertyId
integer <enum>
reference
integer <uint32>

either log position or sequence number, depending on method

Responses

Request samples

Content type
application/json
{
  • "arrayIndex": 0,
  • "count": 0,
  • "deviceAddress": {
    },
  • "method": 0,
  • "objectId": {
    },
  • "propertyId": 0,
  • "reference": 0
}

Response samples

Content type
application/json
{
  • "error": {
    },
  • "firstSequence": 0,
  • "itemCount": 0,
  • "records": [
    ]
}

WhoIs

  • Broadcasts a Who-Is request and streams back I-Am replies until the timeout expires. Listens on all unconfirmed request channels, so unsolicited I-Am messages from other Who-Is requests may also appear in the stream.
Request Body schema: application/json
highLimit
integer <uint32>
lowLimit
integer <uint32>
object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

Responses

Request samples

Content type
application/json
{
  • "highLimit": 0,
  • "lowLimit": 0,
  • "options": {
    },
  • "target": {
    }
}

Response samples

Content type
application/json
{
  • "deviceAddress": {
    }
}

WhoIsRouter

  • Sends a Who-Is-Router-To-Network request and streams replies until timeout. Currently a stub -- the implementation is commented out and returns immediately without sending any network messages.
Request Body schema: application/json
mac
string <bytes>

optional, MAC to send the request two. if not set, sent to broadcast

net
integer <uint32>

optional, DNET if set

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

Responses

Request samples

Content type
application/json
{
  • "mac": "string",
  • "net": 0,
  • "options": {
    }
}

Response samples

Content type
application/json
{
  • "mac": "string",
  • "nets": [
    ]
}

WriteProperty

  • Writes a single property value to a remote BACnet device. The value must match the expected BACnet type for the property or the device will reject it. Writes are concurrency-limited (default 3 in-flight) and support priority-based device locking.
Request Body schema: application/json
object (normalgw.bacnet.v1.DeviceAddress)

DeviceAddress. Specifies the full network address of a BACnet device.

object (normalgw.bacnet.v1.OperationOptions)

Options that apply to the handling of a request within the stack.

priority
integer <uint32>
object (normalgw.bacnet.v1.ObjectPropertyReference)

this references a property value within a a device within an object

object (normalgw.bacnet.v1.ApplicationDataValue)

A raw data value. Depending on the BACnet object, this might either be a scalar value, or an array. You

Responses

Request samples

Content type
application/json
{
  • "deviceAddress": {
    },
  • "options": {
    },
  • "priority": 0,
  • "property": {
    },
  • "value": {
    }
}

Response samples

Content type
application/json
{
  • "error": {
    }
}

CommandManager

The command service provides higher-level access to underlying device operations, including generic "Read" and "Write" operations. These operations encapsulate much of the device-specific code required in order to interact with field devices, such as retrieving BACnet network addresses from the Point service and submitting valid BACnet requests.

The command service also supports grouping multiple operations into command operations. Grouping operations allow Normal to perform expiration and reversion of write operations after a period of time, either by clearing an element in a priority array; or by writing back the original value.

GetCommands

  • Returns a paginated list of all active (non-expired) commands, sorted by ID. Includes each command's active and pending writes.
query Parameters
pageOffset
string
pageSize
string

Responses

Response samples

Content type
application/json
{
  • "commands": [
    ],
  • "totalCount": "string"
}

StartCommand

  • Creates a new command with a name and expiration. Returns the allocated command ID. The name must be unique among active commands (returns ALREADY_EXISTS otherwise). Expiration must be in the future and at most 24 hours out.
Request Body schema: application/json
object

alternatively, use a duration

expiresAt
string <date-time>

timestamp after which the writes should be undone

name
string

caller-provided name for the command. starting a command with an in-use name results in an error to provide a form of locking

Responses

Request samples

Content type
application/json
{
  • "duration": {
    },
  • "expiresAt": "2019-08-24T14:15:22Z",
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "expiresAt": "2019-08-24T14:15:22Z",
  • "id": "string"
}

GetGuardrails

  • Returns the write guardrail configuration. If client_id is provided, also returns client-specific guardrails. Returns FAILED_PRECONDITION if the guardrail system is disabled.
query Parameters
clientId
string

Responses

Response samples

Content type
application/json
{
  • "global": {
    },
  • "keySpecific": {
    }
}

SetGuardrails

  • Creates or replaces write guardrails. If client_id is empty, sets global guardrails; otherwise sets client-specific guardrails. Returns FAILED_PRECONDITION if the guardrail system is disabled.
Request Body schema: application/json
clientId
string
object (normalgw.hpl.v2.WriteGuardrailSet)

Top-level container stored on disk

Responses

Request samples

Content type
application/json
{
  • "clientId": "string",
  • "guardrails": {
    }
}

Response samples

Content type
application/json
{ }

DeleteGuardrail

  • Deletes a single guardrail by ID. If client_id is provided, deletes from that client's guardrails; otherwise deletes from global. Returns FAILED_PRECONDITION if the guardrail system is disabled.
path Parameters
id
required
string
query Parameters
clientId
string

Responses

Response samples

Content type
application/json
{ }

Read

  • Reads live values from underlying devices by resolving point references, grouping by HPL layer, and dispatching protocol-specific reads. A command_id is optional; if provided with cancel_on_error, the command is ended on any read failure. Does not require a running command.
Request Body schema: application/json
cancelOnError
boolean

cancel the underlying command if any reads fail

commandId
string

if not empty, the command ID. This is only used in the case that errors are encountered and cancel_on_error is true; in that case the command will be ended.

Array of objects (normalgw.hpl.v2.ReadCommand)

points to read

Responses

Request samples

Content type
application/json
{
  • "cancelOnError": true,
  • "commandId": "string",
  • "reads": [
    ]
}

Response samples

Content type
application/json
{
  • "errors": [
    ],
  • "results": [
    ]
}

ObserveRawCommandActions

  • Server-streaming RPC that tails the command audit log (backed by a WAL). Emits write, clear, extend, and completion events. Filterable by layer, uuid, or command_ids; set wait=true to block for new entries, or use limit to cap the number of returned events.
query Parameters
layer
string
uuid
string
version
string
limit
integer <uint32>
wait
boolean
commandIds
Array of strings

Responses

Response samples

Content type
application/json
{
  • "action": 0,
  • "attempt": 0,
  • "commandId": "string",
  • "error": {
    },
  • "point": {
    },
  • "ts": "2019-08-24T14:15:22Z",
  • "value": {
    },
  • "version": "string"
}

Write

  • Writes values to HPL points. If command_id is set, writes are tracked by that command and reverted on expiration; otherwise writes are dispatched directly with no reversion. Guardrails are enforced when enabled.
Request Body schema: application/json
cancelOnConflict
boolean

If we try to write to a point which is already written to by a different command, setting this to true will cancel the command.

cancelOnError
boolean

If true, any errors writing to the underlying point results in canceling the underlying command if the write occurs inside of a transaction.

commandId
string

the command id to associate this write with.

systemPriority
string

internal command priority to use (relative to other commands in the internal priority array).

truncateFloats
boolean

if true, the command will truncate floats when converting float -> integer. Otherwise, type conversion will succeed only if the floating point value represents a whole integer. Deprecated: use the options field in WriteCommand

Array of objects (normalgw.hpl.v2.WriteCommand)

Responses

Request samples

Content type
application/json
{
  • "cancelOnConflict": true,
  • "cancelOnError": true,
  • "commandId": "string",
  • "systemPriority": "string",
  • "truncateFloats": true,
  • "writes": [
    ]
}

Response samples

Content type
application/json
{
  • "errors": [
    ],
  • "writes": [
    ]
}

CancelCommand

  • Cancels a running command, reverting all writes it made. Returns NOT_FOUND if the command does not exist or has already expired.
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{ }

GetCommand

  • Retrieves a single command by ID or name. Returns NOT_FOUND if no matching active command exists.
path Parameters
id
required
string
Request Body schema: application/json
id
string
name
string

Responses

Request samples

Content type
application/json
{
  • "id": "string",
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "command": {
    }
}

Configuration

GetConfiguration

  • Returns the current BACnet configuration including device instance/name, discovery settings, segmentation state, and a list of available network interfaces with their IPv4 addresses.

Responses

Response samples

Content type
application/json
{
  • "automaticDiscoveryPeriod": {
    },
  • "availableInterfaces": [
    ],
  • "backgroundScansEnabled": true,
  • "debug": true,
  • "deviceInstance": 0,
  • "deviceName": "string",
  • "segmentationEnabled": true
}

UpdateConfiguration

  • Updates BACnet configuration settings including device instance/name, auto-discovery period, debug logging, and segmentation support. The minimum auto-discovery period is 1 hour. Changes are persisted to disk.
Request Body schema: application/json
object

if non-zero, NF will perform a global whois-based discovery each interval to find any additional devices

backgroundScansEnabled
boolean

when enabled, NF will rescan any devices if their database revision changes

debug
boolean

debug logging enabled

deviceInstance
integer <uint32>

instance number of the local device (device id)

deviceName
string

prop_object_name for the local device object

readOnly
boolean

read only mode disabled mutating bacnet services

segmentationEnabled
boolean

when enabled, the gateway will accept segmented ComplexACK responses

Responses

Request samples

Content type
application/json
{
  • "automaticDiscoveryPeriod": {
    },
  • "backgroundScansEnabled": true,
  • "debug": true,
  • "deviceInstance": 0,
  • "deviceName": "string",
  • "readOnly": true,
  • "segmentationEnabled": true
}

Response samples

Content type
application/json
{ }

GetLocalObjects

  • Returns local BACnet objects from the gateway's object database. Supports pagination, case-insensitive text search (on name, description, and object ID), and filtering by device instance offset (-1 returns objects across all virtual devices). Does not include the Device object itself.
query Parameters
localDeviceInstanceOffset
integer <int32>

local device instance offset 0 for NF device -1 to retrieve all objects

pageOffset
string
pageSize
string
search
string

case-insensitive text search on object name, description, or object ID

Responses

Response samples

Content type
application/json
{
  • "objects": [
    ],
  • "totalCount": "string"
}

UpdateLocalObject

  • Updates properties on an existing local object. Can look up the object by uuid or by object_id. Standard property values are type-checked. New properties are appended; existing ones are overwritten. Returns the full updated object.
Request Body schema: application/json
localDeviceInstanceOffset
integer <uint32>
object (normalgw.bacnet.v1.ObjectId)
Array of objects (normalgw.bacnet.v1.PropertyValue)
uuid
string

Responses

Request samples

Content type
application/json
{
  • "localDeviceInstanceOffset": 0,
  • "objectId": {
    },
  • "props": [
    ],
  • "uuid": "string"
}

Response samples

Content type
application/json
{
  • "object": {
    }
}

CreateLocalObject

  • Creates a persistent local BACnet object. Supported types: analog-value, binary-value, multi-state-value, analog-input, binary-input, multi-state-input, schedule, and device. If instance is 0, one is auto-allocated. Property values are type-checked against the BACnet spec. For virtual devices, the device object must be created first (via OBJECT_DEVICE).
Request Body schema: application/json
localDeviceInstanceOffset
integer <uint32>
object

if instance is zero a new instance will be allocated

Array of objects (normalgw.bacnet.v1.PropertyValue)
uuid
string

Responses

Request samples

Content type
application/json
{
  • "localDeviceInstanceOffset": 0,
  • "objectId": {
    },
  • "props": [
    ],
  • "uuid": "string"
}

Response samples

Content type
application/json
{
  • "objectId": {
    },
  • "uuid": "string"
}

DeleteLocalObjects

  • Bulk-deletes multiple local objects by calling DeleteLocalObject for each entry. Stops on first error.
Request Body schema: application/json
Array of objects (normalgw.bacnet.v1.DeleteLocalObjectRequest)

Responses

Request samples

Content type
application/json
{
  • "objects": [
    ]
}

Response samples

Content type
application/json
{ }

DeleteLocalObject

  • Deletes a local BACnet object by type and instance. Deleting a virtual device object (OBJECT_DEVICE) cascades to remove all objects under that device. The default device object (offset 0) cannot be deleted.
path Parameters
object_id.object_type
required
string
object_id.instance
required
string
query Parameters
objectId.objectType
integer <enum>
objectId.instance
integer <uint32>
localDeviceInstanceOffset
integer <uint32>

Responses

Response samples

Content type
application/json
{ }

GetNetworkPorts

  • Returns all configured network ports (IP, SC, virtual, Ethernet) with their status, network numbers, routing info, and any error state. Includes both active ports and ports that failed to initialize.

Responses

Response samples

Content type
application/json
{
  • "ports": [
    ]
}

AddNetworkPort

  • Adds a new network port (IP, SC, virtual, or Ethernet) to the BACnet router. The port configuration is validated and persisted to disk on success.
Request Body schema: application/json
error
string
object (normalgw.bacnet.v1.EthernetConfiguration)
object (normalgw.bacnet.v1.IPConfiguration)
localNetwork
integer <int32>

local network number

metric
integer <uint32>

the metric of the port, used for routing

name
string
networks
Array of integers <int32> [ items <int32 > ]
portId
integer <uint32>
object (normalgw.bacnet.v1.SCConfiguration)

configuration of a BACnet/SC link

siteRef
string
status
integer <enum>
virtual
object (normalgw.bacnet.v1.VirtualConfiguration)

configuration of the virtual network. Only one is supported.

Responses

Request samples

Content type
application/json
{
  • "error": "string",
  • "ethernet": {
    },
  • "ip": {
    },
  • "localNetwork": 0,
  • "metric": 0,
  • "name": "string",
  • "networks": [
    ],
  • "portId": 0,
  • "sc": {
    },
  • "siteRef": "string",
  • "status": 0,
  • "virtual": { }
}

Response samples

Content type
application/json
{ }

DeleteNetworkPort

  • Removes a network port from the BACnet router by port_id. Returns NOT_FOUND if the port does not exist.
path Parameters
portId
required
integer <uint32>

Responses

Response samples

Content type
application/json
{ }

UpdateNetworkPort

  • Updates an existing network port's configuration. The port configuration type must match the existing port type (e.g. IP config for IP port). The port is reset after update. Can also update ports in error state.
path Parameters
portId
required
integer <uint32>
Request Body schema: application/json
error
string
object (normalgw.bacnet.v1.EthernetConfiguration)
object (normalgw.bacnet.v1.IPConfiguration)
localNetwork
integer <int32>

local network number

metric
integer <uint32>

the metric of the port, used for routing

name
string
networks
Array of integers <int32> [ items <int32 > ]
portId
integer <uint32>
object (normalgw.bacnet.v1.SCConfiguration)

configuration of a BACnet/SC link

siteRef
string
status
integer <enum>
virtual
object (normalgw.bacnet.v1.VirtualConfiguration)

configuration of the virtual network. Only one is supported.

Responses

Request samples

Content type
application/json
{
  • "error": "string",
  • "ethernet": {
    },
  • "ip": {
    },
  • "localNetwork": 0,
  • "metric": 0,
  • "name": "string",
  • "networks": [
    ],
  • "portId": 0,
  • "sc": {
    },
  • "siteRef": "string",
  • "status": 0,
  • "virtual": { }
}

Response samples

Content type
application/json
{ }

DeleteProprietaryPropertyMap

  • Deletes a proprietary property map entry matching the given vendor_id, object_type, and property_id. Returns NOT_FOUND if no matching map exists.
Request Body schema: application/json
objectType
integer <enum>
propertyId
integer <enum>
vendorId
integer <uint32>

Responses

Request samples

Content type
application/json
{
  • "objectType": 0,
  • "propertyId": 0,
  • "vendorId": 0
}

Response samples

Content type
application/json
{ }

GetProprietaryPropertyMap

  • Returns proprietary property maps for a given vendor_id. Pass vendor_id=0xFFFFFFFF to retrieve maps for all vendors. For a specific vendor, also includes maps from the "any vendor" (0xFFFFFFFF) set. Maps are persisted as JSON files on disk.
query Parameters
vendorId
integer <uint32>

Responses

Response samples

Content type
application/json
{
  • "map": [
    ]
}

CreateProprietaryPropertyMap

  • Creates or updates a proprietary property map entry. If a map with the same object_type and property_id already exists for the vendor, it is replaced.
Request Body schema: application/json
objectName
string

name for the point representing this property

object

optionally only use this map for a single object type

propertyId
integer <enum>

property id number

type
integer <enum>

the type of the property

units
integer <enum>

bacnet engineering units to assign

vendorId
integer <uint32>

vendor id this map applies to

Responses

Request samples

Content type
application/json
{
  • "objectName": "string",
  • "objectType": {
    },
  • "propertyId": 0,
  • "type": 0,
  • "units": 0,
  • "vendorId": 0
}

Response samples

Content type
application/json
{ }

ObserveLocalObjectUpdates

  • Streams local object change notifications (creates, updates, deletes, and BACnet writes) from a WAL. Supply a version token to resume from a previous position, or omit to start from the latest. Set wait=true to block for new changes; otherwise the stream closes after delivering available entries.
query Parameters
version
string
limit
integer <int32>
wait
boolean

Responses

Response samples

Content type
application/json
{
  • "changeKind": 0,
  • "localDeviceInstanceOffset": 0,
  • "objectId": {
    },
  • "props": [
    ],
  • "ts": "2019-08-24T14:15:22Z",
  • "uuid": "string",
  • "version": "string"
}

EquipmentService

CreateEquip

  • Creates an equipment instance point in the model layer. UUID is deterministically generated from the name via MD5. Returns AlreadyExists if an equip with the same name exists. Sets class, markers, and equipTypeId attrs from the referenced equipment type.
Request Body schema: application/json
equipmentTypeId
string
name
string

Responses

Request samples

Content type
application/json
{
  • "equipmentTypeId": "string",
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "uuid": "string"
}

GetEquipsById

  • Fetches equipment instances by their equip id attributes. Always includes child points in the response. Returns InvalidArgument if ids is empty.
query Parameters
ids
Array of strings

Responses

Response samples

Content type
application/json
{
  • "equips": [
    ],
  • "totalCount": "string"
}

GetEquips

  • Lists equipment instances filtered by equipment type. Supports filtering by point classes (include or exclude), site references, and arbitrary queries. When include_points is true, also loads and groups child points by class for each equipment.
path Parameters
type
required
string

Equipment Type Filter

query Parameters
pageOffset
string
pageSize
string
pointsClassesFilter
Array of strings

Filter equipment by point classes contained in the model layer

excludeMatchingClasses
boolean
sort.field
string
sort.order
string
sort.layer
string
includePoints
boolean
query.field.property
string
query.field.text
string
query.field.numeric.minValue
number <double>
query.field.numeric.minInfinity
boolean
query.field.numeric.maxValue
number <double>
query.field.numeric.maxInfinity
boolean
query.field.layer
string
query.field.wildcard
boolean
query.reference.property
string
query.reference.targetProperty
string
query.reference.query.field.property
string
query.reference.query.field.text
string
query.reference.query.field.numeric.minValue
number <double>
query.reference.query.field.numeric.minInfinity
boolean
query.reference.query.field.numeric.maxValue
number <double>
query.reference.query.field.numeric.maxInfinity
boolean
query.reference.query.field.layer
string
query.reference.query.field.wildcard
boolean
query.reference.query.reference.property
string
query.reference.query.reference.targetProperty
string
sitesFilter
Array of strings

Responses

Response samples

Content type
application/json
{
  • "equips": [
    ],
  • "totalCount": "string"
}

GetEquipmentClasses

  • Returns ontology-defined equipment classes (loaded from the ontology JSON file at startup). Filterable by id, parent class, and entity kind. Supports pagination and field masking. These are read-only definitions from the ontology, not user-created equipment types.
query Parameters
id
string
parent
string
mask
Array of strings
pageOffset
string
pageSize
string
kind
integer <enum>

Responses

Response samples

Content type
application/json
{
  • "equipmentClasses": [
    ],
  • "totalCount": "string"
}

ObserveEquipmentTypes

  • Server-streaming RPC that watches for equipment type changes via Redis Streams. Pass a version to resume from a specific position; empty string starts from the latest. If wait=false, returns immediately with available updates; if wait=true, blocks until new updates arrive. Optionally filter by ids.
query Parameters
version
string
limit
integer <int32>
wait
boolean
ids
Array of strings

Responses

Response samples

Content type
application/json
{
  • "new": {
    },
  • "old": {
    },
  • "ts": "2019-08-24T14:15:22Z",
  • "version": "string"
}

ExtractEquipments

  • Extracts equipment entities from an input point layer using string extractors or JS functions. Groups input points by extracted ID, looks up existing entities in the output layer, and optionally writes results if write=true. Supports pagination via page_size/page_offset.
Request Body schema: application/json
attrName
string
attrs
Array of strings

attributes to create id

object

other attributes to set

object

map of id -> attribute values to set on matching entities

object

map of id -> attribute values to set on points matching entities

object

extractor which pulls the ID out

inputLayer
string
object (normalgw.hpl.v1.Query)
object

settings for what to do with input references

keySeparator
string

separator for key if multiple attrs specified

namespace
string

uuid namespace for generating uuids for extracted entities. blank for default

outputLayer
string

must have the id field indexed as tags so we can check for dups

pageOffset
string
pageSize
string
object

map of old id -> new id

save
integer <enum>

save to the point layer

write
boolean

if true, write the output to the database

Responses

Request samples

Content type
application/json
{
  • "attrName": "string",
  • "attrs": [
    ],
  • "defaultAttrs": {
    },
  • "extraAttrs": {
    },
  • "extraPointAttrs": {
    },
  • "extractor": {
    },
  • "inputLayer": "string",
  • "inputQuery": {
    },
  • "inputReferences": {
    },
  • "keySeparator": "string",
  • "namespace": "string",
  • "outputLayer": "string",
  • "pageOffset": "string",
  • "pageSize": "string",
  • "renames": {
    },
  • "save": 0,
  • "write": true
}

Response samples

Content type
application/json
{
  • "dropped": [
    ],
  • "equipments": [
    ],
  • "error": "string",
  • "errors": [
    ],
  • "totalCount": "string"
}

EquipmentsExtractionApply

  • Applies extraction changes previously returned by EquipmentsExtractionPreview. Creates/updates equipment points and sets reference attributes on input points. REMOVED points have their reference cleared; extra_point_attrs are set on all referenced points.
Request Body schema: application/json
object
Array of objects (normalgw.ontology.v1.ExtractionEquipmentChange)
object (normalgw.ontology.v1.AttributeValues)
layer
string
referenceAttr
string

Responses

Request samples

Content type
application/json
{
  • "attrs": {
    },
  • "equipments": [
    ],
  • "extraPointAttrs": {
    },
  • "layer": "string",
  • "referenceAttr": "string"
}

Response samples

Content type
application/json
{ }

EquipmentsExtractionPreview

  • Dry-run extraction that returns a preview of equipment changes without writing anything. Loads all matching input points (ignores pagination), compares against existing reference assignments, and classifies each point as ADDED, REMOVED, or NO_CHANGE per equipment.
Request Body schema: application/json
attrName
string
attrs
Array of strings

attributes to create id

object

extractor which pulls the ID out

inputLayer
string
object (normalgw.hpl.v1.Query)
keySeparator
string

separator for key if multiple attrs specified

namespace
string

uuid namespace for generating uuids for extracted entities. blank for default

outputLayer
string

must have the id field indexed as tags so we can check for dups

referenceAttr
string
object

map of old id -> new id

Responses

Request samples

Content type
application/json
{
  • "attrName": "string",
  • "attrs": [
    ],
  • "extractor": {
    },
  • "inputLayer": "string",
  • "inputQuery": {
    },
  • "keySeparator": "string",
  • "namespace": "string",
  • "outputLayer": "string",
  • "referenceAttr": "string",
  • "renames": {
    }
}

Response samples

Content type
application/json
{
  • "dropped": [
    ],
  • "equipments": [
    ],
  • "errors": [
    ]
}

GetWorkflows

  • Lists extraction workflows from the file-based repository. Only returns workflows that have an active in-memory Workflow instance. When content=true, includes template rows; otherwise returns only metadata and headers. Includes pending_changes count and state.
query Parameters
ids
Array of strings
pageOffset
string
pageSize
string
content
boolean

Responses

Response samples

Content type
application/json
{
  • "totalCount": "string",
  • "workflows": [
    ]
}

UpdateWorkflow

  • Updates an existing workflow's definition, template, and rules. Persists to disk, clears pending changes, reloads the template, and re-evaluates all input points. Returns NotFound if the workflow is not running in memory.
Request Body schema: application/json
object (normalgw.ontology.v1.ExtractionWorkflow)

Responses

Request samples

Content type
application/json
{
  • "workflow": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string"
}

CreateWorkflow

  • Creates a new extraction workflow. Generates a UUID if id is empty. Persists to disk, initializes the in-memory workflow processor, triggers a full reload against the input query, and links the workflow to its equipment type.
Request Body schema: application/json
object (normalgw.ontology.v1.ExtractionWorkflow)

Responses

Request samples

Content type
application/json
{
  • "workflow": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string"
}

DeleteWorkflow

  • Deletes a workflow from disk, stops its in-memory processor (clearing pending changes first to avoid deadlocks), and unlinks it from its equipment type.
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{ }

ApplyWorkflowChanges

  • Writes pending workflow changes to the point database. If changes is non-empty, applies only those specific changes synchronously. If empty, applies all pending changes (or filtered subset) asynchronously in a background goroutine. Returns FailedPrecondition if the workflow is already applying or restarting.
path Parameters
id
required
string
Request Body schema: application/json
Array of objects (normalgw.ontology.v1.WorkflowPointUpdate)

Changes to apply to the points db If empty all changes will be applied

object (normalgw.ontology.v1.WorkflowPendingChangesFilter)
id
string

Responses

Request samples

Content type
application/json
{
  • "changes": [
    ],
  • "filters": {
    },
  • "id": "string"
}

Response samples

Content type
application/json
{
  • "taskId": "string"
}

GetWorkflowPendingChanges

  • Returns paginated pending attribute changes for a workflow. Filter by point_type (EQUIPMENT to see equipment-level changes) or by equipment_id (to see points for a specific equip). Changes are stored in Redis sorted sets ordered by timestamp.
path Parameters
id
required
string
query Parameters
pageSize
string
pageOffset
string
filters.pointType
integer <enum>
filters.equipmentId
string

Responses

Response samples

Content type
application/json
{
  • "changes": [
    ],
  • "totalCount": "string"
}

RenameEquip

  • Renames an equipment instance by updating its id/name, generating a new deterministic UUID, and migrating the point via RenamePoint. Also bulk-updates all child points' equipRef from old_name to new_name. Returns NotFound/AlreadyExists as appropriate.
Request Body schema: application/json
newName
string
oldName
string

Responses

Request samples

Content type
application/json
{
  • "newName": "string",
  • "oldName": "string"
}

Response samples

Content type
application/json
{
  • "newUuid": "string"
}

GetEquipmentTypes

  • Lists equipment types from Redis, with optional filtering by ids and pagination. If no ids are provided, returns all equipment types sorted alphabetically. When include_equips is true, also loads equipment instances and point class counts per equip.
query Parameters
ids
Array of strings
pageOffset
string
pageSize
string
includeEquips
boolean

Responses

Response samples

Content type
application/json
{
  • "equipmentTypes": [
    ],
  • "totalCount": "string"
}

UpdateEquipmentType

  • Updates an existing equipment type, merging markers/attributes/relations/points with the ontology base class. Generates a UUID if id is empty. Does not check for prior existence (use CreateEquipmentType for that). Publishes a change event to the observation stream.
Request Body schema: application/json
object (normalgw.ontology.v1.EquipmentType)

Responses

Request samples

Content type
application/json
{
  • "equipmentType": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string"
}

CreateEquipmentType

  • Creates a new equipment type by merging the request with the ontology class definition. Generates a UUID if id is empty. Returns AlreadyExists if an equipment type with the same id exists. Stored in Redis and publishes a change event to the observation stream.
Request Body schema: application/json
object (normalgw.ontology.v1.EquipmentType)

Responses

Request samples

Content type
application/json
{
  • "equipmentType": {
    }
}

Response samples

Content type
application/json
{
  • "id": "string"
}

DeleteEquipmentType

  • Deletes an equipment type by id. Returns FailedPrecondition if the type is referenced by any workflows. Returns NotFound if the id does not exist. Publishes a deletion event to the observation stream.
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{ }

FoxService

GetConnections

  • Returns all Fox (Niagara) connections, or a single connection if connection_id is set. Includes live status, hello message attributes, and connection count. Discovery time is only loaded for single-connection requests. URL credentials are obfuscated in the response.
query Parameters
connectionId
string

Responses

Response samples

Content type
application/json
{
  • "connections": [
    ]
}

AddConnection

  • Adds a new Fox connection. URL must include username, password, hostname, and port. Validates the hostname is resolvable and rejects duplicate host:port pairs. Starts the Fox protocol connection in the background.
query Parameters
id
string
url
string

fox connection URL

name
string
siteRef
string

Responses

Response samples

Content type
application/json
{
  • "id": "string"
}

GetDiscovery

  • Returns the saved discovery tree for a connection from Redis. Set max_depth > 0 to truncate deep subtrees (nodes beyond max_depth are marked Truncated=true with no children). Use ExpandDiscoveryNode to fetch truncated subtrees.
path Parameters
connectionId
required
string
query Parameters
maxDepth
integer <int32>

maximum depth of the tree to return. 0 = full tree (default/legacy behavior) when > 0, nodes beyond this depth are returned as stubs

Responses

Response samples

Content type
application/json
{
  • "discoverTime": "2019-08-24T14:15:22Z",
  • "importableOrds": [
    ],
  • "importedOrds": [
    ],
  • "nodeTypeWhitelist": [
    ],
  • "pointTypes": [
    ],
  • "result": {
    },
  • "unexploredNodeTypes": [
    ]
}

StartDiscovery

  • Starts an asynchronous discovery of the Niagara station. Returns immediately -- discovery runs in the background. Specify node_types to control which types are explored (defaults to configured fox_explore_types). Preserves imported_ords from any previous discovery.
path Parameters
connectionId
required
string
query Parameters
nodeTypes
Array of strings

list of node types to explore blank means only explore the result

Responses

Response samples

Content type
application/json
{ }

ExpandDiscoveryNode

  • Expands a subtree from the saved discovery (does NOT fetch from the live Niagara device). Use this to paginate large discovery trees that were truncated by max_depth in GetDiscovery. Returns importable and imported ords within the subtree.
path Parameters
connectionId
required
string
query Parameters
ord
string

ord of the node to expand

maxDepth
integer <int32>

maximum depth to return from this node. 0 = full subtree, > 0 = limited depth

Responses

Response samples

Content type
application/json
{
  • "importableOrds": [
    ],
  • "importedOrds": [
    ],
  • "result": {
    }
}

Import

  • Imports selected ords from the discovery as points in the point database. Set delete_unimported_points=true to remove points belonging to this connection that are not in the import list. Returns counts of additions and removals.
path Parameters
connectionId
required
string
query Parameters
importOrds
Array of strings
deleteUnimportedPoints
boolean

remove points from the point database which belong to this connection but are onot being imported (e.g., remove stale points)

Responses

Response samples

Content type
application/json
{
  • "additions": 0,
  • "removals": 0
}

Load

  • Fetches children of a stub node from the live Niagara device (not from saved discovery). Depth max is 2. Saves the updated tree to the discovery unless ephemeral=true. Fails if the node is already loaded or not found.
path Parameters
connectionId
required
string

fox connection id to use

query Parameters
ord
string

ord of the node to load

depth
integer <int32>

depth parameter to pass when loading

ephemeral
boolean

Responses

Response samples

Content type
application/json
{
  • "importableOrds": [
    ],
  • "importedOrds": [
    ],
  • "result": {
    }
}

GetConnectionLogs

  • Server-streaming RPC that returns logs for a Fox connection. Currently a stub -- returns immediately without streaming any messages.
path Parameters
connectionId
required
string

Responses

Response samples

Content type
application/json
{
  • "message": "string"
}

GetConnectionPassword

  • Returns the cleartext password for a fox connection. Sensitive: every call is audit-logged with the connection_id and peer address. Intended for "show password" UX in the connection editor; do not use for bulk reads.
path Parameters
connectionId
required
string

Responses

Response samples

Content type
application/json
{
  • "password": "string"
}

GetWiresheets

  • Returns wiresheets (nodes with b=baja modifier) from the saved discovery. Without ord: returns a shallow list of all wiresheet names/ords. With ord: returns the full subtree plus SVG and Mermaid diagram representations. Fails if the ord is not a wiresheet.
path Parameters
connectionId
required
string
query Parameters
ord
string

If empty, returns a list of all wiresheet nodes (shallow). If set, returns the full subtree for that specific wiresheet ord.

Responses

Response samples

Content type
application/json
{
  • "mermaid": "string",
  • "result": {
    },
  • "svg": "string",
  • "wiresheets": [
    ]
}

DeleteConnection

  • Deletes a Fox connection, shuts down the protocol session, and removes discovery data from Redis. Set delete_points=true to also remove all imported points from the point database; the count of deleted points is returned.
path Parameters
id
required
string
query Parameters
deletePoints
boolean

Responses

Response samples

Content type
application/json
{
  • "deletedPointsCount": "string"
}

UpdateConnection

  • Updates a Fox connection's URL, name, or site_ref. Internally deletes and recreates the connection, preserving the ID and UseConnectionNamespace flag. The connection will reconnect with the new settings.
path Parameters
id
required
string
query Parameters
url
string
name
string
siteRef
string

Responses

Response samples

Content type
application/json
{ }

Modbus

DeleteDeviceConnection

  • Deletes a Modbus device connection and removes the device from the point service. Does not delete the points created by the connection -- those must be cleaned up separately if desired.
Request Body schema: application/json
uuid
string

Responses

Request samples

Content type
application/json
{
  • "uuid": "string"
}

Response samples

Content type
application/json
{ }

GetDeviceConnections

  • Returns all configured Modbus device connections with their current connection status (connected/connecting/error/disabled).

Responses

Response samples

Content type
application/json
{
  • "connections": [
    ]
}

CreateDeviceConnection

  • Creates a connection to a Modbus device using an existing profile. Generates a UUID if not provided. Immediately publishes device and point metadata and tests the TCP connection. Polling rate must be configured separately via the point service before data acquisition begins.
Request Body schema: application/json
object (normalgw.modbus.v1.DeviceConnection)

Responses

Request samples

Content type
application/json
{
  • "connection": {
    }
}

Response samples

Content type
application/json
{
  • "connectionUuid": "string"
}

DeleteDeviceProfile

  • Deletes a Modbus device profile. Fails with FailedPrecondition if the profile is currently in use by any connection.
Request Body schema: application/json
uuid
string

Responses

Request samples

Content type
application/json
{
  • "uuid": "string"
}

Response samples

Content type
application/json
{ }

GetDeviceProfiles

  • Returns all configured Modbus device profiles. Set content=true to include register maps (omitted by default for efficiency). Profiles are stored as protobuf files on disk.
query Parameters
content
boolean

set to true to retrieve register maps

Responses

Response samples

Content type
application/json
{
  • "profiles": [
    ]
}

CreateDeviceProfile

  • Creates a new Modbus device profile with register map, endianness, and word order settings. The profile UUID must be unique. Fails with AlreadyExists if a profile with the same UUID exists.
Request Body schema: application/json
object (normalgw.modbus.v1.DeviceProfile)

Responses

Request samples

Content type
application/json
{
  • "profile": {
    }
}

Response samples

Content type
application/json
{ }

PacketCaptureService

StreamCapture

  • Initiates a packet capture on the specified interface and port range, returning a one-time download URL for a live pcap stream. The capture runs until the duration expires (max 1 hour). The download URL must be fetched via HTTP (not gRPC) and streams pcap data as it is captured. Both interface and port range are required.
Request Body schema: application/json
object (google.protobuf.Duration)

A Duration represents a signed, fixed-length span of time represented as a count of seconds and fractions of seconds at nanosecond resolution. It is independent of any calendar and concepts like "day" or "month". It is related to Timestamp in that the difference between two Timestamp values is a Duration and it can be added or subtracted from a Timestamp. Range is approximately +-10,000 years. # Examples Example 1: Compute Duration from two Timestamps in pseudo code. Timestamp start = ...; Timestamp end = ...; Duration duration = ...; duration.seconds = end.seconds - start.seconds; duration.nanos = end.nanos - start.nanos; if (duration.seconds < 0 && duration.nanos > 0) { duration.seconds += 1; duration.nanos -= 1000000000; } else if (duration.seconds > 0 && duration.nanos < 0) { duration.seconds -= 1; duration.nanos += 1000000000; } Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. Timestamp start = ...; Duration duration = ...; Timestamp end = ...; end.seconds = start.seconds + duration.seconds; end.nanos = start.nanos + duration.nanos; if (end.nanos < 0) { end.seconds -= 1; end.nanos += 1000000000; } else if (end.nanos >= 1000000000) { end.seconds += 1; end.nanos -= 1000000000; } Example 3: Compute Duration from datetime.timedelta in Python. td = datetime.timedelta(days=3, minutes=10) duration = Duration() duration.FromTimedelta(td) # JSON Mapping In JSON format, the Duration type is encoded as a string rather than an object, where the string ends in the suffix "s" (indicating seconds) and is preceded by the number of seconds, with nanoseconds expressed as fractional seconds. For example, 3 seconds with 0 nanoseconds should be encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should be expressed in JSON format as "3.000000001s", and 3 seconds and 1 microsecond should be expressed in JSON format as "3.000001s".

interface
string
portEnd
integer <uint32>
portStart
integer <uint32>
protocol
integer <enum>

Responses

Request samples

Content type
application/json
{
  • "duration": {
    },
  • "interface": "string",
  • "portEnd": 0,
  • "portStart": 0,
  • "protocol": 0
}

Response samples

Content type
application/json
{
  • "downloadUrl": "string"
}

PlatformConfig

GetEnvironmentVariables

  • Returns all environment variables that have a non-empty section, sorted by section then ID. Only returns user-facing configuration knobs, not internal variables.
query Parameters
name
string
section
string

Responses

Response samples

Content type
application/json
{
  • "variables": [
    ]
}

SetEnvironmentVariables

  • Updates environment variables by ID. Validates all variables first; if any fail validation, none are applied and errors are returned in the reply. Variables must reference predefined IDs registered via GetEnv.
Request Body schema: application/json
Array of objects (normalgw.platform.v1.EnvironmentVariable)

Responses

Request samples

Content type
application/json
{
  • "variables": [
    ]
}

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

GetSystemInformation

  • Returns site info, auth config, license details, resource utilization (disk/memory), IP addresses, Redis status, and system time. Does not require authentication. When accessed through a tunnel, the auth provider is overridden to NF_CLERK.

Responses

Response samples

Content type
application/json
{
  • "authority": "string",
  • "clientid": "string",
  • "domain": "string",
  • "enableAuth": true,
  • "favIcon": "string",
  • "footerText": "string",
  • "ipAddresses": [
    ],
  • "license": {
    },
  • "logo": "string",
  • "machineInfo": "string",
  • "nfOnlineUrl": "string",
  • "provider": 0,
  • "redisStatus": {
    },
  • "resources": [
    ],
  • "scopes": "string",
  • "services": [
    ],
  • "siteName": "string",
  • "systemTime": "2019-08-24T14:15:22Z",
  • "systemType": 0,
  • "thumbnail": "string",
  • "timezone": "string",
  • "version": "string"
}

SetLicense

  • Installs or clears the license. Pass an empty string to clear. Validates the JWT, checks machine fingerprint match, and on GA systems also verifies online validity. On success, configures tunnel/backup services and restarts licensed services.
Request Body schema: application/json
license
string

Responses

Request samples

Content type
application/json
{
  • "license": "string"
}

Response samples

Content type
application/json
{ }

ResetLicense

  • Unimplemented. Use SetLicense with an empty license string to clear the license instead.
Request Body schema: application/json
object (normalgw.platform.v1.ResetLicenseRequest)

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{ }

GetLicenseToken

  • Returns the raw JWT token string from the current license. Returns FailedPrecondition if no license is installed.
Request Body schema: application/json
object (normalgw.platform.v1.LicenseTokenRequest)

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "token": "string"
}

SetNWConfigEnabled

  • Enables or disables Normal Connect by creating/removing a flag file. Requires a nwconfig service restart to take effect.
Request Body schema: application/json
enabled
boolean

Responses

Request samples

Content type
application/json
{
  • "enabled": true
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "success": true
}

GetNWConfigStatus

  • Returns the Normal Connect (nwconfig) service status by reading its JSON status file. Returns state "not_running" if the status file is absent.

Responses

Response samples

Content type
application/json
{
  • "status": {
    }
}

GetRedisDebugInfo

  • Returns Redis debug information including parsed INFO sections (server, memory, persistence, stats, clients), slow log entries, and auto-detected warnings. Optionally includes a full key-pattern memory analysis (slow on large databases).
query Parameters
includeKeyAnalysis
boolean

Responses

Response samples

Content type
application/json
{
  • "info": {
    }
}

PointManager

  • Point ServiceThe point service is the main interface into the configuration state stored on the device. It provides full-text search of all objects, layered attribute storage, and timeseries data access.

AggregatePoints

  • Runs FT.AGGREGATE with GROUPBY on the specified attributes and applies the given aggregators (COUNT, SUM, AVG, MIN, MAX, COUNT_DISTINCT, LIST). Only works on BASE layers; returns InvalidArgument for UNION layers. Requires at least one attribute and one aggregator.
Request Body schema: application/json
Array of objects (normalgw.hpl.v1.PointAggregator)

aggregators to apply

attrs
Array of strings

attributes to group by

layer
string
object

optional query to filter rows

Responses

Request samples

Content type
application/json
{
  • "aggregators": [
    ],
  • "attrs": [
    ],
  • "layer": "string",
  • "query": {
    }
}

Response samples

Content type
application/json
{
  • "values": [
    ]
}

GetDistinctAttrs

  • Returns distinct values and their counts for the requested attributes using FT.AGGREGATE GROUPBY on the search index. Supports pagination via page_offset/page_size on the aggregation results. If query_layer differs from layer, the query runs against query_layer's index but reads attribute values from layer.
query Parameters
attrs
Array of strings
query
string
structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
layer
string
queryLayer
string
pageOffset
string
pageSize
string

Responses

Response samples

Content type
application/json
{
  • "attrs": [
    ]
}

DeleteConfigKeys

  • Deletes one or more configuration keys. Returns the list of keys that were successfully deleted.
query Parameters
keys
Array of strings

Responses

Response samples

Content type
application/json
{
  • "keys": [
    ]
}

GetConfigKeys

  • Retrieves arbitrary key-value configuration data stored in Redis. If no keys are specified, returns all config keys. Values are opaque byte arrays.
query Parameters
keys
Array of strings

Responses

Response samples

Content type
application/json
{
  • "values": {
    }
}

SetConfigKey

  • Sets a single configuration key to the given byte value, stored persistently in Redis with no expiration.
Request Body schema: application/json
key
string
value
string <bytes>

Responses

Request samples

Content type
application/json
{
  • "key": "string",
  • "value": "string"
}

Response samples

Content type
application/json
{ }

GetConversions

  • Lists conversion definitions. If ids are provided, returns only those; otherwise returns all.
query Parameters
ids
Array of strings

Responses

Response samples

Content type
application/json
{
  • "conversions": [
    ]
}

CreateConversion

  • Creates a reusable value conversion definition. Conversions are applied on the read path to transform raw timeseries values (e.g. linear scaling, boolean inversion, or arbitrary JS). Associate a conversion with points by setting conversion_id via UpdatePoints.
Request Body schema: application/json
object (normalgw.hpl.v1.Conversion)

Responses

Request samples

Content type
application/json
{
  • "conversion": {
    }
}

Response samples

Content type
application/json
{
  • "conversion": {
    }
}

UpdateConversion

  • Updates a conversion definition. All points referencing this conversion will see the updated transform on their next read.
Request Body schema: application/json
object (normalgw.hpl.v1.Conversion)

Responses

Request samples

Content type
application/json
{
  • "conversion": {
    }
}

Response samples

Content type
application/json
{
  • "conversion": {
    }
}

DeleteConversion

  • Deletes a conversion definition and clears conversion_id on any associated points.
path Parameters
id
required
string

Responses

Response samples

Content type
application/json
{ }

CopyAttributes

  • Copies attributes from one layer to another for points matching a query or UUID list. Can also set static attribute values, remap attribute names via mapped_attributes, and update period/COV settings. Requires an output_layer; if no input_layer is given, only static_attributes are applied.
Request Body schema: application/json
attributes
Array of strings

list of attribute names to copy

object

if present, update the COV settings

indexLayer
string

layer to perform search query against. if blank, the input layer is used.

inputLayer
string

layer to read values from. may be a base layer

mappedAttributes
Array of strings

if present, a list of corresponding attribute names to map in the output layer

outputLayer
string

layer to write values to. may be a base layer

object

if present, update the matching points with this period

query
string

the copy operation is applied to all points matching the query or in the list of uuids

object

any attributes set here will be set to the static value in the map instead of the input layer value. if all attributes are in the map, the input layer is ignored and may be blank, and only the output layer is written to. this can be used, for instance, to set an attribute to a constant text string based on a query, or to clear an attribute.

object (normalgw.hpl.v1.Query)
uuids
Array of strings

any UUIDs specified in this list are also consider matched.

Responses

Request samples

Content type
application/json
{
  • "attributes": [
    ],
  • "cov": {
    },
  • "indexLayer": "string",
  • "inputLayer": "string",
  • "mappedAttributes": [
    ],
  • "outputLayer": "string",
  • "period": {
    },
  • "query": "string",
  • "staticAttributes": {
    },
  • "structuredQuery": {
    },
  • "uuids": [
    ]
}

Response samples

Content type
application/json
{
  • "updateCount": 0
}

GetData

  • Queries timeseries data from Redis TimeSeries. Default retention is 7 days (configurable via TIMESERIES_RETENTION). Supports resampling via method/window, reverse ordering, and a max count capped at 10,000 per UUID. Set error_data=true to read the error timeseries instead.
query Parameters
layer
string

Not used starting from 3.0

uuids
Array of strings
from.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

from.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

to.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

to.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

window.seconds
string

Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. Note: these bounds are computed from: 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

window.nanos
integer <int32>

Signed fractions of a second at nanosecond resolution of the span of time. Durations less than one second are represented with a 0 seconds field and a positive or negative nanos field. For durations of one second or more, a non-zero value for the nanos field must be of the same sign as the seconds field. Must be from -999,999,999 to +999,999,999 inclusive.

method
integer <enum>
errorData
boolean

if true, return data from the error series and not the data series

count
integer <int32>
reverse
boolean

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

AddPointsData

  • Ingests timeseries values and/or errors for a single point UUID. Values are written to Redis TimeSeries and the on-disk WAL (for ObserveDataUpdates). Errors are written to a separate WAL and kept in a per-point Redis list capped at POINT_ERRORS_RETENTION (default 5). Supports is_async mode which enqueues the work and returns a task_uuid immediately.
Request Body schema: application/json
Array of objects (normalgw.hpl.v1.Error)
isAsync
boolean
layer
string

Not used starting from 3.0

uuid
string
Array of objects (normalgw.hpl.v1.Value)

Responses

Request samples

Content type
application/json
{
  • "errors": [
    ],
  • "isAsync": true,
  • "layer": "string",
  • "uuid": "string",
  • "values": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "taskUuid": "string"
}

CreateDataExport

  • Creates a timeseries data export job and returns a download_path. Exports resampled data as gzipped CSV (optionally grouped into a ZIP by group_key). Export requests expire after 24 hours.
query Parameters
structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
columnHeaders
Array of strings

column to use as the header

headersSeparator
string
format
integer <enum>

file format

from.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

from.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

to.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

to.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

window.seconds
string

Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. Note: these bounds are computed from: 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

window.nanos
integer <int32>

Signed fractions of a second at nanosecond resolution of the span of time. Durations less than one second are represented with a 0 seconds field and a positive or negative nanos field. For durations of one second or more, a non-zero value for the nanos field must be of the same sign as the seconds field. Must be from -999,999,999 to +999,999,999 inclusive.

method
integer <enum>
groupKey
string

Responses

Response samples

Content type
application/json
{
  • "downloadPath": "string"
}

GetPointErrors

  • Returns the most recent errors stored for each UUID, from a per-point Redis list. The default retention is the last 5 errors per point (configurable via POINT_ERRORS_RETENTION).
query Parameters
uuids
Array of strings

Responses

Response samples

Content type
application/json
{
  • "errors": [
    ]
}

CreateExport

  • Creates a point metadata export job and returns a download_path. The actual CSV file is generated on demand when the download path is fetched. If no mask is provided, all attribute keys across the layer's components are included. Export requests expire after 24 hours.
query Parameters
layer
string

layer to export

structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
masks.attrIncludeMask
Array of strings

applies to attributes: if blank

masks.attrExcludeMask
Array of strings
masks.fieldMask
Array of strings

applies to proto fields

masks.fieldExcludeMask
Array of strings
format
integer <enum>

format

Responses

Response samples

Content type
application/json
{
  • "downloadPath": "string"
}

GetDistinctAttrKeys

  • Returns distinct attribute key names and how many points have each key set to a non-blank value. Uses precomputed sorted sets in Redis (not a full scan), so it is fast but counts may lag behind real-time. If an attribute list is provided, only those keys are returned.
query Parameters
attrs
Array of strings
query
string
structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
layer
string
queryLayer
string
pageOffset
string
pageSize
string

Responses

Response samples

Content type
application/json
{
  • "attrs": [
    ]
}

GetLayers

  • Returns all layers if no name is given, or a single layer by name. Each layer includes a live point_count computed at query time via FT.SEARCH.
query Parameters
name
string

Responses

Response samples

Content type
application/json
{
  • "layers": [
    ],
  • "totalCount": "string"
}

CreateLayer

  • Creates a new BASE or UNION layer. Layer names must be alphanumeric with colons only. If indexed is true, a RediSearch index is created synchronously before returning. Creating a BASE layer triggers an async rebuild of the "default" union layer. Returns AlreadyExists if the layer name is taken.
Request Body schema: application/json
object (normalgw.hpl.v1.Layer)

Responses

Request samples

Content type
application/json
{
  • "layer": {
    }
}

Response samples

Content type
application/json
{ }

DeleteLayer

  • Drops the layer's RediSearch index and removes its definition from Redis. Underlying point data (hashes and timeseries) are always preserved (KEEPDOCS). Deleting a non-"default" layer triggers an async rebuild of the "default" union layer.
path Parameters
name
required
string

Responses

Response samples

Content type
application/json
{ }

GetLayers

  • Returns all layers if no name is given, or a single layer by name. Each layer includes a live point_count computed at query time via FT.SEARCH.
path Parameters
name
required
string

Responses

Response samples

Content type
application/json
{
  • "layers": [
    ],
  • "totalCount": "string"
}

DeletePoints

  • Deletes points by UUID list and/or structured query. Removes the point hash, timeseries keys, and distinct-value counters, and appends a deletion record (old set, new nil) to the update stream. The deprecated layers field is no longer supported and returns InvalidArgument if set.
query Parameters
layers
Array of strings

points will be deleted in these layers. you can only delete points from a base layer. if the list is empty, the point will be deleted in all layers

uuids
Array of strings

delete these uuids

indexLayer
string

delete points matching this query

structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string

Responses

Response samples

Content type
application/json
{
  • "deleteCount": "string"
}

GetPoints

  • Searches for points using the RediSearch full-text index on the specified layer. The layer must be indexed; defaults to "default" (a union of all base layers). Supports structured queries, pagination, sorting (sort field must be indexed), attribute/field masks, and annotation joins.
Request Body schema: application/json
Array of objects (normalgw.hpl.v1.Annotation)
layer
string

which layer to query the index on

object (normalgw.hpl.v1.PointMask)
pageOffset
string

pagination options

pageSize
string
query
string

text query to search for in the database deprecated in 1.6; use structured_query instead

responseFormat
integer <enum>
resultLayer
string

if set, only return results which are from this layer. this impacts the behavior of the pagination fields, since since these are applied first during the query lookup. However, it can be used to query keys which appear in multiple layers without duplicates

object (normalgw.hpl.v1.Sort)
sortField
string
sortOrder
string
object (normalgw.hpl.v1.Query)

Responses

Request samples

Content type
application/json
{
  • "annotations": [
    ],
  • "layer": "string",
  • "masks": {
    },
  • "pageOffset": "string",
  • "pageSize": "string",
  • "query": "string",
  • "responseFormat": 0,
  • "resultLayer": "string",
  • "sort": {
    },
  • "sortField": "string",
  • "sortOrder": "string",
  • "structuredQuery": {
    }
}

Response samples

Content type
application/json
{
  • "points": [
    ],
  • "totalCount": "string"
}

UpdatePoints

  • Creates or updates point metadata. Updates are enqueued to an internal work queue and executed with optimistic concurrency (Redis WATCH). By default the call blocks until the update is applied; set is_async=true to return immediately with a task_uuid. Fields marked not_updatable in the Point message are silently ignored.
Request Body schema: application/json
isAsync
boolean
Array of objects (normalgw.hpl.v1.Point)

Update points in the database. The UUID is mandatory. Other fields will be updated if not null.

Responses

Request samples

Content type
application/json
{
  • "isAsync": true,
  • "points": [
    ]
}

Response samples

Content type
application/json
{
  • "results": [
    ]
}

GetPointsById

  • Looks up points by UUID list. Skips any UUIDs that are not found rather than returning an error. Does not support pagination or sorting; total_count reflects only the points actually returned.
query Parameters
layer
string
uuids
Array of strings
responseFormat
integer <enum>
masks.attrIncludeMask
Array of strings

applies to attributes: if blank

masks.attrExcludeMask
Array of strings
masks.fieldMask
Array of strings

applies to proto fields

masks.fieldExcludeMask
Array of strings

Responses

Response samples

Content type
application/json
{
  • "points": [
    ],
  • "totalCount": "string"
}

GetPoints

  • Searches for points using the RediSearch full-text index on the specified layer. The layer must be indexed; defaults to "default" (a union of all base layers). Supports structured queries, pagination, sorting (sort field must be indexed), attribute/field masks, and annotation joins.
query Parameters
layer
string

which layer to query the index on

resultLayer
string

if set, only return results which are from this layer. this impacts the behavior of the pagination fields, since since these are applied first during the query lookup. However, it can be used to query keys which appear in multiple layers without duplicates

query
string

text query to search for in the database deprecated in 1.6; use structured_query instead

structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
responseFormat
integer <enum>
masks.attrIncludeMask
Array of strings

applies to attributes: if blank

masks.attrExcludeMask
Array of strings
masks.fieldMask
Array of strings

applies to proto fields

masks.fieldExcludeMask
Array of strings
pageOffset
string

pagination options

pageSize
string
sortField
string
sortOrder
string
sort.field
string
sort.order
string
sort.layer
string

Responses

Response samples

Content type
application/json
{
  • "points": [
    ],
  • "totalCount": "string"
}

RenamePoint

  • Changes a point's UUID, atomically renaming the metadata hash and timeseries key in Redis. Publishes an update record with old and new UUIDs to the points update stream. This can be disruptive as not all consumers handle UUID changes gracefully.
Request Body schema: application/json
layer
string
newUuid
string
oldUuid
string

Responses

Request samples

Content type
application/json
{
  • "layer": "string",
  • "newUuid": "string",
  • "oldUuid": "string"
}

Response samples

Content type
application/json
{ }

GetDataSummary

  • Computes statistics (min, max, mean, median, distinct count, histogram) over timeseries data for the given UUIDs and time range. Histogram bins are auto-computed from distinct values or bucket_count; for enum points, bins map 1:1 to enum values. Loads all data into memory so performance depends on the data volume in the time window.
query Parameters
layer
string
uuids
Array of strings
from.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

from.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

to.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

to.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

bucketEdges
Array of numbers <float> [ items <float > ]

if not empty, bucket edges for the histogram. can be used to use the same edges for all points in the request

bucketCount
integer <uint32>

Responses

Response samples

Content type
application/json
{
  • "summaries": [
    ]
}

DeleteTags

  • Removes tag values from comma-separated tag fields. Passing a tag with an empty value string clears all tags for that key. Uses the same underlying mechanism as AddTags.
Request Body schema: application/json
layer
string
Array of objects (normalgw.hpl.v1.Tag)
uuids
Array of strings

Responses

Request samples

Content type
application/json
{
  • "layer": "string",
  • "tags": [
    ],
  • "uuids": [
    ]
}

Response samples

Content type
application/json
{ }

AddTags

  • Atomically adds individual tag values within comma-separated tag fields, avoiding the need for client-side read-modify-write. The layer must be a BASE layer. Tags are deduplicated and sorted alphabetically on write.
Request Body schema: application/json
layer
string
Array of objects (normalgw.hpl.v1.Tag)
uuids
Array of strings

Responses

Request samples

Content type
application/json
{
  • "layer": "string",
  • "tags": [
    ],
  • "uuids": [
    ]
}

Response samples

Content type
application/json
{ }

ObserveDataUpdates

  • Server-streaming RPC that emits new data values from an on-disk WAL. Designed for reliable archival to external databases; default WAL retention is one month. Also emits synthetic ADDED/DELETED/METADATA events when a structured_query filter's membership changes. If with_metadata is set, point metadata is fetched at send time (not at collection time), so it may not reflect the state when the value was recorded.
query Parameters
layer
string
uuids
Array of strings
version
string
limit
integer <int32>
wait
boolean

whether to wait for new records

withMetadata
boolean

if point metadata should be included with each reply value.

structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string

Responses

Response samples

Content type
application/json
{
  • "layer": "string",
  • "point": {
    },
  • "type": 0,
  • "uuid": "string",
  • "value": {
    },
  • "version": "string"
}

ObserveErrorUpdates

  • Server-streaming RPC that emits polling errors from an on-disk WAL. Default WAL retention is one month. Supports the same version/limit/wait/layer/UUID/query filtering as ObserveDataUpdates.
query Parameters
layer
string
uuids
Array of strings
version
string
limit
integer <int32>
wait
boolean

whether to wait for new records

withMetadata
boolean
structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string

Responses

Response samples

Content type
application/json
{
  • "error": {
    },
  • "layer": "string",
  • "point": {
    },
  • "uuid": "string",
  • "version": "string"
}

ObservePointsUpdates

  • Server-streaming RPC that emits point metadata changes from a Redis Stream. Each message contains old/new point snapshots and the list of changed fields. By default starts at the stream head ($); set version to "0-0" to replay from the beginning. Supports filtering by layer, UUIDs, or structured_query (via a background QueryWatcher). Set wait=false for a non-blocking one-shot read.
query Parameters
layer
string

only include updates for a particular layer

uuids
Array of strings

only include updates for a set of uuids

version
string

only retrieve changes since this version

limit
integer <int32>

how many records to send before closing the connection. if zero, never close the connection.

wait
boolean

whether to wait for new records

structuredQuery.field.property
string
structuredQuery.field.text
string
structuredQuery.field.numeric.minValue
number <double>
structuredQuery.field.numeric.minInfinity
boolean
structuredQuery.field.numeric.maxValue
number <double>
structuredQuery.field.numeric.maxInfinity
boolean
structuredQuery.field.layer
string
structuredQuery.field.wildcard
boolean
structuredQuery.reference.property
string
structuredQuery.reference.targetProperty
string
structuredQuery.reference.query.field.property
string
structuredQuery.reference.query.field.text
string
structuredQuery.reference.query.field.numeric.minValue
number <double>
structuredQuery.reference.query.field.numeric.minInfinity
boolean
structuredQuery.reference.query.field.numeric.maxValue
number <double>
structuredQuery.reference.query.field.numeric.maxInfinity
boolean
structuredQuery.reference.query.field.layer
string
structuredQuery.reference.query.field.wildcard
boolean
structuredQuery.reference.query.reference.property
string
structuredQuery.reference.query.reference.targetProperty
string
withMetadata
boolean

Responses

Response samples

Content type
application/json
{
  • "current": {
    },
  • "fields": [
    ],
  • "layers": [
    ],
  • "new": {
    },
  • "old": {
    },
  • "ts": "2019-08-24T14:15:22Z",
  • "version": "string"
}

GetVersions

  • Returns the latest version IDs for the three update streams (data, points, errors). Use these as the starting point for Observe* RPCs to avoid replaying old records.

Responses

Response samples

Content type
application/json
{
  • "dataVersion": "string",
  • "errorsVersion": "string",
  • "pointsVersion": "string"
}

AddData

  • Batched form of AddPointsData. Carries any number of (uuid, values, errors) tuples in one request; the server pipelines all writes into a single redis round trip and (in is_async mode) one queue task. This is the right call for any producer that already has a batch on hand — a 1000-point poll cycle goes from ~4000 RTTs to ~4.
Request Body schema: application/json
isAsync
boolean
layer
string

Layer is propagated into each ObserveDataUpdatesReply so that subscribers filtering by layer/components see only their points. All points in this batch share the same layer; mix-and-match requires multiple calls.

Array of objects (normalgw.hpl.v1.AddDataRequest_PointData)

Responses

Request samples

Content type
application/json
{
  • "isAsync": true,
  • "layer": "string",
  • "points": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "taskUuid": "string"
}

Scan

The BACnet scan services performs device discovery for the BACnet subsystem. This includes network and device scans, periodic rescans, the tracking of device database state, and managing the import of objects into the points database.

GetRenamedDevices

  • Returns a paginated list of device rename records, showing old-to-new UUID mappings along with the timestamp and point metadata from both the old and new devices.
query Parameters
pageOffset
string
pageCount
string

Responses

Response samples

Content type
application/json
{
  • "renamed": [
    ],
  • "totalCount": "string"
}

RenameDevice

  • Creates a device rename mapping from old_uuid to new_uuid, and migrates all child points to the new device namespace by recomputing their UUIDs. This is used when replacing a physical controller so that points retain continuity. The rename record is persisted in Redis.
Request Body schema: application/json
newUuid
string

the device uuid

oldUuid
string

the old device uuid

updateNewPoints
boolean

if we should find all points with uuids based on the old namespace and update them to point at the new namespace.

Responses

Request samples

Content type
application/json
{
  • "newUuid": "string",
  • "oldUuid": "string",
  • "updateNewPoints": true
}

Response samples

Content type
application/json
{
  • "pointsRenamed": "string"
}

DeleteRenamedDevice

  • Removes a device rename record from Redis. Does not undo the point migrations that were performed by RenameDevice. Returns INVALID_ARGUMENT if old_uuid is not a valid UUID.
path Parameters
oldUuid
required
string

Responses

Response samples

Content type
application/json
{ }

RestartJobs

  • Re-submits jobs by creating new jobs with the same parameters as the originals. Silently skips any job IDs that are not found or cannot be loaded. Returns the IDs of the newly created jobs.
Request Body schema: application/json
ids
Array of integers <uint32> [ items <uint32 > ]

Responses

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

Response samples

Content type
application/json
{
  • "ids": [
    ]
}

GetJobs

  • Retrieves scan jobs from Redis with filtering (by status, type, device, parent), sorting (by id, status, queued_at), and pagination. By default returns jobs without full device/object results; set full=true to include scan results. Defaults to 25 results per page sorted by id DESC.
query Parameters
statusFilter
integer <enum>
idFilter
integer <uint32>
parentIdFilter
integer <uint32>
typeFilter
string
deviceFilter
string
full
boolean
sortField
string

supports id, status, queued_at,

sortOrder
string

ASC or DESC

pageOffset
string
pageSize
string

Responses

Response samples

Content type
application/json
{
  • "results": [
    ],
  • "totalCount": "string"
}

StartJob

  • Enqueues a new scan job. Exactly one of device, object, or network scan must be specified. Object scans require a target device address. Network scan parameters are validated before enqueuing. Jobs are distributed across per-network queues to avoid starvation from slow networks. Returns the created job with its assigned ID.
Request Body schema: application/json
autoImport
boolean
object (google.protobuf.Duration)

A Duration represents a signed, fixed-length span of time represented as a count of seconds and fractions of seconds at nanosecond resolution. It is independent of any calendar and concepts like "day" or "month". It is related to Timestamp in that the difference between two Timestamp values is a Duration and it can be added or subtracted from a Timestamp. Range is approximately +-10,000 years. # Examples Example 1: Compute Duration from two Timestamps in pseudo code. Timestamp start = ...; Timestamp end = ...; Duration duration = ...; duration.seconds = end.seconds - start.seconds; duration.nanos = end.nanos - start.nanos; if (duration.seconds < 0 && duration.nanos > 0) { duration.seconds += 1; duration.nanos -= 1000000000; } else if (duration.seconds > 0 && duration.nanos < 0) { duration.seconds -= 1; duration.nanos += 1000000000; } Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. Timestamp start = ...; Duration duration = ...; Timestamp end = ...; end.seconds = start.seconds + duration.seconds; end.nanos = start.nanos + duration.nanos; if (end.nanos < 0) { end.seconds -= 1; end.nanos += 1000000000; } else if (end.nanos >= 1000000000) { end.seconds += 1; end.nanos -= 1000000000; } Example 3: Compute Duration from datetime.timedelta in Python. td = datetime.timedelta(days=3, minutes=10) duration = Duration() duration.FromTimedelta(td) # JSON Mapping In JSON format, the Duration type is encoded as a string rather than an object, where the string ends in the suffix "s" (indicating seconds) and is preceded by the number of seconds, with nanoseconds expressed as fractional seconds. For example, 3 seconds with 0 nanoseconds should be encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should be expressed in JSON format as "3.000000001s", and 3 seconds and 1 microsecond should be expressed in JSON format as "3.000001s".

clientId
string
object (normalgw.bacnet.v1.DeviceScanJob)

Device Scan Jobs find BACnet servers (device objects) on the network and obtain a basic set of properties from them.

object (normalgw.bacnet.v1.NetworkScanJob)

One must be somewhat careful since it is easy enough to simulate a denial of service attack with this tool.

object (normalgw.bacnet.v1.ObjectScanJob)

Object Scan Jobs look at existing BACnet servers and read out their object list.

parentId
integer <uint32>

Responses

Request samples

Content type
application/json
{
  • "autoImport": true,
  • "autoPoll": {
    },
  • "clientId": "string",
  • "device": {
    },
  • "network": {
    },
  • "object": {
    },
  • "parentId": 0
}

Response samples

Content type
application/json
{
  • "autoImport": true,
  • "autoPoll": {
    },
  • "clientId": "string",
  • "device": {
    },
  • "deviceResult": [
    ],
  • "id": 0,
  • "imported": true,
  • "network": {
    },
  • "object": {
    },
  • "objectCount": {
    },
  • "objectResult": [
    ],
  • "parentId": 0,
  • "status": 0,
  • "statusMessage": "string",
  • "timestamps": {
    }
}

CancelJob

  • Cancels a pending or running scan job. Pending jobs are removed from the queue; running jobs are canceled via context cancellation. Returns FAILED_PRECONDITION if the job is already done, canceled, or in error.
Request Body schema: application/json
jobId
integer <uint32>

Responses

Request samples

Content type
application/json
{
  • "jobId": 0
}

Response samples

Content type
application/json
{
  • "jobId": 0,
  • "status": 0,
  • "statusMessage": "string"
}

GetScanDeltas

  • Streams computed deltas (created/modified/missing devices and objects) derived from completed scan jobs. Only DONE jobs generate deltas. The first record for each device/object is always a "create" so clients can reconstruct current state by replaying from the beginning. Supports filtering by device_id and device_only/object_only flags. The stream closes after all available deltas are sent.
query Parameters
version
string

If set, start scanning for deltas at a particular scan version

sinceTime.seconds
string

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.

sinceTime.nanos
integer <int32>

Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive.

deviceId
Array of integers <uint32> [ items <uint32 > ]

filter object scans to only include the set of included device ids.

objectOnly
boolean

only send object deltas

deviceOnly
boolean

only send device deltas

Responses

Response samples

Content type
application/json
{
  • "deviceDelta": {
    },
  • "jobId": 0,
  • "objectDelta": {
    },
  • "version": "string"
}

ObserveJobUpdates

  • Streams job state changes from a Redis stream. Supply a version token to resume from a previous position, or omit to start from the latest. Set wait=true to long-poll for new updates; otherwise the stream closes after delivering available entries. By default strips device/object results for compactness; set full=true to include them.
query Parameters
version
string

Sync token to only request new jobs. If nil or empty, will return all jobs available (since the beginning of time). Since the job stream may expire jobs due to memory pressures you may not be sure this is all jobs; use GetJobs.

limit
integer <int32>
wait
boolean
full
boolean

Responses

Response samples

Content type
application/json
{
  • "job": {
    },
  • "version": "string"
}

DeleteJob

  • Deletes a completed scan job and all its associated Redis index entries. Returns FAILED_PRECONDITION if the job is still running; returns NOT_FOUND if the job does not exist.
path Parameters
jobId
required
integer <uint32>

Responses

Response samples

Content type
application/json
{ }

Status

The Device Status service monitors the error rates of devices, and provides device health statistics to consumers.

DeleteDevices

  • Deletes devices and all their associated points from the points database, along with their error statistics and status tracking data in Redis. Accepts a list of device UUIDs.
query Parameters
uuids
Array of strings

Responses

Response samples

Content type
application/json
{
  • "deleteCount": "string"
}

GetDeviceStatus

  • Returns paginated device health status including error rates, last-alive timestamps, and error status (GREEN/YELLOW/RED/GRAY). Sortable by last_alive or current_error_rate. When error_filter is set, automatically sorts by error rate. Set return_timeseries=true to include per-device error history and site-wide error count time series.
query Parameters
layer
string
errorFilter
integer <enum>

only return devices with a particular error status

returnTimeseries
boolean

return the error timeseries in addition to the current values

sortField
string

possibilities are last_alive or current_error_rate

sortOrder
string
pageOffset
string
pageSize
string
nameFilter
string

server-side filter: only return devices whose name or device_id contains this substring (case-insensitive)

Responses

Response samples

Content type
application/json
{
  • "errorHistory": [
    ],
  • "results": [
    ],
  • "totalCount": "string"
}

GetPointDQStatus

query Parameters
deviceUuid
string

Responses

Response samples

Content type
application/json
{
  • "pointStatuses": {
    }
}

GetDeviceStatusSummary

query Parameters
layer
string

Responses

Response samples

Content type
application/json
{
  • "grayCount": "string",
  • "greenCount": "string",
  • "redCount": "string",
  • "yellowCount": "string"
}

GetErrorSummary

  • Returns a summary of errors within a time window (default 1 hour), broken down by error type and by device. If device_uuid is set, scopes the error type counts to that device. Device errors are sorted by error rate ascending.
query Parameters
layer
string
deviceUuid
string
window.seconds
string

Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. Note: these bounds are computed from: 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years

window.nanos
integer <int32>

Signed fractions of a second at nanosecond resolution of the span of time. Durations less than one second are represented with a 0 seconds field and a positive or negative nanos field. For durations of one second or more, a non-zero value for the nanos field must be of the same sign as the seconds field. Must be from -999,999,999 to +999,999,999 inclusive.

Responses

Response samples

Content type
application/json
{
  • "deviceErrors": [
    ],
  • "errorCounts": {
    }
}