Connecting to a Node

How to construct the OSHConnect entry point, attach Node connections (including the MQTT and NATS streaming transports), and authenticate against secured servers.

Creating an OSHConnect Instance

All public classes and utilities can be imported directly from oshconnect:

from oshconnect import OSHConnect, Node, System, Datastream, ControlStream
from oshconnect import TimePeriod, TimeInstant, TemporalModes
from oshconnect import DataRecordSchema, QuantitySchema, TimeSchema, TextSchema
from oshconnect import ObservationFormat, DefaultEventTypes

The main entry point is the OSHConnect class:

from oshconnect import OSHConnect, TemporalModes

app = OSHConnect(name='MyApp')

Adding a Node

A Node represents a connection to a single OSH server. The OSHConnect instance can manage multiple nodes simultaneously.

from oshconnect import OSHConnect, Node

app = OSHConnect(name='MyApp')
node = Node(protocol='http', address='localhost', port=8585,
            username='test', password='test')
app.add_node(node)

To connect a node with MQTT support for streaming:

node = Node(protocol='http', address='localhost', port=8585,
            username='test', password='test',
            enable_mqtt=True, mqtt_port=1883)
app.add_node(node)

To talk to an older OSH server that predates the CS API Part 3 topic scheme, enable legacy topics. This reverts MQTT topic construction to the pre-Part-3 form — a leading slash and no :data suffix or format subtopic (e.g. /api/datastreams/{id}/observations instead of api/datastreams/{id}/observations:data/<token>):

node = Node(protocol='http', address='localhost', port=8585,
            username='test', password='test',
            enable_mqtt=True, mqtt_legacy_topics=True)
app.add_node(node)

Legacy mode affects MQTT topics only; NATS subjects are unaffected.

To stream over NATS.io instead (the corporate-bus transport, served by OSH’s sensorhub-service-consys-nats binding), enable it the same way — enable_nats mirrors enable_mqtt:

node = Node(protocol='http', address='localhost', port=8585,
            username='test', password='test',
            enable_nats=True, nats_port=4222)      # or nats_token='...'
app.add_node(node)

The two transports are drop-in twins: Datastream / ControlStream drive whichever one the node was configured with (NATS takes precedence if both are enabled). The only wire difference is the subject namespace — NATS data subjects are dot-delimited and nested under systems (api.systems.{sysId}.datastreams.{dsId}.observations:data.<token>), which the client builds for you. Only PROACTIVE-mode plain publish/subscribe is supported; the optional flow-control channel and JetStream are out of scope.

Authentication

OSHConnect currently speaks HTTP Basic Auth to OGC CS API servers. There is no bearer-token, OAuth, or API-key flow yet — the underlying requests library carries credentials as a (username, password) tuple.

Note

Work is planned for more secure authentication options — OpenID Connect (OIDC) / OAuth2 bearer-token flows, matching OpenSensorHub’s own OAuth security module, and API keys are under consideration. Until those land, always pair Basic Auth with protocol='https' on anything other than a local dev node, since Basic credentials are only base64-encoded, not encrypted.

For a secured server, pass username and password to Node:

node = Node(protocol='https', address='sensors.example.org', port=443,
            username='alice', password='s3cret')

Every HTTP call the node makes — discovery, resource creation, schema fetches — automatically carries those credentials. Internally, the node constructs an APIHelper that holds the credentials and reads them back via get_helper_auth() on each request. The same credentials also flow into the MQTT client when enable_mqtt=True (and, for NATS, into user/password auth when enable_nats=True; pass nats_token for token auth instead).

For an unsecured server (e.g., a local OSH dev instance), simply omit username and password:

node = Node(protocol='http', address='localhost', port=8585)

If the server has been secured but you forget to provide credentials, each request will return 401 Unauthorized from the server — no exception is raised by the library; inspect the response status.

Lower-level usage (free helpers)

For one-off scripts or when you don’t want a full Node / OSHConnect setup, the module-level helpers in oshconnect.api_helpers mirror each CS API endpoint and accept an optional auth tuple plus optional headers dict. Every helper returns a requests.Response object:

from oshconnect.api_helpers import list_all_systems, create_new_systems

resp = list_all_systems(
    'http://sensors.example.org/sensorhub',
    auth=('alice', 's3cret'),
)
resp.raise_for_status()
systems = resp.json()['items']

created = create_new_systems(
    'http://sensors.example.org/sensorhub',
    request_body={'name': 'Sensor #1', 'uid': 'urn:test:sensor:1'},
    auth=('alice', 's3cret'),
    headers={'Content-Type': 'application/sml+json'},
)
new_id = created.headers['Location'].rsplit('/', 1)[-1]

Omit auth to call an unsecured endpoint. For application code, prefer the Node / APIHelper path so credentials are configured once at the node boundary instead of threaded through every call site.