<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.29 (Ruby 3.4.5) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

<!ENTITY RFC7644 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7644.xml">
<!ENTITY I-D.ietf-scim-device-model SYSTEM "https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-scim-device-model.xml">
<!ENTITY RFC2119 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY RFC8174 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
<!ENTITY I-D.ietf-asdf-sdf SYSTEM "https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-asdf-sdf.xml">
<!ENTITY I-D.mohan-asdf-sdf-protocol-mapping SYSTEM "https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.mohan-asdf-sdf-protocol-mapping.xml">
<!ENTITY RFC9114 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9114.xml">
<!ENTITY RFC7159 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7159.xml">
<!ENTITY RFC8949 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8949.xml">
<!ENTITY RFC3986 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml">
<!ENTITY RFC6570 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6570.xml">
<!ENTITY RFC9457 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9457.xml">
<!ENTITY RFC4648 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml">
<!ENTITY RFC8610 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8610.xml">
<!ENTITY RFC8126 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml">
<!ENTITY RFC8615 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8615.xml">
]>


<rfc ipr="trust200902" docName="draft-ietf-asdf-nipc-12" category="std" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="NIPC">An Application Layer Interface for Non-IP device control (NIPC)</title>

    <author initials="B." surname="Brinckman" fullname="Bart Brinckman">
      <organization>Cisco Systems</organization>
      <address>
        <postal>
          <city>Brussels</city>
          <country>Belgium</country>
        </postal>
        <email>bbrinckm@cisco.com</email>
      </address>
    </author>
    <author initials="R." surname="Mohan" fullname="Rohit Mohan">
      <organization>Cisco Systems</organization>
      <address>
        <postal>
          <street>170 West Tasman Drive</street>
          <city>San Jose</city>
          <code>95134</code>
          <country>USA</country>
        </postal>
        <email>rohitmo@cisco.com</email>
      </address>
    </author>
    <author initials="B." surname="Sanford" fullname="Braeden Sanford">
      <organization>Philips</organization>
      <address>
        <postal>
          <city>Cambridge</city>
          <country>USA</country>
        </postal>
        <email>braeden.sanford@philips.com</email>
      </address>
    </author>

    <date year="2025" month="August" day="19"/>

    
    
    <keyword>Internet-Draft</keyword>

    <abstract>


<?line 61?>

<t>This memo specifies RESTful application layer interface for gateways 
providing operations against non-IP devices, as well as a CBOR-based 
publish-subscribe interface for streaming data. The described interfaces are
extensible.</t>



    </abstract>



  </front>

  <middle>


<?line 68?>

<section anchor="introduction"><name>Introduction</name>

<section anchor="scope"><name>Scope</name>

<t>Low-power sensors, actuators and other connected devices introduced in
environments and use cases such as building management, healthcare, workplaces,
manufacturing, logistics and hospitality are often battery-powered. With 
limited power budget, they may not be able to support the IP protocol on their
wired or wireless interfaces, hence they support protocols that require a lower
power budget. Promiment examples of such protocols are <xref target="BLE53"/> and
<xref target="Zigbee22"/>. These devices typically do require to communicate with devices
or applications that are connected to IP-based networking infrastructure. 
Therefore, applications on the IP network that need to communicate or receive
telemetry from these non-IP low-power devices must do so through a gateway 
function on the IP network. This gateway functions then translates the 
communication to the non-IP protocol that the low-power device supports.</t>

<figure title="Gateway for non-IP Devices" anchor="gw"><artset><artwork  type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="144" width="688" viewBox="0 0 688 144" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
<path d="M 8,48 L 8,96" fill="none" stroke="black"/>
<path d="M 120,48 L 120,96" fill="none" stroke="black"/>
<path d="M 240,48 L 240,96" fill="none" stroke="black"/>
<path d="M 320,48 L 320,96" fill="none" stroke="black"/>
<path d="M 440,48 L 440,96" fill="none" stroke="black"/>
<path d="M 512,48 L 512,96" fill="none" stroke="black"/>
<path d="M 8,48 L 120,48" fill="none" stroke="black"/>
<path d="M 240,48 L 320,48" fill="none" stroke="black"/>
<path d="M 440,48 L 512,48" fill="none" stroke="black"/>
<path d="M 128,64 L 232,64" fill="none" stroke="black"/>
<path d="M 328,64 L 432,64" fill="none" stroke="black"/>
<path d="M 8,96 L 120,96" fill="none" stroke="black"/>
<path d="M 240,96 L 320,96" fill="none" stroke="black"/>
<path d="M 440,96 L 512,96" fill="none" stroke="black"/>
<polygon class="arrowhead" points="440,64 428,58.4 428,69.6" fill="black" transform="rotate(0,432,64)"/>
<polygon class="arrowhead" points="336,64 324,58.4 324,69.6" fill="black" transform="rotate(180,328,64)"/>
<polygon class="arrowhead" points="240,64 228,58.4 228,69.6" fill="black" transform="rotate(0,232,64)"/>
<polygon class="arrowhead" points="136,64 124,58.4 124,69.6" fill="black" transform="rotate(180,128,64)"/>
<g class="text">
<text x="64" y="68">Application</text>
<text x="280" y="68">Gateway</text>
<text x="476" y="68">Non-IP</text>
<text x="180" y="84">IP-based</text>
<text x="380" y="84">Non-IP</text>
<text x="476" y="84">Device</text>
<text x="184" y="100">Operation</text>
<text x="384" y="100">Operation</text>
</g>
</svg>
</artwork><artwork  type="ascii-art"><![CDATA[
                                                               
    +-------------+              +---------+              +--------+
    | Application |<------------>| Gateway |<------------>| Non-IP |                     
    |             |   IP-based   |         |    Non-IP    | Device |
    +-------------+   Operation  +---------+   Operation  +--------+                 

]]></artwork></artset></figure>

<t>There have been efforts to define Gateway functions for devices that support
a particular protocol, such as a BLE GATT REST API for BLE Gateways
(<xref target="Gatt-REST-API"/>), however they have been limited to a single protocol or
a particular use case. In absence of an open standard describing how
applications on an IP network communicate with non-IP devices, bespoke and
vendor-specific implementations have proliferated. This results in parallel
infrastructure of both gateways and non-IP networks being deployed on a case
by case basis, each connecting separately into the IP network, with a distinct
set of APIs. At the same time, wireless access points supporting both IP-based 
wireless connectivity as well as non-IP based wireless technologies are
deployed ubiquitiously. Many of these wireless access points are equipped with
radios that can transmit and receive different frame types, such as <xref target="BLE53"/>
and <xref target="Zigbee22"/>. This specification aims to define a Gateway API for these 
Non-IP protocols that can be leveraged by this wireless infrastructure in order
to connect Non-IP devices into IP networks. The specification aims to be
extensible, in order to support existing and future non-IP protocols.</t>

<t>A standardized Non-IP Gateway interface has following benefits:</t>

<t><list style="symbols">
  <t>Avoid the need for parallel Non-IP infrastructure.</t>
  <t>Avoid the need for applications to perform bespoke integrations for
different environments.</t>
  <t>Faster and more cost-effective adoption of Non-IP devices in IP network
environments.</t>
</list></t>

</section>
<section anchor="non-ip-gateway"><name>Non-IP Gateway</name>

<t>A non-IP gateway MUST provide at least following functions:</t>

<t><list style="symbols">
  <t>Authentication and authorization of application clients that
will leverage the gateway API to communicate with Non-IP devices.</t>
  <t>Access to a database of onboarded devices. Onboarding ensures that 
the Non-IP Gateway can identify a specific device and has sufficient context
about the device to service gateway API requests.</t>
  <t>The ability to consume an interaction model for a class of devices. This 
allows the gateway to understand how to interact with a device.</t>
  <t>An API that allows for bi-directional communication to non-IP devices.</t>
  <t>One or more channels to process requests, responses, and asymmetric
communications with the non-IP radio resources (Access Points)
at its disposal.</t>
  <t>The ability to stream telemetry received from non-IP devices in real-time
to applications on the IP network.</t>
</list></t>

<t>The definition of the onboarding function is out of scope of this document, but
can be provided by a provisioning interface such as <xref target="RFC7644"/> leveraging 
<xref target="I-D.ietf-scim-device-model"/>. NIPC performs operations on a device or group
object, hence it requires device onboarding to be performed prior to performing
a NIPC operation on a device. NIPC APIs will reference a device or group id 
generated at the time of onboarding as a unique identifier.</t>

<t>The Application gateway is a network function, so its goal is to proxy payloads 
between Non-IP and IP networks. It is not intended to be a middleware function
that interprets, decodes or modifies these payloads.</t>

<figure title="Basic Architecture" anchor="arch"><artset><artwork  type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="288" width="560" viewBox="0 0 560 288" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
<path d="M 8,64 L 8,112" fill="none" stroke="black"/>
<path d="M 8,144 L 8,224" fill="none" stroke="black"/>
<path d="M 104,64 L 104,112" fill="none" stroke="black"/>
<path d="M 104,144 L 104,224" fill="none" stroke="black"/>
<path d="M 208,32 L 208,72" fill="none" stroke="black"/>
<path d="M 208,104 L 208,152" fill="none" stroke="black"/>
<path d="M 208,200 L 208,256" fill="none" stroke="black"/>
<path d="M 232,64 L 232,112" fill="none" stroke="black"/>
<path d="M 232,144 L 232,208" fill="none" stroke="black"/>
<path d="M 312,64 L 312,112" fill="none" stroke="black"/>
<path d="M 336,144 L 336,208" fill="none" stroke="black"/>
<path d="M 368,144 L 368,176" fill="none" stroke="black"/>
<path d="M 432,144 L 432,176" fill="none" stroke="black"/>
<path d="M 464,144 L 464,176" fill="none" stroke="black"/>
<path d="M 536,144 L 536,176" fill="none" stroke="black"/>
<path d="M 552,32 L 552,256" fill="none" stroke="black"/>
<path d="M 208,32 L 552,32" fill="none" stroke="black"/>
<path d="M 8,64 L 104,64" fill="none" stroke="black"/>
<path d="M 232,64 L 312,64" fill="none" stroke="black"/>
<path d="M 104,80 L 224,80" fill="none" stroke="black"/>
<path d="M 112,96 L 232,96" fill="none" stroke="black"/>
<path d="M 8,112 L 104,112" fill="none" stroke="black"/>
<path d="M 232,112 L 312,112" fill="none" stroke="black"/>
<path d="M 8,144 L 104,144" fill="none" stroke="black"/>
<path d="M 232,144 L 336,144" fill="none" stroke="black"/>
<path d="M 368,144 L 432,144" fill="none" stroke="black"/>
<path d="M 464,144 L 536,144" fill="none" stroke="black"/>
<path d="M 104,160 L 136,160" fill="none" stroke="black"/>
<path d="M 176,160 L 224,160" fill="none" stroke="black"/>
<path d="M 336,160 L 360,160" fill="none" stroke="black"/>
<path d="M 432,160 L 456,160" fill="none" stroke="black"/>
<path d="M 368,176 L 432,176" fill="none" stroke="black"/>
<path d="M 464,176 L 536,176" fill="none" stroke="black"/>
<path d="M 112,192 L 128,192" fill="none" stroke="black"/>
<path d="M 192,192 L 232,192" fill="none" stroke="black"/>
<path d="M 232,208 L 336,208" fill="none" stroke="black"/>
<path d="M 8,224 L 104,224" fill="none" stroke="black"/>
<path d="M 208,256 L 552,256" fill="none" stroke="black"/>
<polygon class="arrowhead" points="464,160 452,154.4 452,165.6" fill="black" transform="rotate(0,456,160)"/>
<polygon class="arrowhead" points="368,160 356,154.4 356,165.6" fill="black" transform="rotate(0,360,160)"/>
<polygon class="arrowhead" points="232,160 220,154.4 220,165.6" fill="black" transform="rotate(0,224,160)"/>
<polygon class="arrowhead" points="232,80 220,74.4 220,85.6" fill="black" transform="rotate(0,224,80)"/>
<polygon class="arrowhead" points="120,192 108,186.4 108,197.6" fill="black" transform="rotate(180,112,192)"/>
<polygon class="arrowhead" points="120,96 108,90.4 108,101.6" fill="black" transform="rotate(180,112,96)"/>
<g class="text">
<text x="160" y="68">Request</text>
<text x="60" y="84">onboarding</text>
<text x="268" y="84">SCIM</text>
<text x="56" y="100">app</text>
<text x="268" y="100">Server</text>
<text x="140" y="116">Ctrl</text>
<text x="184" y="116">Endpt</text>
<text x="56" y="164">Control</text>
<text x="156" y="164">REST</text>
<text x="284" y="164">NIPC</text>
<text x="396" y="164">AP</text>
<text x="500" y="164">Device</text>
<text x="56" y="180">&amp;</text>
<text x="208" y="180">|</text>
<text x="288" y="180">Gateway</text>
<text x="56" y="196">Telemetry</text>
<text x="160" y="196">pub/sub</text>
<text x="60" y="212">Apps</text>
<text x="336" y="244">Network</text>
<text x="412" y="244">Deployment</text>
</g>
</svg>
</artwork><artwork  type="ascii-art"><![CDATA[
                         +------------------------------------------+
                         |                                          |
+-----------+   Request  |  +---------+                             |
| onboarding+-------------->|  SCIM   |                             |
|    app    |<--------------+ Server  |                             |
+-----------+  Ctrl Endpt|  +---------+                             |
                         |                                          |
+-----------+            |  +------------+   +-------+   +--------+ |
|  Control  +----REST------>|    NIPC    +-->|  AP   +-->| Device | |
|     &     |            |  |   Gateway  |   +-------+   +--------+ |
| Telemetry |<--pub/sub-----+            |                          |
|    Apps   |            |  +------------+                          |
+-----------+            |                                          |
                         |            Network Deployment            |
                         +------------------------------------------+

]]></artwork></artset></figure>

<t><xref target="arch"/> shows us applications, the NIPC application layer gateway (ALG),
an access point (AP), and a device (D). The applications, application layer
gateway and access point are deployed on an IP-Network. The AP supports a
Non-IP interface, which it uses to communicate with the device.
The Application is deployed in a different administrative domain than the
network elements (ALG &amp; AP).
The role of the application layer gateway is to provide a gateway function
to applications wishing to communicate with non-IP devices in the network
domain served by the gateway.
Applications implementing Non-IP Control can leverage RESTful interfaces
to communicate with Non-IP devices in the network domain and subscribe to
events leveraging a CBOR-based pub/sub interface.</t>

</section>
<section anchor="terminology"><name>Terminology</name>

<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in BCP
14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all
capitals, as shown here.</t>

</section>
</section>
<section anchor="architecture"><name>Architecture</name>

<section anchor="overview"><name>Overview</name>

<t>Non-IP protocols, such as BLE or Zigbee, typically define a number of basic
operations that are similar across protocols. Examples of this are read and 
write data. NIPC provides a unified API to support those operations.</t>

<t>To perform NIPC operations on a device, the gateways needs 2 things:
1) Information about the instance of the device or thing: The device must be
onboarded on the gateway (e.g. by means of SCIM). This allows the NIPC Gateway
to retrieve the device object, identified by an id referenced in the path of 
the NIPC API.
2) Information about the interaction model: The Gateway must be able to perform
protocol-neutral operations, and hence requires a mapping of protocol-neutral
operations to protocol specific operations. These are supplied to the gateway
by means of an SDF model, described in <xref target="I-D.ietf-asdf-sdf"/>.</t>

<figure title="NIPC prerequisites" anchor="prereq"><artset><artwork  type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="240" width="432" viewBox="0 0 432 240" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
<path d="M 8,32 L 8,96" fill="none" stroke="black"/>
<path d="M 8,144 L 8,192" fill="none" stroke="black"/>
<path d="M 112,32 L 112,96" fill="none" stroke="black"/>
<path d="M 112,144 L 112,192" fill="none" stroke="black"/>
<path d="M 208,64 L 208,176" fill="none" stroke="black"/>
<path d="M 344,64 L 344,176" fill="none" stroke="black"/>
<path d="M 8,32 L 112,32" fill="none" stroke="black"/>
<path d="M 208,64 L 344,64" fill="none" stroke="black"/>
<path d="M 112,80 L 200,80" fill="none" stroke="black"/>
<path d="M 8,96 L 112,96" fill="none" stroke="black"/>
<path d="M 8,144 L 112,144" fill="none" stroke="black"/>
<path d="M 112,160 L 200,160" fill="none" stroke="black"/>
<path d="M 208,176 L 344,176" fill="none" stroke="black"/>
<path d="M 8,192 L 112,192" fill="none" stroke="black"/>
<polygon class="arrowhead" points="208,160 196,154.4 196,165.6" fill="black" transform="rotate(0,200,160)"/>
<polygon class="arrowhead" points="208,80 196,74.4 196,85.6" fill="black" transform="rotate(0,200,80)"/>
<g class="text">
<text x="60" y="52">SCIM</text>
<text x="60" y="68">object</text>
<text x="60" y="84">{id}</text>
<text x="236" y="100">NIPC</text>
<text x="296" y="100">Operation</text>
<text x="248" y="116">-</text>
<text x="292" y="116">Property</text>
<text x="248" y="132">-</text>
<text x="284" y="132">Action</text>
<text x="248" y="148">-</text>
<text x="280" y="148">Event</text>
<text x="64" y="164">SDF</text>
<text x="64" y="180">model</text>
</g>
</svg>
</artwork><artwork  type="ascii-art"><![CDATA[
    +------------+   
    |    SCIM    |                      
    |   object   |           +----------------+          
    |    {id}    +---------->|                |
    +------------+           | NIPC Operation |
                             |    - Property  |
                             |    - Action    |
    +------------+           |    - Event     |
    |     SDF    +---------->|                |
    |    model   |           +----------------+
    +------------+  

]]></artwork></artset></figure>

