Skip to main content

Johnson Controls Metasys

GEM connects to Johnson Controls Metasys ADS / ADX / OAS servers through the Metasys REST API. Each Metasys object (a BACnet point behind an NAE/NCE/SNE engine, an AV/BV/analog value, a schedule value) can be surfaced as a GEM zone, with present-value reads and writes flowing over HTTPS with a bearer token.

Use this driver when a site already has a Metasys front end managing the mechanical plant and the goal is to surface a handful of setpoints, fan/lighting overrides, or space temperatures on a GEM dashboard — without dropping a second BACnet client onto the JCI trunk.

note

This is a supervisory integration. GEM talks to the Metasys server, not directly to the field bus. Anything the Metasys server does not publish as an object is not reachable here. For direct field-bus access, use the BACnet integration instead.

Prerequisites

  • A Metasys server (ADS, ADX, or OAS) at release 10.0 or later. The REST API ships with the server — there is no separate install or license part number to add, but older releases expose older API versions (see api_version below).
  • A Metasys user account authorized for API access. Local Metasys accounts work; Active Directory accounts must be entered in the exact domain form the site uses to sign in to the Metasys UI.
  • The account needs write authorization on any object GEM will command. A read-only account can still poll zone state — writes come back as http 403.
  • Network reachability from the GEM controller to the Metasys server on the HTTPS listener (normally 443).

Setup

  1. Add a device with driver metasys.
  2. Set ip to the Metasys server hostname or IP, and port to the HTTPS listener (default 443).
  3. Set username and password to the API-authorized Metasys account. The password is encrypted at rest.
  4. Set api_version to match the server release — v4 on Metasys 11/12, v3 or v2 on older servers. A mismatch shows up as every call returning http 404.
  5. Save and enable the device. On connect the driver posts to /api/<version>/login and stores the returned bearer token.
  6. From the script console, run get_objects to page the server's object list. Each page is indexed in memory so item references become usable as zone addresses.
  7. Walk deeper with get_children on any object id to find the specific points you want.
  8. Create a zone per point, with zone.address set to the object id (GUID) or an indexed item reference.
  9. Set the zone's point_type (and on_value / off_value for binary points) so on / off / set_level encode the value the way that object expects.

Attribute Reference

Device

NameTypeRequiredDefaultNotes
ipstringyesMetasys server hostname or IP.
usernamestringyesAPI-authorized Metasys account.
passwordstringyesEncrypted at rest.
portintno443HTTPS listener port.
protocolstringnohttpsMetasys publishes over HTTPS; only change this for a lab proxy. Self-signed certs are accepted.
api_versionstringnov4API version segment in the URL (v2v5). Match the server release.
status_intervalintno60000How often each zone's point attribute is re-read, in ms.

Zone

NameTypeRequiredDefaultNotes
addressstringyesObject id (GUID) or an indexed item reference.
point_attributestringnopresentValueWhich Metasys attribute this zone reads and writes.
point_typestringnoboolbool, number, or string — controls how on/off/set_level encode the written value.
on_valuestringnoValue written by on. Leave empty for the point_type default (true / 1).
off_valuestringnoValue written by off. Leave empty for the point_type default (false / 0).

Zone Address Format

zone.address is a Metasys object id — a GUID:

11111111-2222-3333-4444-555555555555

An item reference may be used instead:

Site:NAE1/N2-1.AHU-1.ZN-T

Item references only resolve after a discovery run. The driver builds an in-memory map of itemReference → id from every get_objects / get_children / get_network_devices response, and that map is rebuilt from empty on each device reload. A GUID address always works and never depends on discovery — prefer it for anything permanent.

If an address cannot be resolved, commands return unknown object; pass an object id or run get_objects first rather than silently doing nothing.

Commands

CommandArgsDescription
onaddressWrites the zone's on value to the point attribute.
offaddressWrites the zone's off value to the point attribute.
set_leveladdress, levelWrites level as a number to the point attribute.
get_pointaddress, attributeReads one attribute (default presentValue).
set_pointaddress, attribute, valuePATCHes one attribute of an object.
get_objectspage, page_size, typePages the server object list and indexes item references.
get_childrenaddress, page, page_sizeLists child objects for tree discovery.
get_network_devicespage, page_sizeLists engines / supervisory devices known to the server.
get_alarmspage, page_sizeLists current alarms.
get_commandsaddressLists the commands an object exposes.
send_commandaddress, command_id, parametersInvokes an object command; parameters is a JSON array.
api_requestpath, method, bodyRaw authenticated call against /api/<version>/<path>. Administrator only.