<t>Once these 2 prerequisites have been fulfilled, applications that are
authorized can perform NIPC operations on device ids. NIPC operations
are operations on properties, or constitute actions or events on devices,
as per the affordances defined in an SDF model.</t>

</section>
<section anchor="onboarding"><name>Onboarding</name>

<t>In order to perform a NIPC operation on a device, the device has to have its 
identity declared to the NIPC gateway. We refer to this as 'onboarding'. Apart
from the device identity, it is also necessary that the device object contains
all required information to bootstrap trust with the device, as well as
establish connectivity, as NIPC operations assume that connectivity is there. 
Allthough onboarding could theoretically be performed in other ways, it is
strongly recommended to leverage <xref target="RFC7644"/> with
<xref target="I-D.ietf-scim-device-model"/>, as the SCIM device schema has been developed
to contain all nessary attributes and extensions to support NIPC.</t>

</section>
<section anchor="registrations"><name>Registrations</name>

<t>NIPC registrations APIs allow applications to declare information that is not
related to a device instance. Registrations can be information about an
interaction model for a class of devices, or information about an application
that is required to interact with the gateway.</t>

<section anchor="sdf-model-registrations"><name>SDF model registrations</name>

<t>The SDF model for a class of devices determines how a gateway may interact with
these devices in a protocol-neutral way. In order to do that, the SDF model
must contain protocol mappings, mapping protocol-neutral SDF affordances
to protocol-specific ones as defined in <xref target="I-D.mohan-asdf-sdf-protocol-mapping"/>. 
The SDF affordances supported by the device, as well as its protocol-mappings,
are provide to the gateway by means of an SDF model registration. 
SDF models are described in <xref target="I-D.ietf-asdf-sdf"/>.</t>

</section>
<section anchor="data-application-registrations"><name>Data application registrations</name>

<t>An application authorized to perform NIPC operations on devices needs to be
able to define which applications can receive streaming event data from the
gateway. The data-app registrations API allows mapping of an event to a data 
app as well as a protocol.</t>

</section>
</section>
<section anchor="nipc-ops"><name>NIPC Operations</name>

<t>NIPC operations are protocol-neutral operations on SDF affordances, more 
specifically properties, actions &amp; events. NIPC operations can happen against
affordances that were registered in an SDF model. If connection management is
required to execute a NIPC operation, it is assumed that the gateway implictly
establishes and tears down required connections.</t>

<section anchor="properties-apis"><name>Properties APIs</name>

<t>Property APIs allow applications perform operations on properties, such as to
read or write values to them.</t>

</section>
<section anchor="actions"><name>Actions</name>

<t>Action APIs perform actions on devices, such as enabling or disabling a feature
on a device.</t>

</section>
<section anchor="events"><name>Events</name>

<t>Event APIs allow apps to enable or disable event reporting on devices. Events
are reported over the events publish/subscribe interface.</t>

</section>
<section anchor="connection-management-for-nipc-operations"><name>Connection management for NIPC Operations</name>

<t>For protocols that require connection management before executing an operation,
a NIPC gateway will perform implicit connection management. When executing a 
NIP operation, a NIPC Gateway can set up a connection with a device as well as
tear down the connection after the operation has completed. A NIPC Gateway
may support explicit connection management as well. Explicit connection
management can be used by an app that wants to perform multiple NIPC operations
in a single connection. Explicit connection management can be performed by 
calling the /devices/{id}/connections API. After establishing an
explicit connection to a device, an application calls a NIPC Operation, the
Gateway will leverage the existing connection and will also not tear the
connection down after the operation completes. The app will have to explicitly
close the connection.</t>

</section>
<section anchor="extensions"><name>Extensions</name>

<t>NIPC is extendable as a NIPC gateway may want to provide a way to execute a
complex set of NIPC operations in a single API call, or may want to perform
an operation that can deliver an outcome more efficiently than a NIPC API. 
An example of an extension that uses compound operation is the bulk API.</t>

<t>Extensions must leverage the /extension path element. In order to assure
inter-operability, extensions should be IANA registered <xref target="iana-api-ext"/>.</t>

</section>
</section>
<section anchor="events-publish-subscribe-interface"><name>Events publish subscribe interface</name>

<t>Events are published on a publish/subscribe interface. Events can be of
different types:</t>

<t><list style="symbols">
  <t>Streaming data from devices: Streaming data is activated/deactivated with the
NIPC events API</t>
  <t>Broadcasts from devices</t>
  <t>Connection events: Devices connecting &amp; disconnecting</t>
</list></t>

</section>
<section anchor="protocols"><name>Protocols</name>

<section anchor="nipc-apis"><name>NIPC APIs</name>

<t>NIPC is a protocol that is based on RESTful HTTP <xref target="RFC9114"/>. Along with HTTP
headers and URIs, NIPC uses JSON <xref target="RFC7159"/> payloads to convey NIPC 
operations, such as registrations, actions, event and property operations. This
is the case for both request and response parameters, as well as errors.
NIPC uses the JSON media type "application/nipc+json" that is registered in
<xref target="iana-media-types"/>, except for the SDF model registrations APIs, 
where the media type reflects the content as an SDF 
model, and hence is media type "application/sdf+json".
The NIPC property APIs also support the use of other media types to 
describe the content of the property.</t>

</section>
<section anchor="nipc-publishsubscribe-events"><name>NIPC publish/subscribe events</name>

<t>NIPC publish/subscribe events are encoded in CBOR (<xref target="RFC8949"/>) and can be
delivered over either:</t>

<t><list style="symbols">
  <t>MQTT</t>
  <t>Webhook</t>
  <t>Websocket</t>
</list></t>

</section>
</section>
<section anchor="paths"><name>Paths</name>

<section anchor="paths-general"><name>General</name>

<t>The NIPC HTTP protocol is described in terms of a path relative to a Base URI.
The Base URI MUST NOT contain a query string, as clients MAY append additional 
path information and query parameters as part of forming the request.  The base
URI is a URL that most often consists of the "https" protocol scheme, a domain
name, and an initial path <xref target="RFC3986"/>.  That initial path for NIPC is 
recommended to be /nipc.
For example:</t>

<figure><artwork><![CDATA[
  "https://example.com/nipc/"
]]></artwork></figure>

<t>Additionally a version number may be added, for example:</t>

<figure><artwork><![CDATA[
  "https://example.com/nipc/v1/"
]]></artwork></figure>

<t>After the base or version number, the path must contain a collection identifier.
The collection identifier can be one of the following:</t>

<t><list style="symbols">
  <t>/registrations: for NIPC registration APIs</t>
  <t>/devices: for NIPC operations on devices</t>
  <t>/groups: for NIPC operations on groups of devices</t>
  <t>/extensions: for NIPC extension APIs</t>
</list></t>

<t>The well-known URI <spanx style="verb">/.well-known/nipc</spanx> defined in <xref target="iana-well-known"/> can
be used to discover the base path of the NIPC APIs and the supported versions
and extensions. The response to a GET request on this URI MUST be a JSON
document that contains the base path, and optionally the supported versions and<br />
extension APIs. The paths MUST be a URI template as defined in <xref target="RFC6570"/>.
The following is an example of a template defining the NIPC base path as well
as supported extensions on a server.</t>

<figure title="Example response for /.well-known/nipc" anchor="ex-wellknown"><sourcecode type="json"><![CDATA[
{
  "base_path": "/nipc",
  "versions": [
    "/v1"
  ],
  "extensions": [
    "/extensions/{id}/bulk",
    "/extensions/{id}/firmware",
    "/extensions/{id}/properties/blob",
    "/extensions/{id}/properties/file",
    "/extensions/{id}/properties/read/conditional",
    "/extensions/{id}/properties/write"
  ]
}
]]></sourcecode></figure>

</section>
<section anchor="nipc-registrations"><name>NIPC Registrations</name>

<t>Registrations leverage the base path + /registrations. NIPC supports SDF model
registrations and data-app registrations.</t>

<t>paths:</t>

<t><list style="symbols">
  <t>/registrations/models</t>
  <t>/registrations/data-apps</t>
</list></t>

</section>
<section anchor="nipc-operations"><name>NIPC Operations</name>

<t>Every NIPC Operations API pertains to either a device or group of devices, identified by
an id, hence the id will be reflected as the first parameter in the path. 
For example:</t>

<figure><artwork><![CDATA[
  "https://example.com/nipc/v1/{id}"
]]></artwork></figure>

<t>The second parameter in the path refers to the NIPC operation that the API will
perform on the device. This can be:</t>

<t><list style="symbols">
  <t>property</t>
  <t>event</t>
  <t>action</t>
  <t>extension</t>
</list></t>

<t>These are described in <xref target="nipc-ops"/>.</t>

</section>
</section>
<section anchor="schema"><name>Schema</name>

<t>The NIPC schema leans heavily on the SDF schema, as defined in
<xref target="I-D.ietf-asdf-sdf"/>. NIPC operations map directly to SDF affordances.</t>

<section anchor="sdf-model-registrations-1"><name>SDF model registrations</name>

<t>In order to perform a NIPC operation on a device, an SDF interaction model 
needs to be declared that provides protocol mappings for the SDF affordances
the operations will be performed on.</t>

<t>The SDF model can be registered by means of a registrations API POST with 
the SDF model in the body of the request. A registered SDF model can be 
fetched by a registrations API GET with an sdfReference.</t>

</section>
<section anchor="nipc-operations-1"><name>NIPC Operations</name>

<t>NIPC operations require 2 key parameters:
1) A device ID identifying the device the operation should be executed on
2) an SDF reference for the SDF affordance the operations pertains to</t>

<section anchor="device-id"><name>Device ID</name>

<t>All NIPC operations are executed against a device or a group of devices.
Devices or groups of devices are identified by a unique uuid.</t>

<texttable title="Definition of a device our group of devices" anchor="devicedef">
      <ttcol align='left'>Attribute</ttcol>
      <ttcol align='left'>Req</ttcol>
      <ttcol align='left'>Type</ttcol>
      <ttcol align='left'>Example</ttcol>
      <c>id</c>
      <c>T</c>
      <c>uuid</c>
      <c>12345678-1234-5678-1234-56789abcdef4</c>
</texttable>

<t>Id is the unique uuid of the device. This id is generated when registering
the device, for example against a SCIM server. As such, this id is a common
identifier, known both to the application as well as the NIPC Server.</t>

</section>
</section>
<section anchor="sdf-name"><name>SDF Name</name>

<t>NIPC operations happen against SDF affordances and are referenced with an
global sdfName, which is the full path including the namespace.</t>

<t>The operations are either Properties, Events or Actions and their references
are of type string</t>

<t>For example:</t>

<texttable title="Definition of a NIPC operation on a property" anchor="nipcopsdef">
      <ttcol align='left'>Attribute</ttcol>
      <ttcol align='left'>Req</ttcol>
      <ttcol align='left'>Type</ttcol>
      <ttcol align='left'>Example</ttcol>
      <c>Property</c>
      <c>T</c>
      <c>string</c>
      <c>https://example.com/heartrate#/<br />sdfObject/thermostat/sdfProperty/temperature</c>
</texttable>

</section>
<section anchor="responses"><name>Responses</name>

<t>A NIPC Gateway will respond to a NIPC operation request synchronously, and
provide the result of the completed operation in the HTTP response.</t>

<t>The exception to the above are NIPC extensions, <xref target="apiextensions"/>. These contain 
compound statements, and thus require the gateway to execute multiple
NIPC operations. In this case the NIPC gateway will return HTTP status
code 202 after receiving the request and verifying it is able to execute it.
The client can then perform an HTTP GET of the extension API to get the
execution status for the request. If a callback URL address was defined in
the request, the NIPC Gateway can optionally perform a callback with a
response to the compound request after the compound statement completes.</t>

<t>Actions also follow an asynchronous pattern, returning HTTP status code 202
when the action is accepted, along with a Location header pointing to the
action instance for status tracking.</t>

<t>A failure response will consist of a HTTP status code of 4xx or 5xx, and 
will follow the <xref target="RFC9457"/> Problem Details format with <spanx style="verb">application/problem+json</spanx>
media type. The response will contain a <spanx style="verb">type</spanx> field with a URI identifying
the error type, and a human-readable <spanx style="verb">detail</spanx> field. The <spanx style="verb">type</spanx> field
is a URI and is described in <xref target="errorhandling"/>.</t>

<t>Failure response:</t>

<t>Example of a failure response:</t>

<figure title="Example failure response" anchor="failure"><artwork><![CDATA[
=============== NOTE: '\\' line wrapping per RFC 8792 ===============

{
  "type": "https://www.iana.org/assignments/nipc-problem-types#inval\
\id-id",
  "status": 400,
  "title": "Invalid Device ID",
  "detail": "Device ID 12345678-1234-5678-1234-56789abcdef4 does not\
\ exist or is not a device"
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"type" is a URI identifying the specific error type</t>
  <t>"status" is the HTTP status code</t>
  <t>"title" is a brief, human-readable summary of the error type</t>
  <t>"detail" is a human-readable explanation specific to this occurrence</t>
</list></t>

</section>
</section>
</section>
<section anchor="nipc-registrations-1"><name>NIPC Registrations</name>

<t>NIPC allows an application to register an SDF model for a class of devices,
as well as a data application that will receive streaming data from the 
gateway.</t>

<section anchor="sdf-model-registrations-apis"><name>SDF model registrations APIs</name>

<t>These APIs allow applications to register an SDF model for a class of devices.
These APIs use the <spanx style="verb">application/sdf+json</spanx> media type, as described in 
<xref section="7.1" sectionFormat="of" target="I-D.ietf-asdf-sdf"/>.</t>

<section anchor="register-an-sdf-model"><name>Register an SDF model</name>

<t>Method: <spanx style="verb">POST /registrations/models</spanx></t>

<t>Description: Registers one or more SDF models for a class of devices</t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>an SDF document in JSON format containing one of more sdfThings or sdfObjects, similar to the example in <xref target="thermometer-sdf"/>.</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example of a response to an SDF model registration" anchor="exregresp"><artwork><![CDATA[
[
 {
  "sdfName": "https://example.com/heartrate#/sdfObject/healthsensor"
 }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"sdfName" is the name of the top-level sdfThing or sdfObject 
 in the SDF model</t>
</list></t>

</section>
<section anchor="get-all-sdf-models"><name>Get all SDF models</name>

<t>Method: <spanx style="verb">GET /registrations/models</spanx></t>

<t>Description: Gets all SDF models registered with the gateway</t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example get all SDF models response" anchor="exgetallresp"><artwork><![CDATA[
[
 {
  "sdfName": "https://example.com/heartrate#/sdfObject/healthsensor"
 },
 {
  "sdfName": "https://example.com/thermometer#/sdfObject/thermometer"
 }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"sdfName" is the name of the top-level sdfThing or sdfObject 
 in the SDF model</t>
</list></t>

</section>
<section anchor="get-an-sdf-model"><name>Get an SDF model</name>

<t>Method: <spanx style="verb">GET /registrations/models{?sdfName}</spanx></t>

<t>Description: Gets an SDF model registered with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>sdfName: the name of the top-level sdfThing or sdfObject 
 in the SDF model.</t>
</list></t>

<t>Response:</t>

<t>The SDF model is returned in JSON format, similar to the example in 
<xref target="thermometer-sdf"/>.</t>

</section>
<section anchor="delete-an-sdf-model"><name>Delete an SDF model</name>

<t>Method: <spanx style="verb">DELETE /registrations/models{?sdfName}</spanx></t>

<t>Description: Deletes an SDF model registered with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>sdfName: the name of the top-level sdfThing or sdfObject 
 in the SDF model.</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example delete SDF model response" anchor="exdelresp"><artwork><![CDATA[
{
  "sdfName": "https://example.com/heartrate#/sdfObject/healthsensor"
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"sdfName" is the name of the top-level sdfThing or sdfObject 
 in the SDF model</t>
</list></t>

</section>
<section anchor="update-an-sdf-model"><name>Update an SDF model</name>

<t>Method: <spanx style="verb">PUT /registrations/models{?sdfName}</spanx></t>

<t>Description: Updates an SDF model registered with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>sdfName: the name of the top-level sdfThing or sdfObject 
 in the SDF model.</t>
</list></t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>an SDF model in JSON format, similar to the example in <xref target="thermometer-sdf"/>.</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example update SDF model response" anchor="exupresp"><artwork><![CDATA[
{
  "sdfName": "https://example.com/heartrate#/sdfObject/healthsensor"
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"sdfName" is the name of the top-level sdfThing or sdfObject 
 in the SDF model</t>
</list></t>

</section>
</section>
<section anchor="data-application-registrations-apis"><name>Data application registrations APIs</name>

<t>These APIs allow applications to register a data application that will receive
streaming data from the gateway. These APIs operate on a data app ID.
This ID corresponds to the endpoint app ID of the telemetry endpoint app 
that is registered with the SCIM server. The endpoint app is defined in 
<xref section="6" sectionFormat="of" target="I-D.ietf-scim-device-model"/>.</t>

<section anchor="register-a-data-application"><name>Register a data application</name>

<t>Method: <spanx style="verb">POST /registrations/data-apps{?dataAppId}</spanx></t>

<t>Description: Registers a data application with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>dataAppId: the id of the data application</t>
</list></t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>events: a list of events that the data application wants to receive
streaming data for.</t>
</list></t>

<t>The request body also contains one of the following:</t>

<t><list style="symbols">
  <t>mqttClient: a boolean that denotes that the data application
is an MQTT client that will receive streaming data over MQTT</t>
  <t>mqttBroker: an object that contains the MQTT broker information
where the broker will publish the streaming data.
  <list style="symbols">
      <t>URI: the URI of the MQTT broker</t>
      <t>username: the username to authenticate with the MQTT broker</t>
      <t>password: the password to authenticate with the MQTT broker</t>
      <t>brokerCACert: the CA certificate of the MQTT broker (optional)</t>
      <t>customTopic: the custom topic to publish the streaming data to
(optional)</t>
    </list></t>
  <t>webhook: an object that contains a webhook URL along with any 
 credentials that are required to authenticate the webhook. 
 The webhook URL is the endpoint where the streaming data will be sent.
  <list style="symbols">
      <t>URI: the webhook URL</t>
      <t>headers: An object that contains the headers to be sent with the webhook
request. The headers can contain any authentication information
required by the webhook server.</t>
      <t>serverCACert: the CA certificate of the webhook server (optional)</t>
    </list></t>
  <t>websocket: an object that contains a websocket URL along with any 
credentials that are required to authenticate the websocket. 
The websocket URL is the endpoint where the streaming data will be sent.
  <list style="symbols">
      <t>URI: the websocket URL</t>
      <t>headers: An object that contains the headers to be sent with the websocket
request. The headers can contain any authentication information
required by the websocket server.</t>
      <t>serverCACert: the CA certificate of the websocket server (optional)</t>
    </list></t>
</list></t>

<t>Example of a request body:</t>

<figure title="Example with mqttClient" anchor="exregmqttclientrsp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "events": [
    {
      "event": "https://example.com/heartrate#/sdfObject/healthsenso\
r/sdfEvent/fallDetected"
    }
  ],
  "mqttClient": true
}
]]></artwork></figure>

<t>Example of a request body for a data application that is an MQTT broker:</t>

<figure title="Example with mqttBroker" anchor="exregmqttbrokerrsp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "events": [
    {
      "event": "https://example.com/heartrate#/sdfObject/healthsenso\
r/sdfEvent/fallDetected"
    }
  ],
  "mqttBroker": {
    "URI": "mqtt.example.com:1883",
    "username": "user",
    "password": "password",
    "customTopic": "custom/topic"
  }
}
]]></artwork></figure>

<t>Response:</t>

<t>If successful, the response will be identical to the request body.</t>

</section>
<section anchor="update-a-data-application"><name>Update a data application</name>

<t>Method: <spanx style="verb">PUT /registrations/data-apps{?dataAppId}</spanx></t>

<t>Description: Updates a data application with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>dataAppId: the id of the data application</t>
</list></t>

<t>Request Body: Same as the request body for the register data application API.</t>

<t>Response:</t>

<t>If successful, the response will be identical to the request body.</t>

</section>
<section anchor="get-a-data-application"><name>Get a data application</name>

<t>Method: <spanx style="verb">GET /registrations/data-apps{?dataAppId}</spanx></t>

<t>Description: Gets a data application registered with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>dataAppId: the id of the data application</t>
</list></t>

<t>Response:</t>

<t>The response will be identical to the request body for the register data
application API.</t>

</section>
<section anchor="delete-a-data-application"><name>Delete a data application</name>

<t>Method: <spanx style="verb">DELETE /registrations/data-apps{?dataAppId}</spanx></t>

<t>Description: Deletes a data application registered with the gateway</t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>dataAppId: the id of the data application</t>
</list></t>

<t>Response:</t>

<t>The response will be identical to the request body for the register data
application API.</t>

</section>
</section>
</section>
<section anchor="nipc-apis-1"><name>NIPC APIs</name>

<t>The primary goal of the NIPC APIs is to  perform operations on SDF Affordances, such as properties, events &amp; actions.This allows a user of the NIPC API to get or update properties of devices, perform actions on devices, and consume events from devices.</t>

<t>The NIPC APIs consists of 3 main collections which reflect SDF Affordances as defined in <xref section="1.2" sectionFormat="of" target="I-D.ietf-asdf-sdf"/>:</t>

<t><list style="symbols">
  <t>NIPC Property APIs: These APIs allow applications to get and update device 
properties.</t>
  <t>NIPC Event APIs: These APIs allow applications to enable or disable event
reporting on devices.</t>
  <t>NIPC Action APIs: These APIs allow applications to perform actions on
devices.</t>
</list></t>

<t>One or more SDF models must be registered in order to use these NIPC
Property, Event and Action APIs. The SDF models can be a top-level sdfThing with
multiple sdfObjects or a top-level sdfObject. These APIs depend on the SDF 
affordances (i.e. sdfProperty, sdfEvent and sdfAction) defined in
the SDF model and a device ID that is defined in <xref target="I-D.ietf-scim-device-model"/>.
An SDF affordance can be referenced using the global name of the SDF affordance
as described in <xref section="4" sectionFormat="of" target="I-D.ietf-asdf-sdf"/>.</t>

<t>The SDF global name will be used against the registered SDF model to 
determine the protocol-specific protocolmap that the NIPC API will operate on. 
The SDF global name is also percent-encoded as per <xref section="2.1" sectionFormat="of" target="RFC3986"/>.</t>

<section anchor="nipc-property-apis"><name>NIPC Property APIs</name>

<t>These APIs allow applications to get and update device properties. 
These operations may require a connection to the device to be established. 
This connection can be established as part of the same API call implicitly.
If a connection is already active for this device, the existing connection willi
be leveraged without modifying it.</t>

<t>These APIs support multiple media types based on Content-Type and Accept
headers to accommodate different data formats.</t>

<t>When using <spanx style="verb">application/nipc+json</spanx>, the request and response bodies follow 
the format shown in the examples above, with binary data encoded as 
base64 in the "value" field. 
For other content types, the data is transmitted according to the 
specific format requirements of that media type.</t>

<section anchor="write-multiple-values"><name>Write multiple values</name>

<t>Method: <spanx style="verb">PUT /devices/{id}/properties{?propertyName}</spanx></t>

<t>Description: Write values to one or more properties on a device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>propertyName: a single property to update. If this parameter is
provided, the request body can contain any conten type payload 
with the value to write to the property. If this parameter is not
provided, the request body MUST contain an application/nipc+json payload
with an array of properties to update, each containing a property and a
value.</t>
</list></t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>If the query parameter propertyName is provided, the request body
can contain any content type payload with the value to write to the property.
The value is the raw binary data to write to the property.</t>
</list></t>

<t>or</t>

<t><list style="symbols">
  <t>an array of properties to update, each containing a property and a value.
The value is the raw binary data, encoded in base64 with padding as per 
<xref section="5" sectionFormat="of" target="RFC4648"/>.</t>
</list></t>

<t>Example body updating multiple properties:</t>

<figure title="Example updating multiple properties" anchor="exupmprop"><sourcecode type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

[
  {
    "property": "https://example.com/heartrate#/sdfObject/thermostat\
/sdfProperty/temperature",
    "value": "dGVzdA=="
  },
  {
    "property": "https://example.com/heartrate#/sdfObject/thermostat\
/sdfProperty/humidity",
    "value": "eGVzdB=="
  }
]
]]></sourcecode></figure>

<t>Response:</t>

<t>If the Accept header is set to <spanx style="verb">application/nipc+json</spanx>, the response will be
an array with a status field set to 200 for each property that was updated, 
or a problem type object for each property that failed to update.</t>

<t>If the Accept header is set to any other media type and the propertyName query parameter is provided, the response will be 204 No Content with no body.</t>

<t>Example of a response:</t>

<figure title="Example update multiple properties response" anchor="exupmresp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

[
  {
    "status": 200
  },
  {
    "type": "https://www.iana.org/assignments/nipc-problem-types#inv\
alid-property",
    "status": 400,
    "title": "Invalid Property",
    "detail": "Property https://example.com/heartrate#/sdfObject/the\
rmostat/sdfProperty/temperature does not exist or is not writable"
  }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"properties" is an array of properties that were updated, each containing
a property and a value</t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="read-multiple-values"><name>Read multiple values</name>

<t>Method: <spanx style="verb">GET /devices/{id}/properties{?propertyName*}</spanx></t>

<t>Description: Read values from one or more properties on a device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>propertyName: The property to read. This can be a single property or multiple
properties. If multiple properties are provided, the request body MUST
contain an application/nipc+json payload with an array of properties to read.</t>
</list></t>

<t>Response:</t>

<t>If the Accept header is set to <spanx style="verb">application/nipc+json</spanx>, the response will be
an array of properties, each containing a property and a value. The value is
the raw binary data read from the property, encoded in base64 with padding as per <xref section="5" sectionFormat="of" target="RFC4648"/>.</t>

<t>Example of a response:</t>

<figure title="Example read multiple properties response" anchor="exreadmresp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

[
  {
    "property": "https://example.com/heartrate#/sdfObject/thermostat\
/sdfProperty/temperature",
    "value": "dGVzdA=="
  },
  {
    "property": "https://example.com/heartrate#/sdfObject/thermostat\
/sdfProperty/humidity",
    "value": "eGVzdB=="
  }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"property" is the property that was read from</t>
  <t>"value" is the bytes that were read in base64 encoding</t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
</section>
<section anchor="nipc-event-apis"><name>NIPC Event APIs</name>

<t>These APIs allow applications to enable or disable event reporting on devices.
These operations may require a connection to the device to be established. This
connection can be established as part of the same API call implicitly. If a
connection is already active for this device, the existing connection will be
leveraged without modifying it.</t>

<t>The event is the global name of an <spanx style="verb">sdfEvent</spanx>.</t>

<t>The ID in the path is the id of the device or group of devices.
An event can be enabled on a group of devices if it is supported by the
underlying protocol. For example, if the underlying protocol is BLE, 
the event can be enabled on a group of devices if the event is an 
advertisement event or connection status event.</t>

<t>If the data application registered for this event is an MQTT broker or 
client, the event is used to construct the MQTT topic for the event.
The topic is constructed using the data application ID, the default 
namespace for the event, and the event itself. For example, if the data 
application ID is <spanx style="verb">"12345678-1234-5678-1234-56789abcdef4"</spanx> 
and the event is 
<spanx style="verb">"https://example.com/thermometer#/sdfThing/thermometer/sdfEvent/isPresent"</spanx>,
the topic will be:</t>

<figure><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

data-app/<dataAppId>/<namespace>/<json_pointer_to_sdf_event>

data-app/12345678-1234-5678-1234-56789abcdef4/thermometer/sdfThing/\
thermometer/sdfEvent/isPresent
]]></artwork></figure>

<t>A data application can subscribe to this topic using the topic or it 
can use MQTT wildcards to subscribe to <spanx style="verb">data-app/+/temperature/#</spanx> to 
receive all events for the <spanx style="verb">temperature</spanx> namespace.</t>

<t>If a custom topic is provided for an MQTT broker, the custom topic is
used as the MQTT topic instead.</t>

<section anchor="enable-event-reporting"><name>Enable event reporting</name>

<t>Method: <spanx style="verb">POST /devices/{id}/events{?eventName}</spanx></t>

<t>Description: Enables an event on a specific device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>eventName: the event to enable</t>
</list></t>

<t>The eventName is a URL encoded string that is the absolute URI that is the global
name of an <spanx style="verb">sdfEvent</spanx>.</t>

<t>Response:</t>

<t>Returns HTTP status code 201 Created with a Location header pointing to the created event instance.</t>

<t>Example of a successful response:</t>

<figure><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

HTTP/1.1 201 Created
Location: /devices/12345678-1234-5678-1234-56789abcdef4/events?insta\
nceId=87654321-4321-8765-4321-fedcba9876543
]]></artwork></figure>

<t>The Location header contains the URI for the created event instance, which can be used to check status or disable the event.</t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="disable-event-reporting"><name>Disable event reporting</name>

<t>Method: <spanx style="verb">DELETE /devices/{id}/events{?instanceId}</spanx></t>

<t>Description: Disables an event on a specific device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device or group of devices</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>instanceId: the instance ID of the event to disable (obtained from the Location header when the event was enabled)</t>
</list></t>

<t>Response:</t>

<t>Returns HTTP status code 204 No Content on successful disable.</t>

<figure><artwork><![CDATA[
HTTP/1.1 204 No Content
]]></artwork></figure>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="get-status-of-one-or-more-events"><name>Get status of one or more events</name>

<t>Method: <spanx style="verb">GET /devices/{id}/events{?instanceId*}</spanx></t>

<t>Description: Get the status of one or more events on a specific device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device or group of devices</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>instanceId: a comma separated list of event instance IDs to filter by (optional)</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example get multiple events status response" anchor="exgetmresp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

[
  {
    "instanceId": "87654321-4321-8765-4321-fedcba9876543",
    "event": "https://example.com/heartrate#/sdfObject/healthsensor/\
sdfEvent/fallDetected"
  }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"instanceId" is the unique instance ID for each enabled event</t>
  <t>"event" is the event URI for each enabled event</t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="enable-event-reporting-on-a-group-of-devices"><name>Enable event reporting on a group of devices</name>

<t>Method: <spanx style="verb">POST /groups/{id}/events</spanx></t>

<t>Description: Enables an event on a group of devices</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the group of devices</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>eventName: the event to enable</t>
</list></t>

<t>The eventName is a URL encoded string that is the absolute URI that is the global
name of an <spanx style="verb">sdfEvent</spanx>.</t>

<t>Response:</t>

<t>Returns HTTP status code 201 Created with a Location header pointing to the created event instance.</t>

<t>Example of a successful response:</t>

<figure><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

HTTP/1.1 201 Created
Location: /groups/12345678-1234-5678-1234-56789abcdef4/events?instan\
ceId=87654321-4321-8765-4321-fedcba9876543
]]></artwork></figure>

<t>The Location header contains the URI for the created event instance, which can be used to check status or disable the event.</t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="disable-event-reporting-on-a-group-of-devices"><name>Disable event reporting on a group of devices</name>

<t>Method: <spanx style="verb">DELETE /groups/{id}/events{?instanceId}</spanx></t>

<t>Description: Disables an event on a group of devices</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the group of devices</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>instanceId: the instance ID of the event to disable (obtained from the Location header when the event was enabled)</t>
</list></t>

<t>Response:</t>

<t>Returns HTTP status code 204 No Content on successful disable.</t>

<figure><artwork><![CDATA[
HTTP/1.1 204 No Content
]]></artwork></figure>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="get-event-status-on-a-group-of-devices"><name>Get event status on a group of devices</name>

<t>Method: <spanx style="verb">GET /groups/{id}/events{?instanceId*}</spanx></t>

<t>Description: Get the status of one or more events on a group of devices</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the group of devices</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>instanceId: a list of event instance IDs to filter by (optional)</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example get multiple group events status response" anchor="exgetmgevntsresp"><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

[
  {
    "instanceId": "87654321-4321-8765-4321-fedcba9876543",
    "event": "https://example.com/heartrate#/sdfObject/healthsensor/\
sdfEvent/fallDetected"
  }
]
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"instanceId" is the unique instance ID for each enabled event</t>
  <t>"event" is the event URI for each enabled event</t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
</section>
<section anchor="nipc-action-apis"><name>NIPC Action APIs</name>

<t>These APIs allow applications to perform actions on devices. These operations
may require a connection to the device to be established. This connection can
be established as part of the same API call implicitly. If a connection is
already active for this device, the existing connection will be leveraged
without modifying it.</t>

<section anchor="perform-an-action"><name>Perform an action</name>

<t>Method: <spanx style="verb">POST /devices/{id}/actions{?actionName}</spanx></t>

<t>Description: Perform an action on a specific device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>actionName: the action to perform</t>
</list></t>

<t>Request Body:</t>

<t>The request body is optional and may contain a value. The media type of the value can be defined by the underlying protocol, for example it could be octet-stream for binary data.</t>

<t>Response:</t>

<t>Actions are performed asynchronously. A successful request returns HTTP status code 202 Accepted 
with a Location header pointing to the action instance for status checking.</t>

<t>Example of a successful response:</t>

<figure><artwork><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

HTTP/1.1 202 Accepted
Location: /devices/12345678-1234-5678-1234-56789abcdef4/actions?inst\
anceId=87654321-4321-8765-4321-fedcba9876543
]]></artwork></figure>

<t>The Location header contains the URI for the action instance, which can be used to check the action status.</t>

</section>
<section anchor="check-action-status"><name>Check action status</name>

<t>Method: <spanx style="verb">GET /devices/{id}/actions{?instanceId}</spanx></t>

<t>Description: Check the status of an action on a specific device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Query Parameters:</t>

<t><list style="symbols">
  <t>instanceId: the instance ID of the action (obtained from the Location header)</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example action status response" anchor="exactionstatusresp"><artwork><![CDATA[
{
  "status": "COMPLETED"
}
]]></artwork></figure>

<t>where "status" indicates the current state of the action (e.g., "IN_PROGRESS" or "COMPLETED").</t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
</section>
<section anchor="nipc-explicit-connections-management-apis"><name>NIPC explicit connections management APIs</name>

<t>A lot of protocols do not require connection management, so for these protocols, these APIs will not apply.
NIPC Gateways perform implicit connection management for protocols that require connection management (such as BLE), so in principle the user of the NIPC API does not have to perform connection management. In some cases however, a user might want to keep a connection open, perform an action, evaluate the result and perform a second action based on that result. In this case it is useful to perform explicit connection management so the connections remains established to execute subsequent actions.  These APIs allow applications to explicitly manage device connections.
The examples in this section will be based on BLE, which requires connection management.</t>

<section anchor="connect-to-a-device"><name>Connect to a device</name>

<t>Method: <spanx style="verb">POST /devices/{id}/connections</spanx></t>

<t>Description: Connect to a device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>Connection retry parameters</t>
  <t>A protocol map object. In the case of BLE, if no protocol map is included,
service discovery is performed to discover all supported properties when
connecting to a device. Optionally, service discovery may be limited to
properties defined in the "ble" protocol extension. The services to be 
discovered can be added in an array. Property discover can be buffered
across connections, so the API also supports caching parameters.</t>
</list></t>

<t>Example body of a connection without specific discovery of properties:</t>