Who may write to which object

Unaddressed reads — get_objects, get_network_devices, get_alarms — are open to any caller with access to the device. Enumeration is how an integrator finds the object to bind a zone to in the first place.

Addressed commands — the writes (on, off, set_level, set_point, send_command) and the reads that name an object (get_point, get_children, get_commands) — are confined to objects this device has a zone for when the request comes from a UI, the REST API, or voice. The rule is enforced centrally at the command dispatch layer, so it covers every command that carries an address. An address with no matching zone returns not authorized: address is not mapped to a zone on this device.

That matters because a Metasys server fronts far more than the points a site exposes: economizer positions, chiller and boiler setpoints, AHU safety objects, and on some installs access-control and life-safety supervision points. Without the containment, any user whose UI showed a single Metasys zone could enumerate the object tree and write to all of it.

  • Administrators are not restricted — commissioning and Commands-tab testing reach any object.
  • Macros, triggers, schedules and other drivers are not restricted — existing automation is unaffected, including automation that writes to an object with no zone.
  • api_request is a raw passthrough carrying the driver's bearer token, so it is administrator-only outright. A non-elevated caller gets not authorized.

path is always resolved relative to this device's /api/<version>/ prefix. An absolute URL pasted into path is reduced to its path component and applied to this server — it cannot be used to send the bearer token somewhere else.

Writing a setpoint

command: set_point
args: {address: "11111111-2222-3333-4444-555555555555", attribute: "presentValue", value: 72.5}

Sending an object command

send_command is the path for anything that is not a plain attribute write — overrides, releases, alarm enables. Discover the object's command ids first:

command: get_commands
args: {address: "11111111-2222-3333-4444-555555555555"}

then invoke one with its parameter list:

command: send_command
args: {address: "11111111-2222-3333-4444-555555555555", command_id: "Release", parameters: "[]"}

Authentication and Tokens

The driver exchanges username / password for a bearer token at /api/<version>/login, then:

  • refreshes the token five minutes before the expiry the server reported (or every 20 minutes if the server sent no expiry),
  • re-logs-in automatically if a refresh fails,
  • retries a request once after re-authenticating if it comes back 401 mid-flight.

Tokens are held in memory only — they are never written to the database, and a device reload starts a fresh login.

warning

Repeated bad passwords will trip the site's Metasys account lockout policy the same way a human sign-in would. If the device is flapping on http 401, disable it before troubleshooting the credential.

Known Limitations

  • Writes land at the default priority. A present-value PATCH does not carry a BACnet write priority. When a site needs an explicit priority — a true override that survives the sequence — use send_command with the object's Operator Override / Release commands instead.
  • Binary point encoding varies by release. Some servers accept and return true / false; others use enum strings such as attributeEnumSet.binaryPvEnum.bacbinActive. Run get_point against the object, see what comes back, and set the zone's on_value / off_value to match.
  • No change-of-value subscription. State comes from polling on status_interval. Metasys does expose a stream/subscription mechanism; this driver does not consume it yet, so a large zone count means a slow round-robin — the poll paces itself at 200 ms per zone.
  • Discovery endpoint shapes drift across API versions. get_children, get_network_devices, and get_alarms are modeled against the v4 paging contract (page / pageSize, {total, items}). On an older server, a 404 or an unexpected body means that endpoint moved — reach it with api_request and the path from the release's own API reference.
  • Zone level is rounded. A numeric present value is mirrored to the zone level attribute as an integer; the unrounded value is still available from get_point.
  • No alarm-spine wiring. get_alarms returns the list on demand; Metasys alarms are not yet raised as GEM alarms.

Troubleshooting

SymptomCheck
login http 401Confirm the account can sign in to the Metasys UI. AD accounts must use the exact domain form the site uses.
Every call returns http 404api_version does not match the server release. Try v3 or v2 on pre-11 servers.
unknown object on a zone commandRun get_objects to index item references, or put the object GUID in zone.address.
not authorized: address is not mapped to a zone on this deviceThe command targets an object with no GEM zone on this device. Create the zone, or run the command as an administrator. See Who may write to which object.
not authorized on api_requestapi_request is administrator-only.
Writes return http 403The API account is read-only on that object. Metasys authorization is per-category and per-object, so read access does not imply write access.
Connect fails with a TLS errorSelf-signed certificates are accepted by default, so a hard TLS failure usually means port is not the HTTPS listener.
Zone state never updatesConfirm get_point returns a value for that address, and that point_attribute matches an attribute the object actually publishes.