<figure title="Example connection" anchor="exconn"><artwork><![CDATA[
{
  "retries": 3,
  "retryMultipleAPs": true
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"retries" defines the number of retries in case the operations does not 
succeed</t>
  <t>"retryMultipleAPs" can be used in case there is an infrastructure with 
multiple access points or radios that can reach the device. If set to "true"
a different access point may be used for retries.</t>
</list></t>

<t>In case the application would like to discover specific properties of a device,
a protocol mapping can be added that defines what properties should be
discovered.</t>

<t>Example body of a BLE connection with specific discovery of properties:</t>

<figure title="Example connection with explicit discovery of connections" anchor="exconnprp"><artwork><![CDATA[
{
  "retries": 3,
  "retryMultipleAPs": true,
  "sdfProtocolMap": {
    "ble": {
      "services": [
        {
          "serviceID": "12345678-1234-5678-1234-56789abcdef4"
        }
      ],
      "cached": false,
      "cacheIdlePurge": 3600,
      "autoUpdate": true,
      "bonding": "default"
    }
  }
}
]]></artwork></figure>

<t>where in the BLE protocol object:</t>

<t><list style="symbols">
  <t>"services" is an array of services defined by their serviceIDs.</t>
  <t>"cached" refers to whether the services need to be cached for 
subsequent connects, in order not to perform service discovery on
each request.</t>
  <t>"cacheIdlePurge" defines how long (in seconds) the cache should be maintained 
before purging.</t>
  <t>some devices support notifications on changes in services, 
"autoUpdate" allows the network to update services based on 
notification (on by default)</t>
  <t>"bonding" allows you to override the bonding method configured when 
onboarding the device</t>
</list></t>

<t>Response:</t>

<t>Success responses include a protocol mapping with an array of 
discovered properties, as defined in the specific protocol.
For example, for BLE, this is an array of supported services, which in turn
contains an array of charateristics, which in turn contains an array of
descriptors, as shown in <xref target="BLEservices"/>.</t>

<figure title="BLE Services" anchor="BLEservices"><artwork><![CDATA[
    services
     - serviceID
        |
        |> characteristics
            - charactericID
            - flags
               |
               |> Descriptors
                   - descriptorID
]]></artwork></figure>

<t>Example of a response:</t>

<figure title="Example connection response" anchor="exconnresp"><artwork><![CDATA[
{
  "id": "12345678-1234-5678-1234-56789abcdef4",
  "sdfProtocolMap": {
    "ble": [
      {
        "serviceID": "12345678-1234-5678-1234-56789abcdef4",
        "characteristics": [
          {
            "characteristicID": 
              "12345678-1234-5678-1234-56789abcdef4",
            "flags": [
              "read",
              "write"
            ],
            "descriptors": [
              {
                "descriptorID": 
                  "12345678-1234-5678-1234-56789abcdef4"
              }
            ]
          }
        ]
      }
    ]
  }
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"id" is the id of the device</t>
  <t>"sdfProtocolMap" contains an Array of BLE services as shown in
   <xref target="BLEservices"/></t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="update-a-connection"><name>Update a connection</name>

<t>Method: <spanx style="verb">PUT /devices/{id}/connections</spanx></t>

<t>Description: Update cached ServiceMap for a device. Full service discovery will
be performed, unless specific services are described in the API body.</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Request Body:</t>

<t><list style="symbols">
  <t>A protocol map object. In the case of BLE, if no protocol map is included,
service discovery is performed to discover all supported properties when
connecting to a device. Optionally, service discovery may be limited to
properties defined in the "ble" protocol extension. The services to be 
discovered can be added in an array. Property discover can be buffered
across connections, so the API also supports caching parameters.</t>
</list></t>

<t>Example body of an update connection:</t>

<figure title="Example service discovery response" anchor="exupconn"><artwork><![CDATA[
{
  "sdfProtocolMap": {
    "ble": {
      "services": [
        {
          "serviceID": "12345678-1234-5678-1234-56789abcdef4"
        }
      ],
      "cached": false,
      "cacheIdlePurge": 3600,
      "autoUpdate": true
    }
  }
}
]]></artwork></figure>

<t>where in the BLE protocol object:</t>

<t><list style="symbols">
  <t>"services" is an array of services defined by their serviceIDs</t>
  <t>"cached" refers to whether the services need to be cached for 
subsequent connects, in order not to perform service discovery on
each request</t>
  <t>"cacheIdlepurge" defines how long the cache should be maintained 
before purging</t>
  <t>some devices support notifications on changes in services, 
"autoUpdate" allows the network to update services based on 
notification (on by default)</t>
</list></t>

<t>Response:</t>

<t>Success responses include a protocol mapping with an array of 
discovered properties, as defined in the specific protocol.
For example, for BLE, this is an array of supported services, which in turn
contains an array of charateristics, which in turn contains an array of
descriptors, as shown in <xref target="BLEservices"/>.</t>

<t>Example of a response:</t>

<figure title="Example connection response" anchor="exupconnresp"><artwork><![CDATA[
{
  "id": "12345678-1234-5678-1234-56789abcdef4",
  "sdfProtocolMap": {
    "ble": [
      {
        "serviceID": "12345678-1234-5678-1234-56789abcdef4",
        "characteristics": [
          {
            "characteristicID": 
              "12345678-1234-5678-1234-56789abcdef4",
            "flags": [
              "read",
              "write"
            ],
            "descriptors": [
              {
                "descriptorID": 
                  "12345678-1234-5678-1234-56789abcdef4"
              }
            ]
          }
        ]
      }
    ]
  }
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"id" is the id of the device</t>
  <t>"sdfProtocolMap" contains an Array of BLE services as shown in
   <xref target="BLEservices"/></t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="disconnect-from-a-device"><name>Disconnect from a device</name>

<t>Method: <spanx style="verb">DELETE /devices/{id}/connections</spanx></t>

<t>Description: Disconnect from a device</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Response:</t>

<t>Returns HTTP status code 200 OK with device ID on successful disconnect.</t>

<t>Example of a response:</t>

<figure title="Example disconnect response" anchor="exdisconnresp"><artwork><![CDATA[
{
  "id": "12345678-1234-5678-1234-56789abcdef4"
}
]]></artwork></figure>

<t>where "id" is the id of the device.</t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
<section anchor="get-connection-status"><name>Get connection status</name>

<t>Method: <spanx style="verb">GET /devices/{id}/connections</spanx></t>

<t>Description: Get connection status for a device. Success when device(s)
is/are connected, includes service map for the device if available.
Failure when a device is not connected.</t>

<t>Parameters:</t>

<t><list style="symbols">
  <t>id: the id of the device</t>
</list></t>

<t>Response:</t>

<t>Example of a response:</t>

<figure title="Example connection status response" anchor="exconnstatresp"><artwork><![CDATA[
{
  "id": "12345678-1234-5678-1234-56789abcdef4",
  "sdfProtocolMap": {
    "ble": [
      {
        "serviceID": "12345678-1234-5678-1234-56789abcdef4",
        "characteristics": [
          {
            "characteristicID": 
              "12345678-1234-5678-1234-56789abcdef4",
            "flags": [
              "read",
              "write"
            ],
            "descriptors": [
              {
                "descriptorID": 
                  "12345678-1234-5678-1234-56789abcdef4"
              }
            ]
          }
        ]
      }
    ]
  }
}
]]></artwork></figure>

<t>where-</t>

<t><list style="symbols">
  <t>"id" is the id of the device</t>
  <t>"sdfProtocolMap" contains an Array of BLE services as shown in <xref target="BLEservices"/></t>
</list></t>

<t>A failure will generate a standard failed response. Please refer to <xref target="failure"/>
definition of failed response.</t>

</section>
</section>
</section>
<section anchor="nipc-extensibility"><name>NIPC Extensibility</name>

<t>NIPC is extensible in two ways:</t>

<t><list style="symbols">
  <t>Protocol mapping: New protocol mapping can extend NIPC with support
for new non-IP protocols</t>
  <t>API extensions: API extensions leverage compound statements of basic NIPC
action APIs to simplify common operations for applications.</t>
</list></t>

<section anchor="protocol-extensions"><name>Protocol extensions</name>

<t>NIPC supports mapping protocol specific properties to NIPC properties
as described in <xref target="I-D.mohan-asdf-sdf-protocol-mapping"/>.
BLE and Zigbee are used as examples, but protocol
mapping is extensible to other protocols, so now non-IP protocols can be 
supported by NIPC without a schema change.</t>

<t>The protocol objects need to be extended with the new
protocol as well. Protocol objects will be extended as follows:</t>

<texttable title="Adding Protocol mappings" anchor="newprotext">
      <ttcol align='left'>Attribute</ttcol>
      <ttcol align='left'>Type</ttcol>
      <ttcol align='left'>Example</ttcol>
      <c>ble</c>
      <c>object</c>
      <c>an object with BLE-specific properties</c>
      <c>zigbee</c>
      <c>object</c>
      <c>an object with Zigbee-specific properties</c>
      <c>newProtocol</c>
      <c>object</c>
      <c>an object with newProtocol-specific props</c>
</texttable>

<t>In the new protocol object, protocol specific properties can be added.</t>

</section>
<section anchor="apiextensions"><name>API extensions</name>

<t>/extension</t>

<t>The extension APIs allow for extensibility of the APIs, either IANA 
registered extensions (<xref target="iana-api-ext"/>) or vendor-specific extensions.
Extension APIs must leverage the basic NIPC defined APIs and combine them in 
compound statements in order to streamline application operation against
devices, make operations more expediant and convenient in one API call.
In principle they do not add any basic functionality. In
the OpenAPI model <xref target="NIPCextensions"/> below, we have defined a few example 
extensions.</t>

<t>The extensions can contain long running operations, such as firmware updates,
or other bulk operations that can be performed on a device. For long 
running operations, the extension API will return a 202 Accepted status 
code and a location header with the URL to check the status of the operation.
The status of the operation can be checked by calling the status extension API
with the same device ID. The status extension API will return a 200 OK status code
when the operation is in progress. When the operation is complete, 
the status extension API will return a 303 See Other status code with a 
location header with the URL to check the status of the operation.
The GET operation on the extension API will return a 200 OK status code
with the actual response once the operation is complete.</t>

</section>
</section>
<section anchor="errorhandling"><name>NIPC Error Handling</name>

<t>The error types in the NIPC APIs use URI-based error type identifiers 
as defined in <xref target="iana-problem-details"/>. The error types 
can be generic or specific to the API category. The error types are 
organized into the following categories:</t>

<t><list style="symbols">
  <t>Generic: Broadly applicable errors, including authorization, 
invalid identifiers, and generic failures.</t>
  <t>Property APIs: Errors related to property APIs (read/write).</t>
  <t>Event APIs: Errors related to event APIs (enable/disable).</t>
  <t>Protocol specific: Errors related to protocol-specific operations.</t>
  <t>Extension APIs: Errors related to extension APIs.</t>
</list></t>

<t>The specific error types are defined in the table below:</t>

<texttable title="Error Codes" anchor="errorcodes">
      <ttcol align='left'>Error Type</ttcol>
      <ttcol align='left'>Description</ttcol>
      <ttcol align='left'>Category</ttcol>
      <c>invalid-id</c>
      <c>Invalid device ID or gateway doesn't recognize the ID</c>
      <c>Generic</c>
      <c>invalid-sdf-url</c>
      <c>Invalid SDF URL or SDF affordance not found</c>
      <c>Generic</c>
      <c>extension-operation-not-executed</c>
      <c>Operation was not executed since the previous operation failed</c>
      <c>Generic</c>
      <c>sdf-model-already-registered</c>
      <c>SDF model already registered</c>
      <c>Generic</c>
      <c>sdf-model-in-use</c>
      <c>SDF model in use</c>
      <c>Generic</c>
      <c>property-not-readable</c>
      <c>Property not readable</c>
      <c>Property APIs</c>
      <c>property-not-writable</c>
      <c>Property not writable</c>
      <c>Property APIs</c>
      <c>event-already-enabled</c>
      <c>Event already enabled</c>
      <c>Event APIs</c>
      <c>event-not-enabled</c>
      <c>Event not enabled</c>
      <c>Event APIs</c>
      <c>event-not-registered</c>
      <c>Event not registered for any data application</c>
      <c>Event APIs</c>
      <c>protocolmap-ble-already-connected</c>
      <c>Device already connected</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-no-connection</c>
      <c>No connection found for device</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-connection-timeout</c>
      <c>BLE connection timeout</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-bonding-failed</c>
      <c>BLE bonding failed</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-connection-failed</c>
      <c>BLE connection failed</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-service-discovery-failed</c>
      <c>BLE service discovery failed</c>
      <c>Protocol specific</c>
      <c>protocolmap-ble-invalid-service-or-characteristic</c>
      <c>Invalid BLE service or characteristic ID</c>
      <c>Protocol specific</c>
      <c>protocolmap-zigbee-connection-timeout</c>
      <c>Zigbee connection timeout</c>
      <c>Protocol specific</c>
      <c>protocolmap-zigbee-invalid-endpoint-or-cluster</c>
      <c>Invalid Zigbee endpoint or cluster ID</c>
      <c>Protocol specific</c>
      <c>extension-broadcast-invalid-data</c>
      <c>Invalid transmit data</c>
      <c>Transmit APIs</c>
      <c>extension-firmware-rollback</c>
      <c>Firmware rollback</c>
      <c>Extension APIs</c>
      <c>extension-firmware-update-failed</c>
      <c>Firmware update failed</c>
      <c>Extension APIs</c>
</texttable>

<t>The appropriate HTTP status code is returned in the response.</t>

</section>
<section anchor="publishsubscribe-interface"><name>Publish/Subscribe Interface</name>

<t>The publish/subscribe interface, or data streaming interface, is an MQTT
publishing interface. Pub/sub topics can be created and managed by means
of the /registration/data-app API.</t>

<t>In this memo, we propose the data format to be CBOR <xref target="RFC8949"/>.</t>

<section anchor="cddl-definition"><name>CDDL Definition</name>

<t>We have a CDDL <xref target="RFC8610"/> definition where we define the
DataSubscription struct that will be used by all the messages published 
to the MQTT broker.</t>

<t>The DataSubscription struct is a CBOR map that will contain the raw data
in bytes and a timestamp of the data. Optionally, the message will also
have a deviceID that corresponds to the SCIM ID of the device if the 
payload is associated to a known device.</t>

<t>Other fields in the CDDL such as apMacAddress and rssi can be optionally
included but these fields can expose the underlying network topology.</t>

<t>Each message also has a subscription choice group that will define the
type of data that is being published.</t>

<t>Each MQTT message can be a collection of DataSubscription structs. This
collection is represented as DataBatch in the CDDL.</t>

<figure><sourcecode type="CDDL"><![CDATA[
start = DataBatch

DataBatch = [* DataSubscription]

DataSubscription = {
  ? data: bytes,
  timestamp: float, ; epoch in seconds
  ? deviceID: text,
  ? apMacAddress: text,
  subscription
}

subscription = (
  bleSubscription: BleSubscription //
  bleAdvertisement: BleAdvertisement //
  bleConnectionStatus: BleConnectionStatus //
  zigbeeSubscription: ZigbeeSubscription //
  rawPayload: RawPayload
)

BleSubscription = {
  serviceID: text,
  characteristicID: text
}

BleAdvertisement = {
  macAddress: text,
  ? rssi: nint,
}

BleConnectionStatus = {
  macAddress: text,
  connected: bool,
  ? reason: int
}

ZigbeeSubscription = {
  endpointID: int,
  clusterID: int,
  attributeID: int
  attributeType: int
}

RawPayload = {
  contextID: text
}
]]></sourcecode></figure>

</section>
<section anchor="cbor-examples"><name>CBOR Examples</name>

<t>This section contains a few examples of the DataSubscription struct 
depicted in CBOR diagnostic notation.</t>

<figure title="Onboarded BLE Device Advertisement"><artwork><![CDATA[
[
  {
    "data": h'02011A020A0C16FF4C001007721F41B0392078',
    "deviceID": "75fde96d-886f-4ac0-a1d5-df79f76e7c9c",
    "timestamp": 1727484393,
    "bleAdvertisement": {
        "macAddress": "C1:5C:00:00:00:01",
        "rssi": -25
    }
  }
]
]]></artwork></figure>

<figure title="Non-onboarded BLE Device Advertisement"><artwork><![CDATA[
[
  {
    "data": h'02011A020A0C16FF4C001007721F41B0392078',
    "timestamp": 1727484393,
    "bleAdvertisement": {
        "macAddress": "C1:5C:00:00:00:01",
        "rssi": -25
    }
  }
]
]]></artwork></figure>

<figure title="BLE GATT Notification"><artwork><![CDATA[
[
  {
    "data": h'434630374346303739453036',
    "deviceID": "75fde96d-886f-4ac0-a1d5-df79f76e7c9c",
    "timestamp": 1727484393,
    "bleSubscription": {
        "serviceID": "a4e649f4-4be5-11e5-885d-feff819cdc9f",
        "characteristicID": "c4c1f6e2-4be5-11e5-885d-feff819cdc9f"
    }
  }
]
]]></artwork></figure>

<figure title="BLE Connection status event"><artwork><![CDATA[
[
  {
    "deviceID": "75fde96d-886f-4ac0-a1d5-df79f76e7c9c",
    "timestamp": 1727484393,
    "bleConnectionStatus": {
        "macAddress": "C1:5C:00:00:00:01",
        "connected": true
    }
  }
]
]]></artwork></figure>

<figure title="Zigbee Attribute Notification"><artwork><![CDATA[
[
  {
    "data": h'434630374346303739453036',
    "deviceID": "75fde96d-886f-4ac0-a1d5-df79f76e7c9c",
    "timestamp": 1727484393,
    "zigbeeSubscription": {
        "endpointID": 1,
        "clusterID": 6,
        "attributeID": 12,
        "type": 1
    }
  }
]
]]></artwork></figure>

</section>
</section>
<section anchor="examples"><name>Examples</name>

<t>This section contains a few examples on how applications can leverage 
NIPC operations to communicate with BLE and Zigbee devices.</t>

<section anchor="property-readwrite"><name>Property Read/Write</name>

<t>In this example, we will connect to a device and read and write from a
property.</t>

<t>The sequence of operations for this are:</t>

<t><list style="symbols">
  <t>Onboard a device using the SCIM Interface (out of scope of this
memo)</t>
  <t>Register an SDF model for the device  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

POST /registration/model
Content-Type: application/sdf+json
Accept: application/nipc+json
Host: localhost

{ ... }

HTTP/1.1 200 OK
content-type: application/nipc+json

[
  {
    "sdfName": "https://example.com/thermometer#/sdfThing/thermom\
eter"
  }
]
]]></artwork></figure>
  <vspace blankLines='1'/>
Request Body: JSON object with the SDF model, from <xref target="thermometer-sdf"/></t>
  <t>Read a property from the BLE device  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

GET /devices/12345678-1234-5678-1234-56789abcdef4/properties?prop\
ertyName=https%3A%2F%2Fexample.com%2Fthermometer%23%2FsdfThing%2F\
thermometer%2FsdfProperty%2Fdevice_name
Accept: application/nipc+json
Host: localhost

HTTP/1.1 200 OK
content-type: application/nipc+json

[
  {
    "property": "https://example.com/thermometer#/sdfThing/thermo\
meter/sdfProperty/device_name",
    "value": "dGVzdA=="
  }
]
]]></artwork></figure>
  </t>
  <t>Write to a property on the BLE device  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

PUT /devices/12345678-1234-5678-1234-56789abcdef4/properties
Content-Type: application/nipc+json
Host: localhost

[
  {
    "property": "https://example.com/thermometer#/sdfThing/thermo\
meter/sdfProperty/device_name",
    "value": "dGVzdA=="
  }
]

HTTP/1.1 200 OK
content-type: application/nipc+json

[
  {
    "property": "https://example.com/thermometer#/sdfThing/thermo\
meter/sdfProperty/device_name",
    "value": "dGVzdA=="
  }
]
]]></artwork></figure>
  </t>
</list></t>

</section>
<section anchor="enabling-an-event"><name>Enabling an Event</name>

<t>In this example, we will onboard a device, and setup an advertisement
subscription event for that device.</t>

<t>The sequence of operations for this are:</t>

<t><list style="symbols">
  <t>Onboard a device and endpoint app using the SCIM Interface (out of scope of this
   memo)</t>
  <t>Register an SDF model for the device  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

POST /registration/data-app?dataAppId=23456789-1234-5678-1234-567\
89abcdef4
Content-Type: application/nipc+json
Accept: application/nipc+json
Host: localhost

{
  "events": [
    "https://example.com/thermometer#/sdfThing/thermometer/sdfEve\
nt/isPresent"
  ],
  "mqttClient": true
}

HTTP/1.1 200 OK
content-type: application/nipc+json

{
  "events": [
    "https://example.com/thermometer#/sdfThing/thermometer/sdfEve\
nt/isPresent"
  ],
  "mqttClient": true
}
]]></artwork></figure>
  <vspace blankLines='1'/>
Request Body: JSON object with the SDF model, from <xref target="thermometer-sdf"/></t>
  <t>Register the data app with the event  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

POST /registration/data-app?dataAppId=23456789-1234-5678-1234-567\
89abcdef4
Content-Type: application/nipc+json
Accept: application/nipc+json
Host: localhost

{
  "events": [
    "https://example.com/thermometer#/sdfThing/thermometer/sdfEve\
nt/isPresent"
  ],
  "mqttClient": true
}

HTTP/1.1 200 OK
content-type: application/nipc+json

{
  "events": [
    "https://example.com/thermometer#/sdfThing/thermometer/sdfEve\
nt/isPresent"
  ],
  "mqttClient": true
}
]]></artwork></figure>
  </t>
  <t>Enable the advertisement event  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

POST /devices/12345678-1234-5678-1234-56789abcdef4/events?eventNa\
me=https%23%2F%2Fexample.com%2Fthermometer%23%2FsdfThing%2Fthermo\
meter%2FsdfEvent%2FisPresent
Host: localhost
Content-Length: 0

HTTP/1.1 201 Created
Location: /devices/12345678-1234-5678-1234-56789abcdef4/events?in\
stanceId=87654321-4321-8765-4321-fedcba9876543
]]></artwork></figure>
  </t>
  <t>Check the status of the event  <vspace blankLines='1'/>
    <figure><artwork><![CDATA[
============== NOTE: '\' line wrapping per RFC 8792 ==============

GET /devices/12345678-1234-5678-1234-56789abcdef4/events?instance\
Id=87654321-4321-8765-4321-fedcba9876543
Host: localhost

HTTP/1.1 200 OK
content-type: application/nipc+json

{
  "event": "https://example.com/thermometer#/sdfThing/thermometer\
/sdfEvent/isPresent"
}
]]></artwork></figure>
  </t>
</list></t>

</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<section anchor="api-authorization"><name>API authorization</name>

<t>In order to enable a network wishing to offer NIPC ALG functions, the network
administrator authorizes application(s) to perform operations on the Gateway.
This happens out of band and may be accomplished by means of exchanging tokens
or public keys.
Authorization can be role-based. The 3 primary roles are:</t>

<t><list style="numbers" type="1">
  <t>Onboarding: Authorize an onboarding application against a SCIM server
co-located with the gateway.</t>
  <t>Control: Authorize applications that may control devices.</t>
  <t>Data: Authorize applications that may receive telemetry.<br />
It is possible to further refine roles down to an API basis.</t>
</list></t>

</section>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<t>This section provides guidance to the Internet Assigned Numbers Authority
(IANA) regarding registration of values related to NIPC, in accordance
with <xref target="RFC8126"/>.</t>

<section anchor="iana-media-types"><name>Media Type Registration</name>

<t>This document registers the "application/nipc+json" media type 
for messages of the NIPC APIs defined in this document carrying
parameters encoded in JSON.</t>

<t>Type name: application</t>

<t>Subtype name: nipc+json</t>

<t>Required parameters: none</t>

<t>Optional parameters: none</t>

<t>Encoding considerations: Encoding considerations are identical to those specified for the "application/json" media type.</t>

<t>Security considerations: See the <xref target="security-considerations"/> section of this document.</t>

<t>Interoperability considerations: none</t>

<t>Published specification: This document, the NIPC API specification.</t>

<t>Applications that use this media type:</t>

<t>Fragment identifier considerations: none</t>

<t>Additional information:</t>

<t><list style="symbols">
  <t>Deprecated alias names for this type: none</t>
  <t>Magic number(s): none</t>
  <t>File extension(s): none</t>
  <t>Macintosh file type code(s): none</t>
</list></t>

<t>Person &amp; email address to contact for further information:</t>

<t>Intended usage: LIMITED USE</t>

<t>Restrictions on usage: To be used for NIPC APIs as defined in this document.</t>

<t>Author:</t>

<t>Change controller: IETF</t>

</section>
<section anchor="iana-api-ext"><name>API extensions</name>

<t>IANA is requested to create a new registry called "NIPC API extensions".</t>

<t>The registry must contain following attributes:</t>

<t><list style="symbols">
  <t>Extension URI</t>
  <t>Extension name</t>
  <t>Description</t>
  <t>Openapi model describing the extension. This model must be reviewed by an expert.</t>
</list></t>

<t>Following API extensions are described in this document:</t>

<texttable>
      <ttcol align='left'>Extension URI</ttcol>
      <ttcol align='left'>Extension name</ttcol>
      <ttcol align='left'>Description</ttcol>
      <ttcol align='left'>Model reference</ttcol>
      <c>/extension/{id}/bulk</c>
      <c>Bulk API</c>
      <c>Call multiple NIPC's in a single request</c>
      <c><xref target="NIPCextensions"/></c>
      <c>/extension/{id}/properties/file</c>
      <c>File write API</c>
      <c>Write a file with multiple property ops</c>
      <c><xref target="NIPCextensions"/></c>
      <c>/extension/{id}/properties/blob</c>
      <c>Binary write API</c>
      <c>Write a binary blob with multiple property ops</c>
      <c><xref target="NIPCextensions"/></c>
      <c>/extensions/{id}/properties/read/conditional</c>
      <c>Read conditional API</c>
      <c>Read a property until a condition is fulfilled</c>
      <c><xref target="NIPCextensions"/></c>
      <c>/extensions/{id}/firmware</c>
      <c>Firmware upgrade API</c>
      <c>Firmware upgrade API, leveraging mutiple opsed</c>
      <c><xref target="NIPCextensions"/></c>
      <c>/extensions/{id}/manage/transmit</c>
      <c>Transmit API</c>
      <c>Transmits a payload to a device</c>
      <c><xref target="NIPCextensions"/></c>
</texttable>

</section>
<section anchor="iana-well-known"><name>Well-known URIs</name>

<t>IANA is requested to register the following well-known URI in the "Well-Known URIs" registry as defined by <xref target="RFC8615"/>:</t>

<texttable>
      <ttcol align='left'>URI Suffix</ttcol>
      <ttcol align='left'>Change Controller</ttcol>
      <ttcol align='left'>Specification Document</ttcol>
      <c>nipc</c>
      <c>IETF</c>
      <c>This document, <xref target="paths-general"></xref></c>
</texttable>

<t>The well-known URI for NIPC is:</t>

<figure><artwork><![CDATA[
/.well-known/nipc
]]></artwork></figure>

</section>
<section anchor="iana-problem-details"><name>Problem Details for NIPC APIs</name>

<t>IANA is requested to create a new registry, the "NIPC Problem Type" registry, 
with following URL: <eref target="https://www.iana.org/assignments/nipc-problem-types"></eref>.</t>

<t>Registrations MUST use the prefix <eref target="&quot;https://iana.org/assignments/nipc-problem-types#&quot;"></eref> for the type URI.</t>

<t>The registration requests MUST use the template defined in <xref section="4.2" sectionFormat="of" target="RFC9457"/>.</t>

<t>IANA is requested to register the following URIs in the "NIPC Problem Type" 
registry:</t>

<texttable>
      <ttcol align='left'>Problem Type URI</ttcol>
      <ttcol align='left'>Description</ttcol>
      <ttcol align='left'>Reference</ttcol>
      <c>https://www.iana.org/assignments/nipc-problem-types#invalid-id</c>
      <c>Invalid device ID or gateway doesn't recognize the ID</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#invalid-sdf-url</c>
      <c>Invalid SDF URL or SDF affordance not found</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#extension-operation-not-executed</c>
      <c>Operation was not executed since the previous operation failed</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#sdf-model-already-registered</c>
      <c>SDF model already registered</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#sdf-model-in-use</c>
      <c>SDF model in use</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#property-not-readable</c>
      <c>Property not readable</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#property-not-writable</c>
      <c>Property not writable</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#event-already-enabled</c>
      <c>Event already enabled</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#event-not-enabled</c>
      <c>Event not enabled</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#event-not-registered</c>
      <c>Event not registered for any data application</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-already-connected</c>
      <c>Device already connected</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-no-connection</c>
      <c>No connection found for device</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-connection-timeout</c>
      <c>BLE connection timeout</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-bonding-failed</c>
      <c>BLE bonding failed</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-connection-failed</c>
      <c>BLE connection failed</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-service-discovery-failed</c>
      <c>BLE service discovery failed</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-ble-invalid-service-or-characteristic</c>
      <c>Invalid BLE service or characteristic ID</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-zigbee-connection-timeout</c>
      <c>Zigbee connection timeout</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#protocolmap-zigbee-invalid-endpoint-or-cluster</c>
      <c>Invalid Zigbee endpoint or cluster ID</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#extension-broadcast-invalid-data</c>
      <c>Invalid transmit data</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#extension-firmware-rollback</c>
      <c>Firmware rollback</c>
      <c>This document</c>
      <c>https://www.iana.org/assignments/nipc-problem-types#extension-firmware-update-failed</c>
      <c>Firmware update failed</c>
      <c>This document</c>
</texttable>

<t>Each Problem Type URI is intended for use as the "type" member in Problem Details responses as described.</t>

</section>
</section>


  </middle>

  <back>


<references title='References' anchor="sec-combined-references">

    <references title='Normative References' anchor="sec-normative-references">

&RFC7644;
&I-D.ietf-scim-device-model;
&RFC2119;
&RFC8174;
&I-D.ietf-asdf-sdf;
&I-D.mohan-asdf-sdf-protocol-mapping;
&RFC9114;
&RFC7159;
&RFC8949;
&RFC3986;
&RFC6570;
&RFC9457;
&RFC4648;
&RFC8610;
&RFC8126;
&RFC8615;


    </references>

    <references title='Informative References' anchor="sec-informative-references">

<reference anchor="BLE53" >
  <front>
    <title>Bluetooth Core Specification, Version 5.3</title>
    <author >
      <organization>Bluetooth SIG</organization>
    </author>
    <date year="2021"/>
  </front>
</reference>
<reference anchor="Zigbee22" >
  <front>
    <title>zigbee Specification, Version 22 1.0</title>
    <author >
      <organization>Connectivity Standards Alliance</organization>
    </author>
    <date year="2017"/>
  </front>
</reference>
<reference anchor="Gatt-REST-API" target="https://www.bluetooth.com/bluetooth-resources/gatt-rest-api/">
  <front>
    <title>A RESTful API used to access data in devices using the functionality defined in the Bluetooth GATT profile</title>
    <author >
      <organization>Bluetooth SIG</organization>
    </author>
    <date year="2017"/>
  </front>
</reference>


    </references>

</references>


<?line 2233?>

<section anchor="openapi-definition"><name>OpenAPI definition</name>

<t>The following non-normative model is provide for convenience of
the implementor.</t>

<figure anchor="openAPI"><artwork><![CDATA[
<CODE BEGINS>
file "openapi.yml"
=============== NOTE: '\\' line wrapping per RFC 8792 ===============

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
\2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API
  description: |-
    This API specifies RESTful application layer interface for
    gateways providing operations against non-IP devices. The
    described interface is extensible. The examples includes
    leverage Bluetooth Low Energy and Zigbee as they are commonly
    deployed.
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name: NIPC property APIs
    description: |-
      APIs that allow apps to get and update device properties.
      If the underlying protocol requires connection management, it
      will be performed as part of the API call.
  - name: NIPC event APIs
    description: |-
      APIs that allow apps to enable or disable event reporting on
      devices. If the underlying protocol requires connection
      management, it will be performed as part of the API call.
  - name: NIPC action APIs
    description: |-
      APIs that perform actions on devices.
  - name: NIPC management APIs
    description: |-
      APIs that manage device connections.
  - name: NIPC registration APIs
    description: |-
      APIs that register sdf models or data applications

paths:
### NIPC Property APIs
  /devices/{id}/properties:
    put:
      tags:
        - NIPC property APIs
      summary: Update a value of one or more properties on a device
      description: |-
        Write a value to a property or multiple properties to a
        device. If underlying protocol requires a connection to be
        set up, this API call will perform the necessary connection
        management. If a connection is already active for this
        device, the existing connection will be leveraged without
        modifying it.
      operationId: UpdateProperties
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be written to.
        required: false
        allowReserved: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
\tat/sdfProperty/temperature"
      requestBody:
        description: |-
          The value to be written to the property or properties.
          If multiple properties are specified, the request body
          should be application/nipc+json.
        content:
          application/nipc+json:
            schema:
              $ref: '#/components/schemas/PropertyValueArray'
          "*/*":
            schema:
              description: |-
                Any other content type, such as 
                application/octet-stream, application/json that will 
                be written to the device.
        required: true
      responses:
        '204':
          description: |-
            Success, no content, used for a single property write
        '200':
          description: Success, used for multiple property writes
          content:
            application/nipc+json:
              schema:
                allOf: 
                  - $ref: '#/components/schemas/PropertyValueRespons\
\eArray'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'

    get:
      tags:
        - NIPC property APIs
      summary: |-
        Read a value from one or multiple properties on a device
      description: |-
        Read a value to a property or multiple properties from a
        device. If underlying protocol requires a connection to be
        set up, this API call will perform the necessary connection
        management. If a connection is already active for this
        device, the existing connection will be leveraged without
        modifying it. 
      operationId: GetProperties
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: Properties to be read
        required: true
        allowReserved: true
        schema:
          type: array
          items:
            type: string
            example: "https://example.com/heartrate#/sdfObject/therm\
\ostat/sdfProperty/temperature"
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf: 
                  - $ref: '#/components/schemas/Id'
                  - $ref: '#/components/schemas/PropertyValueReadRes\
\ponseArray'
            "*/*":
              schema:
                type: string
                description: |-
                  Any other content type, such as
                  application/octet-stream, application/json that 
                  will be read from the device.
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
 
 ### NIPC Event APIs
  /devices/{id}/events:
    post:
      tags:
        - NIPC event APIs
      summary: Enable an event on a specific device
      description: |-
        Enable an event on a specific device or for a group of
        devices. If the underlying protocol requires a connection to
        be set up, this API call will perform the necessary
        connection management. If a connection is already active for
        this device, the existing connection will be leveraged
        without modifying it.
      operationId: EnableEvent
      parameters:
      - name: id
        in: path
        description: device id or group id
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: eventName
        in: query
        description: event that needs to be enabled
        required: true
        allowReserved: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/healths\
\ensor/sdfEvent/fallDetected"
      responses:
        '201':
          description: Success
          headers:
            Location:
              description: Location of the created event
              schema:
                type: string
                format: uri
                example: "/devices/{id}/events?instanceId={instanceI\
\d}"
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'

    delete:
      tags:
        - NIPC event APIs
      summary: Disable an event on a specific device
      description: |-
        Disable an event on a specific device or a group of devices.
        If the underlying protocol requires a connection to be set
        up, this API call will perform the necessary connection
        management. If a connection is already active for this
        device, the existing connection will be leveraged without
        modifying it.
      operationId: DisableEvent
      parameters:
      - name: id
        in: path
        description: device id or group id
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: instanceId
        in: query
        description: instance id of the event that needs to be disab\
\led
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '204':
          description: Success, no content
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
               
    get:
      tags:
        - NIPC event APIs
      summary: Get status of events on a device
      description: |-
        Get status of an event or multiple events on a specific devi\
\ce
      operationId: GetEvents
      parameters:
      - name: id
        in: path
        description: The ID of the device.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: instanceId
        in: query
        description: |-
          Instance ID of the events that need to be filtered
        required: false
        schema:
          type: array
          items:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                $ref: '#/components/schemas/EventStatusResponseArray'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'

  /groups/{id}/events:
    post:
      tags:
        - NIPC event APIs
      summary: Enable an event on a group of devices
      description: |-
        Enable an event on a group of devices.
        If the underlying protocol requires a connection to be set
        up, this API call will perform the necessary connection
        management. If a connection is already active for this
        device, the existing connection will be leveraged without
        modifying it.
      operationId: EnableGroupEvent
      parameters:
      - name: id
        in: path
        description: |-
          group id for which the event needs to be enabled
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: eventName
        in: query
        description: event that needs to be enabled
        required: true
        allowReserved: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/healths\
\ensor/sdfEvent/fallDetected"
      responses:
        '201':
          description: Success, event enabled
          headers:
            Location:
              description: Location of the created event
              schema:
                type: string
                format: uri
                example: "/groups/{id}/events?instanceId={instanceId\
\}"
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
    delete:
      tags:
        - NIPC event APIs
      summary: Disable an event on a group of devices
      description: |-
        Disable an event on a group of devices. If the underlying
        protocol requires a connection to be set up, this API call
        will perform the necessary connection management.
        If a connection is already active for this device, the
        existing connection will be leveraged without modifying it.
      operationId: DisableGroupEvent
      parameters:
      - name: id
        in: path
        description: |-
          group id for which the event needs to be disabled
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: instanceId
        in: query
        description: instance id of the event that needs to be disab\
\led
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '204':
          description: Success, no content
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
    get:
      tags:
        - NIPC event APIs
      summary: Get status of events on a group of devices
      description: |-
        Get status of an event or multiple events on a group of devi\
\ces.
      operationId: GetGroupEvents
      parameters:
      - name: id
        in: path
        description: group id of the SCIM group
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: instanceId
        in: query
        description: |-
          Instance IDs of the events that need to be filtered
        required: false
        schema:
          type: array
          items:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success, events retrieved
          content:
            application/nipc+json:
              schema:
                $ref: '#/components/schemas/EventStatusResponseArray'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'

### NIPC action APIs
  /devices/{id}/actions:
    post:
      tags:
        - NIPC action APIs
      summary: Perform an action on a device
      description: |-
        Perform an action on a device.
        If the underlying protocol requires a connection to be set
        up, this API call will perform the necessary connection
        management. If a connection is already active for this
        device, the existing connection will be leveraged without
        modifying it.
      operationId: ActionProperty
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: actionName
        in: query
        description: action that needs to be performed
        required: true
        allowReserved: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/healths\
\ensor/sdfAction/start"
      requestBody:
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
        required: false
      responses:
        '202':
          description: Accepted, action is being performed
          headers:
            Location:
              description: Location of the action
              schema:
                type: string
                format: uri
                example: "/devices/{id}/actions?instanceId={instance\
\Id}"
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
    get:
      tags:
        - NIPC action APIs
      summary: Get status of an action on a device
      description: |-
        Get status of an action on a specific device or a group of
        devices. Success is action is active, failure if action not
        active.
      operationId: GetAction
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: instanceId
        in: query
        description: |-
          instance id of the action that needs to be checked
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success, action is active
          content:
            application/nipc+json:
              schema:
                $ref: '#/components/schemas/ActionResponse'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
               
  /devices/{id}/connections:
    post:
      tags:
        - NIPC management APIs
      summary: Connect a device
      description: |-
        Connect a device. 3 retries by default, optionally retry
        policy can be defined in the API body. If the protocol
        requires service discovery, full service discovery will be
        performed, unless specific services are described in the API
        body.
      operationId: ActionCreateConnection
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/nipc+json:
            schema:
              anyOf:
                - $ref: '#/components/schemas/Connection'
                - $ref: './protocolmaps/ProtocolMap.yaml#/components\
\/schemas/ProtocolMap-ServiceList'
        required: false
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Id'
                  - $ref: './protocolmaps/ProtocolMap.yaml#/componen\
\ts/schemas/ProtocolMap-ServiceMap'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
  
    put:
      tags:
        - NIPC management APIs
      summary: Update cached ServiceMap for a device.
      description: |-
        Update cached ServiceMap for a device. Full service discovery
        will be performed, unless specific services are described in
        the API body.
      operationId: ActionUpdateServiceMap
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/nipc+json:
            schema:
              $ref: './protocolmaps/ProtocolMap.yaml#/components/sch\
\emas/ProtocolMap-ServiceList'
        required: false
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Id'
                  - $ref: './protocolmaps/ProtocolMap.yaml#/componen\
\ts/schemas/ProtocolMap-ServiceMap'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
  
    delete:
      tags:
        - NIPC management APIs
      summary: Disconnect a device 
      description: |-
        Disconnect a device.
      operationId: ActionDeleteConnection
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Id'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'
                  
    get:
      tags:
        - NIPC management APIs
      summary: Get connection state for a device
      description: |-
        Get connection status for a device. Success when device(s)
        is/are connected, includes service map for the device if
        available. Failure when a device is not connected
      operationId: ActionGetConnection
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Id'
                  - $ref: './protocolmaps/ProtocolMap.yaml#/componen\
\ts/schemas/ProtocolMap-ServiceMap'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/FailureResponse'


### Registrations
  /registrations/models:
    post:
      tags:
        - NIPC registration APIs
      summary: Register an sdfObject
      description: |-
        Register an sdfObject, including Properties, Events and
        actions
      operationId: registerSdfObject
      requestBody:
        content:
          application/sdf+json:
            schema:
              $ref: '#/components/schemas/SdfModel'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                type: array
                items:
                  allOf:
                    - $ref: '#/components/schemas/SdfReference'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'

    get:
      tags:
        - NIPC registration APIs
      summary: Get all registered SDF model names
      description: |-
        Get all registered SDF model names.
      operationId: getSdfRefs
      parameters:
        - name: sdfName
          in: query
          description: |-
            sdfName can be a reference to an sdfThing or sdfObject
          required: false
          allowReserved: true
          schema:
            type: string
            example: "https://example.com/heartrate#/sdfObject/healt\
\hsensor"
      responses:
        '200':
          description: Success
          content:
            application/sdf+json:
              schema:
                $ref: '#/components/schemas/SdfModel'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'
    put:
      tags:
        - NIPC registration APIs
      summary: Update an SDF model
      description: |-
        Update an SDF model, including Properties, Events and
        actions
      operationId: updateSdf
      parameters:
        - name: sdfName
          in: query
          description: |-
            sdfName can be a reference to an sdfThing or sdfObject
          required: true
          allowReserved: true
          schema:
            type: string
            example: "https://example.com/heartrate#/sdfObject/healt\
\hsensor"
      requestBody:
        content:
          application/sdf+json:
            schema:
              $ref: '#/components/schemas/SdfModel'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SdfReference'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'
 
    delete:
      tags:
        - NIPC registration APIs
      summary: Delete an sdfObject
      description: |-
        Delete an sdfObject, including Properties, Events and
        actions
      operationId: deleteSdfObject
      parameters:
        - name: sdfName
          in: query
          description: sdfObject name
          required: true
          schema:
            type: string
            example: "https://example.com/heartrate#/sdfObject/healt\
\hsensor"
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SdfReference'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'

  /registrations/data-apps:
    post:
      tags:
        - NIPC registration APIs
      summary: Register a dataApp
      description: |-
        Register a dataApp that is able to receive device data. 
      operationId: registerDataApp
      parameters:
        - name: dataAppId
          in: query
          description: id of the data app that will be registered
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/nipc+json:
            schema:
              $ref: '#/components/schemas/DataApp'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/DataApp'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'

    put:
      tags:
        - NIPC registration APIs
      summary: Update registration of a dataApp
      description: |-
        Update registration of a dataApp that is able to receive dev\
\ice data. 
      operationId: UpdateDataApp
      parameters:
        - name: dataAppId
          in: query
          description: id of the data app that will be updated
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/nipc+json:
            schema:
              $ref: '#/components/schemas/DataApp'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/DataApp'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'
                  
    delete:
      tags:
        - NIPC registration APIs
      summary: Delete registration of a dataApp
      description: |-
        Delete registration of a dataApp that is able to receive
        device data. 
      operationId: DeleteDataApp
      parameters:
        - name: dataAppId
          in: query
          description: id of the data app that will be updated
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/DataApp'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'
  
    get:
      tags:
        - NIPC registration APIs
      summary: Get registration of a dataApp
      description: |-
        Get registrationdetails of a dataApp that is able to receive
        device data. 
      operationId: GetDataApp
      parameters:
        - name: dataAppId
          in: query
          description: id of the data app that will be updated
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          content:
            application/nipc+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/DataApp'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/FailureResponse'

components:
  schemas:
# Base objects
## A SCIM id, can be a device or a group
    Id:
      required:
        - id
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: |-
            A SCIM-generated UUID, can be a device or group
          example: 12345678-1234-5678-1234-56789abcdef4

## A property
    Property:
      required:
        - property
      type: object
      properties:
        property:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
\tat/sdfProperty/temperature"

    ActionResponse:
      required:
        - action
      type: object
      properties:
        status:
          type: string
          example: COMPLETED
          description: |-
            Status of the action, can be IN_PROGRESS or COMPLETED

## A value
    Value:
      required:
        - value
      type: object
      properties:
        value:
          type: string
          format: byte
          example: dGVzdA==

## A value of an property of an Device
    PropertyValue:
      allOf:
        - $ref: '#/components/schemas/Property'
        - $ref: '#/components/schemas/Value'

## An array of Property values
    PropertyValueArray:
      type: array
      items:
        $ref: '#/components/schemas/PropertyValue'

## Event
    Event:
      required:
        - event
      type: object
      properties:
        event:
          type: string
          description: |-
            percent-encoded JSON pointer to the SDF event object
          example: https://example.com/heartrate#/sdfObject/healthse\
\nsor/sdfEvent/fallDetected

    InstanceId:
      type: object
      properties:
        instanceId:
          type: string
          format: uuid
          description: |-
            A SCIM-generated UUID for the event instance
          example: 12345678-1234-5678-1234-56789abcdef4
            
## A Connection
    Connection:
      type: object
      properties:
        retries:
          type: integer
          format: int32
          example: 3
        retryMultipleAPs:
          type: boolean
          example: true
          
 ## DataApp
    DataApp:
      oneOf:
        - $ref: '#/components/schemas/DataAppMqttClient'
        - $ref: '#/components/schemas/DataAppMqttBroker'
        - $ref: '#/components/schemas/DataAppWebhook'
        - $ref: '#/components/schemas/DataAppWebsocket'
      type: object
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/Event'


    DataAppMqttClient:
      type: object
      properties: 
        mqttClient:
          type: boolean

    DataAppMqttBroker:
      type: object
      properties: 
        mqttBroker:
          type: object
          required:
            - URI
            - username
            - password
          properties: 
            URI: 
              type: string
              example: mqtt.broker.com:8883
            username:
              type: string
              example: user1
            password: 
              type: string
              example: password1
            brokerCACert:
              description: PEM encoded CA certificate
              type: string
            customTopic:
              type: string
              description: custom MQTT topic to publish to
              example: custom/topic
      
    DataAppWebhook:
      type: object
      properties: 
        webhook:
          type: object
          properties: 
            URI: 
              type: string
              example: webhook.com:443
            headers:
              type: object
              additionalProperties:
                type: string
              example:
                x-api-key: fjelk-3dl33f-2wdsd
            serverCACert: 
              type: string 
          
    DataAppWebsocket:
      type: object
      properties: 
        websocket:
          type: object
          properties: 
            URI: 
              type: string
              example: websocket.com:443
            headers:
              type: object
              additionalProperties:
                type: string
              example:
                x-api-key: fjelk-3dl33f-2wdsd
            serverCACert: 
              type: string 

 ## sdfObject registration definition
    SdfReference:
      type: object
      description: SDF URL referring to the sdfobject
      properties: 
        sdfName:
          type: string
          example: "https://example.com/heartrate#/sdfObject/healths\
\ensor"
    
    SdfModel:
      allOf:
        - type: object
          description: Sample SDF model
          properties:
            namespace:
              type: object
              additionalProperties:
                type: string
              example:
                heartrate: https://example.com/heartrate
            defaultNamespace:
              type: string
              example: heartrate
        - oneOf:
          - $ref: '#/components/schemas/SdfThing'
          - $ref: '#/components/schemas/SdfObject'

    SdfThing:
      type: object
      description: Sample SDF thing
      properties:
        sdfThing:
          additionalProperties:
            anyOf:
                - $ref: '#/components/schemas/SdfProperty'
                - $ref: '#/components/schemas/SdfEvent'
                - $ref: '#/components/schemas/SdfAction'
                - $ref: '#/components/schemas/SdfObject'
          example:
            multipleSensor:
              sdfEvent:
                isPresent:
                  sdfOutputData:
                    sdfProtocolMap:
                      ble:
                        type: advertisement
              sdfObject:
                healthsensor:
                  sdfProperty:
                    heartrate:
                      sdfProtocolMap:
                        ble:
                          serviceID: 12345678-1234-5678-1234-56789ab\
\cdef4
                          characteristicID: 12345678-1234-5678-1234-\
\56789abcdef4
                  sdfEvent:
                    fallDetected:
                      sdfOutputData:
                        sdfProtocolMap:
                          ble:
                            serviceID: 12345678-1234-5678-1234-56789\
\abcdef4
                            characteristicID: 12345678-1234-5678-123\
\4-56789abcdef4
                  sdfAction:
                    start:
                      sdfProtocolMap:
                        ble:
                          serviceID: 12345678-1234-5678-1234-56789ab\
\cdef4
                          characteristicID: 12345678-1234-5678-1234-\
\56789abcdef4

    SdfObject:
      type: object
      description: Sample SDF object
      properties:
        sdfObject:
          additionalProperties:
            anyOf:
              - $ref: '#/components/schemas/SdfProperty'
              - $ref: '#/components/schemas/SdfEvent'
              - $ref: '#/components/schemas/SdfAction'
          example:
            healthsensor:
              sdfProperty:
                heartrate:
                  sdfProtocolMap:
                    ble:
                      serviceID: 12345678-1234-5678-1234-56789abcdef4
                      characteristicID: 12345678-1234-5678-1234-5678\
\9abcdef4
              sdfEvent:
                fallDetected:
                  sdfOutputData:
                    sdfProtocolMap:
                      ble:
                        serviceID: 12345678-1234-5678-1234-56789abcd\
\ef4
                        characteristicID: 12345678-1234-5678-1234-56\
\789abcdef4
              sdfAction:
                start:
                  sdfProtocolMap:
                    ble:
                      serviceID: 12345678-1234-5678-1234-56789abcdef4
                      characteristicID: 12345678-1234-5678-1234-5678\
\9abcdef4

    SdfProperty:
      type: object
      description: Sample SDF property
      properties:
        sdfProperty:
          additionalProperties: 
            allOf:
              - $ref: './protocolmaps/ProtocolMap.yaml#/components/s\
\chemas/ProtocolMap-Property'
          example:
            heartrate:
              sdfProtocolMap:
                ble:
                  serviceID: 12345678-1234-5678-1234-56789abcdef4
                  characteristicID: 12345678-1234-5678-1234-56789abc\
\def4
          
    SdfEvent:
      type: object
      description: Sample SDF property
      properties:
        sdfEvent:
          additionalProperties: #example, this will be the registere\
\d event
            type: object
            properties:
              sdfOutputData:
                allOf:
                  - $ref: './protocolmaps/ProtocolMap.yaml#/componen\
\ts/schemas/ProtocolMap-Event'
          example:
            fallDetected:
              sdfOutputData:
                sdfProtocolMap:
                  ble:
                    serviceID: 12345678-1234-5678-1234-56789abcdef4
                    characteristicID: 12345678-1234-5678-1234-56789a\
\bcdef4
    
    SdfAction:
      type: object
      description: Sample SDF property
      properties:
        sdfAction:
          additionalProperties: 
            allOf:
              - $ref: './protocolmaps/ProtocolMap.yaml#/components/s\
\chemas/ProtocolMap-Property'
          example:
            start:
              sdfProtocolMap:
                ble:
                  serviceID: 12345678-1234-5678-1234-56789abcdef4
                  characteristicID: 12345678-1234-5678-1234-56789abc\
\def4

# responses

    SuccessResponse:
      type: object
      properties:
        status:
          type: integer
          format: int32
          example: 200
          description: HTTP status code

## Error 500 application Failure response
    FailureResponse:
      type: object
      properties:
        type:
          type: string
          description: URI to the error type
          enum:
            - https://www.iana.org/assignments/nipc-problem-types#in\
\valid-id
            - https://www.iana.org/assignments/nipc-problem-types#in\
\valid-sdf-url
            - https://www.iana.org/assignments/nipc-problem-types#ex\
\tension-operation-not-executed
            - https://www.iana.org/assignments/nipc-problem-types#sd\
\f-model-already-registered
            - https://www.iana.org/assignments/nipc-problem-types#sd\
\f-model-in-use
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\operty-not-readable
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\operty-not-writable
            - https://www.iana.org/assignments/nipc-problem-types#ev\
\ent-already-enabled
            - https://www.iana.org/assignments/nipc-problem-types#ev\
\ent-not-enabled
            - https://www.iana.org/assignments/nipc-problem-types#ev\
\ent-not-registered
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-already-connected
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-no-connection
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-connection-timeout
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-bonding-failed
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-connection-failed
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-service-discovery-failed
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-ble-invalid-service-or-characteristic
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-zigbee-connection-timeout
            - https://www.iana.org/assignments/nipc-problem-types#pr\
\otocolmap-zigbee-invalid-endpoint-or-cluster
            - https://www.iana.org/assignments/nipc-problem-types#ex\
\tension-broadcast-invalid-data
            - https://www.iana.org/assignments/nipc-problem-types#ex\
\tension-firmware-rollback
            - https://www.iana.org/assignments/nipc-problem-types#ex\
\tension-firmware-update-failed
            - about:blank
        status:
          type: integer
          format: int32
          example: 400
          description: HTTP status code
        title:
          type: string
          example: Invalid Device ID
          description: Human-readable error title
        detail:
          type: string
          example: |-
            Device ID 12345678-1234-5678-1234-56789abcdef4 does not
            exist or is not a device
          description: Human-readable error message  

## Property operations responses
    
    PropertyValueResponseArrayItem:
      oneOf:
        - $ref: '#/components/schemas/SuccessResponse'
        - $ref: '#/components/schemas/FailureResponse'
    
    PropertyValueResponseArray:
      type: array
      items:
          $ref: '#/components/schemas/PropertyValueResponseArrayItem'

    PropertyValueReadResponseArrayItem:
      oneOf:
        - $ref: '#/components/schemas/PropertyValue'
        - $ref: '#/components/schemas/FailureResponse'
    
    PropertyValueReadResponseArray:
      type: array
      items:
        allOf:
          - $ref: '#/components/schemas/PropertyValueReadResponseArr\
\ayItem'

## Event operations responses
    EventStatusResponseArrayItem:
      oneOf:
        - allOf:
          - $ref: '#/components/schemas/Event'
          - $ref: '#/components/schemas/InstanceId'
        - $ref: '#/components/schemas/FailureResponse'

    EventStatusResponseArray:
      type: array
      items:
          $ref: '#/components/schemas/EventStatusResponseArrayItem'

<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="protocol-mapping"><name>Protocol mapping</name>

<t>NIPC requires that a protocol mapping be provided as part of the SDF
model for a device or have one provided using the NIPC action APIs with 
embedded protocol mapping. The protocol mapping is a JSON object that 
describes the underlying technology used to communicate with the device 
along with any additional information needed to communicate with the 
device.</t>

<t>The JSON format of the protocol mapping is provided as a non-normative
OpenAPI model for the convenience of the implementor.</t>

<section anchor="protocol-mapping-openapi-model"><name>Protocol mapping OpenAPI model</name>

<figure anchor="protocolmapmodel"><artwork><![CDATA[
<CODE BEGINS>
file "ProtocolMap.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) Protocol Mapping
  description: |-
    Non IP Device Control (NIPC) Protocol Mapping. When adding a
    new protocol mapping pls add a reference to the protocol map
    for all the schemas in this file.
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.10.0
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/

components:
  schemas:
# Protocol Mapping
## Protocol Map for Service Discovery
    ProtocolMap-ServiceList:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-ServiceList'

## Protocol Map for Service Discovery result
    ProtocolMap-ServiceMap:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-ServiceMap'
            - $ref: './ProtocolMap-Zigbee.yaml#/components/schemas/P\
rotocolMap-Zigbee-ServiceMap'
        
## Protocol Map for Error Codes
    ProtocolMap-ErrorCodes:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:  
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-ErrorCodes'
            - $ref: './ProtocolMap-Zigbee.yaml#/components/schemas/P\
rotocolMap-Zigbee-ErrorCodes'

## Protocol Map for Broadcasts
    ProtocolMap-Broadcast:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:  
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-Broadcast'
            - $ref: './ProtocolMap-Zigbee.yaml#/components/schemas/P\
rotocolMap-Zigbee-Broadcast'

## Protocol Map for a property
    ProtocolMap-Property:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:  
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-Propmap'
            - $ref: './ProtocolMap-Zigbee.yaml#/components/schemas/P\
rotocolMap-Zigbee-Propmap'

## Protocol Map for an event
    ProtocolMap-Event:
      type: object
      properties:
        sdfProtocolMap:
          oneOf:  
            - $ref: './ProtocolMap-BLE.yaml#/components/schemas/Prot\
ocolMap-BLE-Event'
            - $ref: './ProtocolMap-Zigbee.yaml#/components/schemas/P\
rotocolMap-Zigbee-Event'
 
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="protocol-map-for-ble"><name>Protocol map for BLE</name>

<figure anchor="protocolmapble"><artwork><![CDATA[
<CODE BEGINS>
file "ProtocolMap-BLE.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) BLE Protocol Mapping
  description: |-
    Non IP Device Control (NIPC) BLE Protocol Mapping. 
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.10.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/

components:
  schemas:
# BLE Protocol Mapping
## A Service is a device with optional service IDs
    ProtocolMap-BLE-ServiceList:
      type: object
      properties:
        ble:
          type: object
          properties:
            services:
              type: array
              items:
                type: object
                properties:
                  serviceID:
                    type: string
                    format: uuid
                    example: 12345678-1234-5678-1234-56789abcdef4
            cached:
              description: |-
                If we can cache information, then device doesn't need
                to be rediscovered before every connected.
              type: boolean
              default: false
            cacheIdlePurge:
              description: cache expiry period, when device allows
              type: integer
              example: 3600 # default 1 hour
            autoUpdate:
              description: |-
                autoupdate services if device supports it (default)
              type: boolean
              example: true
            bonding: #optional, by default defined in SCIM object 
              type: string
              example: default
              enum:
                - default 
                - none
                - justworks
                - passkey
                - oob

##  Protocol Mapping for BLE Service Map
    ProtocolMap-BLE-ServiceMap:
      required:
        - services
      type: object
      properties:
        ble:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-BLE-Service'

    ProtocolMap-BLE-Service:
      required:
        - serviceID
        - characteristics
      type: object
      properties:
        serviceID:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
        characteristics:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-BLE-Characterist\
ic'

    ProtocolMap-BLE-Characteristic:
      required:
        - characteristicID
        - flags
        - descriptors
      type: object
      properties:
        characteristicID:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
        flags:
          type: array
          example:
          - read
          - write
          items:
            type: string
            enum:
              - read
              - write
              - notify
        descriptors:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-BLE-Descriptor'

    ProtocolMap-BLE-Descriptor:
      required:
        - descriptorID
      type: object
      properties:
        descriptorID:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4

##  Protocol Mapping for BLE Broadcast
    ProtocolMap-BLE-Broadcast:
      required:
        - ble
      type: object
      properties:
        ble:
          type: object

## Protocol Mapping for BLE Property
    ProtocolMap-BLE-Propmap:
      required:
        - ble
      type: object
      properties:
        ble:
          required:
            - serviceID
            - characteristicID
          type: object
          properties:
            serviceID:
              type: string
              format: uuid
              example: 12345678-1234-5678-1234-56789abcdef4
            characteristicID:
              type: string
              format: uuid
              example: 12345678-1234-5678-1234-56789abcdef4
              
## Defines different types of BLE events
    ProtocolMap-BLE-Event:
      required:
        - ble
      type: object
      properties:
        ble:
          required:
            - type
          type: object
          properties:
            type:
              type: string
              example: gatt
              enum:
                - gatt
                - connection_events
                - advertisements
            serviceID:
              type: string
              example: 12345678-1234-5678-1234-56789abcdef0
            characteristicID:
              type: string
              example: 12345678-1234-5678-1234-56789abcdef1

## BLE Error codes
    ProtocolMap-BLE-ErrorCodes:
      type: object
      properties:
        nipcStatus:
          type: integer
          format: int32
          enum:
            - 1011 # BLE bonding failed
            - 1013 # BLE service discovery failed
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="protocol-map-for-zigbee"><name>Protocol map for Zigbee</name>

<figure anchor="protocolmapzigbee"><artwork><![CDATA[
<CODE BEGINS>
file "ProtocolMap-Zigbee.yaml"
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) Zigbee Protocol Mapping
  description: |-
    Non IP Device Control (NIPC) Zigbee Protocol Mapping. 
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.10.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/

components:
  schemas:
# Zigbee Protocol Mapping
##  Protocol Mapping for Zigbee Service Map
    ProtocolMap-Zigbee-ServiceMap:
      required:
        - zigbee
      type: object
      properties:
        zigbee:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-Zigbee-Endpoint'

    ProtocolMap-Zigbee-Endpoint:
      required:
        - endpointID
        - clusters
      type: object
      properties:
        endpointID:
          type: integer
          format: int32
          example: 10
        clusters:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-Zigbee-Cluster'

    ProtocolMap-Zigbee-Cluster:
      required:
        - clusterID
        - properties
      type: object
      properties:
        clusterID:
          type: integer
          format: int32
          example: 0
        properties:
          type: array
          items:
            $ref: '#/components/schemas/ProtocolMap-Zigbee-Property'

    ProtocolMap-Zigbee-Property:
      required:
        - attributeID
        - propertyType
      type: object
      properties:
        attributeID:
          type: integer
          format: int32
          example: 1
        propertyType:
          type: integer
          format: int32
          example: 32
          
## Protocol Mapping for Zigbee broadcast
    ProtocolMap-Zigbee-Broadcast:
      required:
        - zigbee
      type: object
      properties:
        zigbee:
          type: object

## Protocol mapping for Zigbee property
    ProtocolMap-Zigbee-Propmap:
      required:
        - zigbee
      type: object
      properties:
        zigbee:
          required:
            - endpointID
            - clusterID
            - attributeID
          type: object
          properties:
            endpointID:
              type: integer
              format: int32
              example: 1
            clusterID:
              type: integer
              format: int32
              example: 6
            attributeID:
              type: integer
              format: int32
              example: 16
            type:
              type: integer
              format: int32
              example: 1

    ProtocolMap-Zigbee-Event:
      allOf:  
        - $ref: '#/components/schemas/ProtocolMap-Zigbee-Propmap'

## Zigbee Error codes
    ProtocolMap-Zigbee-ErrorCodes:
      type: object
      properties:
        nipcStatus:
          type: integer
          format: int32
          enum:
            - 1021 # Zigbee join failed
<CODE ENDS>
]]></artwork></figure>

</section>
</section>
<section anchor="NIPCextensions"><name>NIPC API extensions</name>

<t>The following OpenAPI models define a few example extensions to the 
NIPC API.</t>

<section anchor="nipc-api-write-binary-blob-extension"><name>NIPC API write binary blob extension</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-Blob.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API write binary blob extension
  description: |-
    Non IP Device Control (NIPC) API write binary blob extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/properties/blob:
    put:
      tags:
        - NIPC API extensions
      summary: Write a binary blob to a property on a device
      description: |-
        Write a binary blob to a property on a device. Will chunk up
        the binary blob and perform multiple writes. If the 
        underlying protocol requires a connection to be set up, 
        this API call will perform the necessary connection 
        management. If a connection is already active for this 
        device, the existing connection will be leveraged without 
        modifying it. ID cannot be a group-id.
      operationId: writeBlob
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be written to.
        required: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
tat/sdfProperty/firmware"
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Extension-Blob'
        required: true
      responses:
        '204':
          description: Success, no content
        'default':
          description: Error response
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse' 

components:
  schemas:
# Extensions
## A binary blob Extension
    Extension-Blob:
      required:
        - blob
      type: object
      properties:
        blob:
          type: string
          format: byte
        chunksize:
          type: integer
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="nipc-api-bulk-operations-extension"><name>NIPC API bulk operations extension</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-Bulk.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API bulk extension
  description: |-
    Non IP Device Control (NIPC) API bulk extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/bulk:
    post:
      tags:
        - NIPC API extensions
      summary: Compound operations on a device
      description: Compound operations on a device
      operationId: Bulk
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Extension-Bulk'
            examples:
              bulkRequest:
                $ref: '#/components/examples/bulkRequest'
        required: true
      responses:
        '202':
          description: Accepted
          headers:
            Location:
              schema:
                type: string
              description: URL to get the bulk status response
              example: /extensions/12345678-1234-5678-1234-56789abcd\
ef4/bulk/status?requestId=12345678-1234-5678-1234-56789abcdef4
        '401':
          description: Unauthorized
        '405':
          description: Invalid request
        '500':
          description: Server-side failure
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'
      callbacks:
        bulkEvent:
          '{$request.body#/callback.url}':
            post:
              description: Callback for bulk response
              operationId: bulkCallback
              requestBody:
                content:
                  application/json:
                    schema:
                      allOf:
                        - $ref: '../NIPC.yaml#/components/schemas/Id'
                        - $ref: '#/components/schemas/Extension-Bulk\
Response'
              responses:
                '200':
                  description: OK
                '400':
                  description: Bad request
                '401':
                  description: Unauthorized
                '405':
                  description: Invalid request
                '500':
                  description: Server-side failure
    get:
      tags:
        - NIPC API extensions
      summary: Get Bulk response
      description: Get Bulk response
      operationId: getBulkResponse
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: requestId
        in: query
        description: Request ID of the bulk operation
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: OK
          headers:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../NIPC.yaml#/components/schemas/Id'
                  - $ref: '#/components/schemas/Extension-BulkRespon\
se'
              examples:
                bulkResponse:
                  $ref: '#/components/examples/bulkResponse'
                errorBulkResponse:
                  $ref: '#/components/examples/errorBulkResponse'
                
  /extensions/{id}/bulk/status:
    get:
      tags:
        - NIPC API extensions
      summary: Get Bulk status
      description: Get Bulk status
      operationId: getBulkStatus
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: requestId
        in: query
        description: Request ID of the bulk operation
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: OK
          headers:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: './Extension-ReadConditional.yaml#/compone\
nts/schemas/Extension-StatusResponse'
        '303':
          description: See Other
          headers:
            Location:
              schema:
                type: string
              description: URL to get the bulk response
              example: /extensions/12345678-1234-5678-1234-56789abcd\
ef4/bulk?requestId=12345678-1234-5678-1234-56789abcdef4
          content:
            application/json:
              schema:
                allOf:
                  - $ref: './Extension-ReadConditional.yaml#/compone\
nts/schemas/Extension-StatusResponse'
              examples:
                successExample:
                  summary: Success
                  value:
                    status: COMPLETED

components:
  schemas:
# Extensions
## Bulk schema Extension
    Extension-Bulk:
      allOf:
        - $ref: './Extension-ReadConditional.yaml#/components/schema\
s/Extension-Callback'
        - type: object
          properties:
            operations:
              type: array
              items:
                $ref: '#/components/schemas/Extension-BulkOperation'

## Extension that defines an operation in a bulk API
    Extension-BulkOperation:
      required:
        - method
        - path
      allOf:
        - type: object
          properties:
            method:
              type: string
              enum:
               - POST
               - PUT
               - GET
            path:
              type: string
              enum:
                - /devices/{id}/properties?propertyName={propertyNam\
e}
                - /devices/{id}/actions/?actionName={actionName}
                - /extensions/{id}/properties/read/conditional?prope\
rtyName={propertyName}
              example: /devices/12345678-1234-5678-1234-56789abcdef4\
/properties?propertyName=https://example.com/thermometer%23/sdfThing\
/thermometer/sdfProperty/temperature
            data:
              type: object
              oneOf:
                - $ref: '../NIPC.yaml#/components/schemas/Value'
                - $ref: './Extension-ReadConditional.yaml#/component\
s/schemas/Extension-ConditionalRead'


## Multiple returns for a bulk operation
    Extension-BulkResponse:
      type: object
      properties:
        operations:
          type: array
          items:
            $ref: '#/components/schemas/Extension-OperationResponse'

## Return for an operation
    Extension-OperationResponse:
      allOf:
        - type: object
          properties:
            method:
              type: string
              enum:
               - POST
               - PUT
               - GET
            path:
              type: string
              enum:
                - /devices/{id}/properties?propertyName={propertyNam\
e}
                - /devices/{id}/actions/?actionName={actionName}
                - /extensions/{id}/properties/read/conditional?prope\
rtyName={propertyName}
              example: /devices/12345678-1234-5678-1234-56789abcdef4\
/properties?propertyName=https://example.com/thermometer%23/sdfThing\
/thermometer/sdfProperty/temperature
            response:
              anyOf:
                - $ref: '../NIPC.yaml#/components/schemas/Value'
                - $ref: '../NIPC.yaml#/components/schemas/SuccessRes\
ponse'
                - $ref: '../NIPC.yaml#/components/schemas/FailureRes\
ponse'

  examples:
    bulkRequest:
      summary: Bulk request example
      value:
        operations:
          - method: GET
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
          - method: PUT
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
            data:
              value: dGVzdA==
          - method: POST
            path: /extensions/12345678-1234-5678-1234-56789abcdef4/p\
roperties/read/conditional?propertyName=https://example.com/thermome\
ter%23/sdfThing/thermometer/sdfProperty/temperature
            data:
              value: dGVzdA==
              maxRepeat: 5
              retryTime: 1
    bulkResponse:
      summary: Bulk response example
      value:
        operations:
          - method: GET
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
            response:
              value: dGVzdA==
          - method: PUT
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
            response:
              status: 200
          - method: POST
            path: /extensions/12345678-1234-5678-1234-56789abcdef4/p\
roperties/read/conditional?propertyName=https://example.com/thermome\
ter%23/sdfThing/thermometer/sdfProperty/temperature
            response:
              value: dGVzdA==
    errorBulkResponse:
      summary: Error Bulk response example
      value:
        operations:
          - method: GET
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
            response:
              type: https://www.iana.org/assignments/nipc-problem-ty\
pes#property-not-readable
              status: 400
              title: Property not readable
              detail: Property https://example.com/thermometer#/sdfT\
hing/thermometer/sdfProperty/temperature is not readable
          - method: PUT
            path: /devices/12345678-1234-5678-1234-56789abcdef4/prop\
erties?propertyName=https://example.com/thermometer%23/sdfThing/ther\
mometer/sdfProperty/temperature
            response:
              type: https://www.iana.org/assignments/nipc-problem-ty\
pes#extension-operation-not-executed
              status: 400
              title: Operation not executed
              detail: Operation was not executed since the previous \
operation failed
          - method: POST
            path: /extensions/12345678-1234-5678-1234-56789abcdef4/p\
roperties/read/conditional?propertyName=https://example.com/thermome\
ter%23/sdfThing/thermometer/sdfProperty/temperature
            response:
              type: https://www.iana.org/assignments/nipc-problem-ty\
pes#extension-operation-not-executed
              status: 400
              title: Operation not executed
              detail: Operation was not executed since the previous \
operation failed
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="nipc-api-write-file-extension"><name>NIPC API write file extension</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-File.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API write file extension
  description: |-
    Non IP Device Control (NIPC) API write file extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/properties/file:
    put:
      tags:
        - NIPC API extensions
      summary: Write a file to a property on a device
      description: |-
        Write a file to a property on a device. Will chunk up the 
        file and perform multiple writes. If the underlying protocol
        requires a connection to be set up, this API call will 
        perform the necessary connection management. If a connection
        is already active for this device, the existing connection 
        will be leveraged without modifying it. ID cannot be a
        group-id.
      operationId: writeFile
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be written to.
        required: true
        schema:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
tat/sdfProperty/firmware"
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Extension-File'
        required: true
      responses:
        '204':
          description: Success, no content
        'default':
          description: Error response
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse' 

components:
  schemas:
# Extensions
## A File Extension
    Extension-File:
      required:
        - fileURL
      type: object
      properties:
        fileURL:
          type: string
          example: "https://domain.com/firmware.dat"
        chunksize:
          type: integer
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="nipc-api-firmware-update-extension"><name>NIPC API firmware update extension</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-Firmware.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API firmware upgrade extension
  description: |-
    Non IP Device Control (NIPC) API firmware upgrade extension, 
    requires the file extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/firmware:
    put:
      tags:
        - NIPC API extensions
      summary: Upgrade the firmware of a device
      description: |-
        Update the firmware of a device. Will perform all operations
        required to upgrade the firmware. ID cannot be a group-id.
      operationId: upgradeFirmware
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: './Extension-File.yaml#/components/schemas/E\
xtension-File'
                - $ref: '#/components/schemas/Extension-Firmware'
                - $ref: './Extension-ReadConditional.yaml#/component\
s/schemas/Extension-Callback'
        required: true
      responses:
        '202':
          description: Accepted
          headers:
            Location:
              schema:
                type: string
              description: Location of the resource
              example: /12345678-1234-5678-1234-56789abcdef4/extensi\
on/firmware/status?requestId=12345678-1234-5678-1234-56789abcdef4
        default:
          description: Error response
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'
      callbacks:
        bulkEvent:
          '{$request.body#/callback.url}':
            post:
              description: Callback for bulk response
              operationId: bulkCallback
              requestBody:
                content:
                  application/json:
                    schema:
                      anyOf:
                        - $ref: '../NIPC.yaml#/components/schemas/Id'
                        - $ref: '../NIPC.yaml#/components/schemas/Fa\
ilureResponse'
              responses:
                '200':
                  description: OK
                '400':
                  description: Bad request
                '401':
                  description: Unauthorized
                '405':
                  description: Invalid request
                '500':
                  description: Server-side failure
                  
    get:
      tags:
        - NIPC API extensions
      summary: Get the status of a firmware upgrade of a device
      description: |-
        Get the status of a firmware upgrade of a device. 
        Returns success when ongoing or completed, with a reason. 
        Returns failure when upgrade has failed. 
        ID cannot be a group-id.
      operationId: upgradeFirmwareStatus
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: requestId
        in: query
        description: Request ID of the firmware upgrade operation
        required: true
        schema:
          type: string
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: OK
          headers:
            Location:
              schema:
                type: string
              description: Location of the resource
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/Id'
        '400':
          description: Bad request
        '401':
          description: Unauthorized
        '405':
          description: Invalid request
        '500':
          description: Server-side failure
          content:
            application/json:
              schema:
                - $ref: '../NIPC.yaml#/components/schemas/FailureRes\
ponse'
  /extensions/{id}/firmware/status:
    get:
      tags:
        - NIPC API extensions
      summary: Get the status of a firmware upgrade of a device
      description: |-
        Get the status of a firmware upgrade of a device. 
        Returns success when ongoing or completed, with a reason. 
        Returns failure when upgrade has failed. 
        ID cannot be a group-id.
      operationId: upgradeFirmwareStatus
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: requestId
        in: query
        description: Request ID of the firmware upgrade operation
        required: true
        schema:
          type: string
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          headers:
          content:
            application/json:
              schema:
                allOf: 
                  - $ref: '../NIPC.yaml#/components/schemas/Id'
                  - $ref: './Extension-ReadConditional.yaml#/compone\
nts/schemas/Extension-StatusResponse'
        '303':
          description: See Other
          headers:
            Location:
              schema:
                type: string
              description: URL to get the firmware response
              example: /12345678-1234-5678-1234-56789abcdef4/extensi\
on/firmware?requestId=12345678-1234-5678-1234-56789abcdef4
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../NIPC.yaml#/components/schemas/Id'
                  - $ref: './Extension-ReadConditional.yaml#/compone\
nts/schemas/Extension-StatusResponse'
              examples:
                successExample:
                  summary: Completed
                  value:
                    id: 12345678-1234-5678-1234-56789abcdef4
                    status: COMPLETED

components:
  schemas:
# Extensions
## a Firmware Extension
    Extension-Firmware:
      type: object
      properties:
        firmware:
          type: string
          enum:
            - nordic
            - silabs
        sha256Checksum:
          type: string
          description: firmware checksum
        controlProperty:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
tat/sdfProperty/upgradecontrol"
          description: sdfName of the property used for control of t\
he firmware upgrade
        dataProperty:
          type: string
          example: "https://example.com/heartrate#/sdfObject/thermos\
tat/sdfProperty/upgradedata"
          description: sdfName of the property used for firmware tra\
nsfer
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="nipc-api-conditional-read-extension"><name>NIPC API conditional read extension</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-ReadConditional.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API read conditional extension
  description: |-
    Non IP Device Control (NIPC) API read conditional extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/properties/read/conditional:
    post:
      tags:
        - NIPC API extensions
      summary: Conditional read of a property
      description: Conditional read of a property
      operationId: conditionalRead
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be read conditionally.
        required: true
        allowReserved: true
        schema:
          type: string
          example: "#/sdfObject/thermostat/sdfProperty/temperature"
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Extension-ConditionalRead'
        required: true
      responses:
        '202':
          description: Accepted
          headers:
            Location:
              schema:
                type: string
              description: |-
                URL to get the conditional read status
              example: /12345678-1234-5678-1234-56789abcdef4/extensi\
on/property/temperature/read/conditional/status?requestId=12345678-1\
234-5678-1234-56789abcdef4
            Retry-After:
              schema:
                type: integer
              description: |-
                Time in seconds to wait before retrying
        'default':
          description: Error response
          content:
            application/json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'
      callbacks:
        callbackEvent:
          "{$request.body#/callback.url}":
            post:
              requestBody:
                content:
                  application/json:
                    schema:
                      anyOf:
                        - allOf:
                          - $ref: '../NIPC.yaml#/components/schemas/\
Id'
                          - $ref: '../NIPC.yaml#/components/schemas/\
PropertyValue'
                        - $ref: '../NIPC.yaml#/components/schemas/Fa\
ilureResponse'
                    examples:
                      successExample:
                        summary: Success
                        value:
                          id: 12345678-1234-5678-1234-56789abcdef4
                          property: https://example.com/heartrate#/s\
dfObject/thermostat/sdfProperty/temperature
                          value: dGVzdA==
                      failedResponse:
                        summary: Failed
                        value:
                          id: 12345678-1234-5678-1234-56789abcdef4
                          status: 400
                          nipcStatus: 1000
                          detail: "Invalid request"
                          property: https://example.com/heartrate#/s\
dfObject/thermostat/sdfProperty/temperature
                          value: dGVzdA==
                          
              responses:
                '200':
                  description: Success
    get:
      tags:
        - NIPC API extensions
      summary: Get Conditional read response of a property
      description: Conditional read response of a property
      operationId: getConditionalRead
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be read conditionally.
        required: true
        allowReserved: true
        schema:
          type: string
          example: "#/sdfObject/thermostat/sdfProperty/temperature"
      - name: requestId
        in: query
        description: |-
          Request ID of the conditional read operation
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: Success
          headers:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../NIPC.yaml#/components/schemas/Value'
            application/octet-stream:
              schema:
                type: string
                format: binary
              description: Binary data of the property value
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                allOf:
                  - $ref: '../NIPC.yaml#/components/schemas/FailureR\
esponse'
  /extensions/{id}/properties/read/conditional/status:
    get:
      tags:
        - NIPC API extensions
      summary: Get Conditional read status of a property
      description: Conditional read status of a property
      operationId: getConditionalReadStatus
      parameters:
      - name: id
        in: path
        description: The ID of the device. Group ID is not allowed.
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      - name: propertyName
        in: query
        description: |-
          The SDF property name that needs to be read conditionally.
        required: true
        allowReserved: true
        schema:
          type: string
          example: "#/sdfObject/thermostat/sdfProperty/temperature"
      - name: requestId
        in: query
        description: Request ID of the conditional read operation
        required: true
        schema:
          type: string
          format: uuid
          example: 12345678-1234-5678-1234-56789abcdef4
      responses:
        '200':
          description: OK
          headers:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Extension-StatusResp\
onse'
        '303':
          description: See Other
          headers:
            Location:
              schema:
                type: string
              description: URL to get the conditional read response
              example: /12345678-1234-5678-1234-56789abcdef4/extensi\
on/property/temperature/read/conditional?requestId=12345678-1234-567\
8-1234-56789abcdef4
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Extension-StatusResp\
onse'
              examples:
                successExample:
                  summary: Completed
                  value:
                    id: 12345678-1234-5678-1234-56789abcdef4
                    status: COMPLETED

components:
  schemas:
# Extensions
    Extension-Callback:
      type: object
      properties:
        callback:
          type: object
          properties:
            url:
              description: |-
                URL to send the callback to
                (default is the same as the request URL)
              type: string
              example: "http://localhost:8080/callback"
            headers:
              description: |-
                Headers to include in the callback
                (default is empty)
              type: object
              example:
                x-api-key: "1234567890"
              additionalProperties:
                type: string

    Extension-StatusResponse:
      type: object
      properties:
        status:
          description: |-
            Status of the callback
          type: string
          enum:
            - IN_PROGRESS
            - COMPLETED

    Extension-ConditionalRead:
      allOf:
        - $ref: '../NIPC.yaml#/components/schemas/Value'
        - $ref: '#/components/schemas/Extension-Callback'
        - type: object
          properties:
            maxRepeat:
              description: |-
                maximum time the conditional read should repeat
                (default 5, max 10)
              type: integer
              example: 5
            retryTime:
              description: |-
                time between reads in seconds (default 1, max 10)
              type: integer
              example: 1
<CODE ENDS>
]]></artwork></figure>

</section>
<section anchor="nipc-api-property-extensions"><name>NIPC API property extensions</name>

<figure><artwork><![CDATA[
<CODE BEGINS>
file "Extension-Property.yaml"
=============== NOTE: '\' line wrapping per RFC 8792 ================

# yaml-language-server: $schema=https://json-schema.org/draft/2020-1\
2/schema
openapi: 3.0.3
info:
  title: Non IP Device Control (NIPC) API read conditional extension
  description: |-
    Non IP Device Control (NIPC) API read conditional extension
  termsOfService: http://swagger.io/terms/
  contact:
    email: bbrinckm@cisco.com
  license:
    name: TBD
    url: TBD
  version: 0.9.0
externalDocs:
  description: NIPC IETF draft
  url: https://datatracker.ietf.org/doc/draft-ietf-asdf-nipc/
servers:
  - url: "{gw_host}/nipc/draft-12"
    variables:
      gw_host:
        default: localhost
        description: Gateway Host
tags:
  - name:  NIPC API extensions
    description: |-
      APIs that simplify application interaction by implementing
      one or more basic APIs into a single API call.

paths:
### Extensions
  /extensions/{id}/manage/transmit:
    post:
      tags:
        - NIPC API extensions
      summary: Broadcast to a device
      description: |-
        Broadcast a payload to a device. The broadcast is performed \
on the AP where the device was last seen
      operationId: ActionBroadcast
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Transmit'
        required: true
      responses:
        '200':
          description: Success
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'
   
  /extensions/{id}/properties/write:
    post:
      tags:
        - NIPC API extensions
      summary: Write a value to an property using protocol mapping
      description: |-
        Write a value to an unregistered property, embedding property
        protocol mapping in the API, this does not require
        property registration. You cannot write to a group id.
      operationId: ActionPropWrite
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/json:
            schema:
              allOf:
                - $ref: '../NIPC.yaml#/components/schemas/Value' 
                - $ref: '../protocolmaps/ProtocolMap.yaml#/component\
s/schemas/ProtocolMap-Property'
        required: true
      responses:
        '204':
          description: Success, no content
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'
                
  /extensions/{id}/properties/read:
    post:
      tags:
        - NIPC API extensions
      summary: Read a value to an property using protocol mapping
      description: |-
        Read a value from an unregistered property, embedding 
        property protocol mapping in the API, this does not require
        property registration. You cannot read from a group id.
      operationId: ActionPropRead
      parameters:
        - name: id
          in: path
          description: The ID of the device. Group ID is not allowed.
          required: true
          schema:
            type: string
            format: uuid
            example: 12345678-1234-5678-1234-56789abcdef4
      requestBody:
        content:
          application/json:
            schema:
              $ref: '../protocolmaps/ProtocolMap.yaml#/components/sc\
hemas/ProtocolMap-Property'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                allOf: 
                  - $ref: '../NIPC.yaml#/components/schemas/Value'
        default:
          description: Error response
          content:
            application/problem+json:
              schema:
                $ref: '../NIPC.yaml#/components/schemas/FailureRespo\
nse'

components:
  schemas:
    Transmit:
      allOf:
        - $ref: '../protocolmaps/ProtocolMap.yaml#/components/schema\
s/ProtocolMap-Broadcast'
      required:
        - cycle
      type: object
      properties:
        cycle:
          type: string
          example: single
          enum:
            - single
            - repeat
        # transmit time in ms
        transmitTime:
          type: integer
          example: 3000
        # interval between transmits in ms
        transmitInterval:
          type: integer
          example: 500
        payload:
          type: string
          format: byte
          example: AgEaAgoMFv9MABAHch9BsDkgeA==
<CODE ENDS>
]]></artwork></figure>

</section>
</section>
<section anchor="thermometer-sdf"><name>Example SDF model with protocol mappings for BLE</name>

<figure title="Example SDF model with protocol mappings for BLE"><artwork><![CDATA[
<CODE BEGINS>
file "thermometer.sdf.json"
{
  "namespace": {
    "thermometer": "https://example.com/thermometer"
  },
  "defaultNamespace": "thermometer",
  "sdfThing": {
    "thermometer": {
      "sdfObject": {
        "health_thermometer": {
          "description": "Health Thermometer",
          "sdfProperty": {
            "temperature_type": {
              "description": "Temperature Type",
              "observable": false,
              "writable": false,
              "readable": true,
              "sdfProtocolMap": {
                "ble": {
                  "serviceID": "1809",
                  "characteristicID": "2A1D"
                }
              }
            },
            "measurement_interval": {
              "description": "Measurement Interval",
              "observable": false,
              "writable": false,
              "readable": true,
              "sdfProtocolMap": {
                "ble": {
                  "serviceID": "1809",
                  "characteristicID": "2A21"
                }
              }
            }
          },
          "sdfEvent": {
            "temperature_measurement": {
              "description": "Temperature Measurement",
              "sdfOutputData": {
                "sdfProtocolMap": {
                  "ble": {
                    "type": "gatt",
                    "serviceID": "1809",
                    "characteristicID": "2A1C"
                  }
                }
              }
            },
            "intermediate_temperature": {
              "description": "Intermediate Temperature",
              "sdfOutputData": {
                "sdfProtocolMap": {
                  "ble": {
                    "type": "gatt",
                    "serviceID": "1809",
                    "characteristicID": "2A1E"
                  }
                }
              }
            }
          }
        }
      },
      "description": "Generic Access, Device Information",
      "sdfProperty": {
        "device_name": {
          "description": "Device Name",
          "observable": false,
          "writable": true,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "1800",
              "characteristicID": "2A00"
            }
          }
        },
        "appearance": {
          "description": "Appearance",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "1800",
              "characteristicID": "2A01"
            }
          }
        },
        "manufacturer_name_string": {
          "description": "Manufacturer Name String",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "180A",
              "characteristicID": "2A29"
            }
          }
        },
        "model_number_string": {
          "description": "Model Number String",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "180A",
              "characteristicID": "2A24"
            }
          }
        },
        "hardware_revision_string": {
          "description": "Hardware Revision String",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "180A",
              "characteristicID": "2A27"
            }
          }
        },
        "firmware_revision_string": {
          "description": "Firmware Revision String",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "180A",
              "characteristicID": "2A26"
            }
          }
        },
        "system_id": {
          "description": "System ID",
          "observable": false,
          "writable": false,
          "readable": true,
          "sdfProtocolMap": {
            "ble": {
              "serviceID": "180A",
              "characteristicID": "2A23"
            }
          }
        }
      },
      "sdfEvent": {
        "isPresent": {
          "description": "BLE advertisements",
          "sdfOutputData": {
            "sdfProtocolMap": {
              "ble": {
                "type": "advertisements"
              }
            }
          }
        },
        "isConnected": {
          "description": "BLE connection events",
          "sdfOutputData": {
            "sdfProtocolMap": {
              "ble": {
                "type": "connection_events"
              }
            }
          }
        }
      }
    }
  }
}
<CODE ENDS>
]]></artwork></figure>

</section>


  </back>

<!-- ##markdown-source:
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
0a4CAA==

-->

</rfc>

