API Reference¶
All public symbols are re-exported from the top-level package and can be imported directly:
from oshconnect import OSHConnect, Node, Datastream, TimePeriod, ObservationFormat, ...
Lower-level CS API utilities are available from the oshconnect.csapi4py subpackage:
from oshconnect.csapi4py import APIResourceTypes, MQTTCommClient, ConnectedSystemsRequestBuilder, ...
—
Core Application¶
- class oshconnect.oshconnectapi.OSHConnect(name, datastore=None, **kwargs)[source]¶
Bases:
object- Parameters:
name (str)
datastore (DataStore)
- __init__(name, datastore=None, **kwargs)[source]¶
- Parameters:
name (str) – name of the OSHConnect instance
datastore (DataStore) – optional DataStore backend for persisting the resource graph
kwargs
- datastore: DataStore¶
- styling: Styling¶
- timestream: TimeManagement¶
- add_node(node)[source]¶
Add a node to the OSHConnect instance. :param node: Node object :return:
- Parameters:
node (Node)
- remove_node(node_id)[source]¶
Remove a node from the OSHConnect instance. :param node_id: :return:
- Parameters:
node_id (str)
- classmethod load_config(file_name)[source]¶
Load configuration data from a JSON file and return the stored config dict. Note: Despite the return type hint, this returns the configuration dictionary.
- Parameters:
file_name (str)
- Return type:
- save_to_store()[source]¶
Persist the full node graph to the configured datastore.
- Raises:
RuntimeError – if no datastore has been configured.
- Return type:
None
- load_from_store()[source]¶
Restore the node graph from the configured datastore into this instance.
Reconstructed Nodes are registered with this instance’s SessionManager so their child resources (Systems, Datastreams, ControlStreams) can initialise correctly. Calling this method appends to any already-loaded nodes.
- Raises:
RuntimeError – if no datastore has been configured.
- Return type:
None
- Parameters:
config (dict)
- select_temporal_mode(mode)[source]¶
Select the temporal mode for the system. Real-time, archive, batch, as well as synchronization settings. :param mode: :return:
- Parameters:
mode (str)
- discover_systems(nodes=None)[source]¶
Discover systems from the nodes that have been added to the OSHConnect instance. They are associated with the nodes that they are discovered from so access to them flows through there. :param nodes: :return:
- set_playback_mode(mode)[source]¶
- Parameters:
mode (TemporalModes)
- set_timeperiod(start_time, end_time)[source]¶
Sets the time range (TimePeriod) for the OSHConnect instance. This is used to bookend the playback of the datastreams. :param start_time: ISO8601 formatted string or one of (now or latest) :param end_time: ISO8601 formatted string or one of (now or latest) :return:
- add_datastream(datastream, system)[source]¶
Adds a datastream into the OSHConnect instance. :param datastream: DataSource object :param system: System object or system id :return:
- Parameters:
datastream (DatastreamResource)
- Return type:
- find_system(system_id)[source]¶
Find a system in the OSHConnect instance. :param system_id: :return: the found system or None if not found
- add_system_to_node(system, target_node, insert_resource=False)[source]¶
Add a system to the target node. :param system: System object :param target_node: Node object, must be within the OSHConnect instance :param insert_resource: Whether to insert the system into the target node’s server, default is False :return:
- create_and_insert_system(system_opts, target_node)[source]¶
Create a system on the target node. :param system_opts: System object parameters :param target_node: Node object, must be within the OSHConnect instance :return: the created system
- connect_session_streams(session_id)[source]¶
Connects all datastreams that are associated with the given session ID. :param session_id: :return:
- Parameters:
session_id (str)
- get_resource_group(resource_ids)[source]¶
Get a group of resources by their IDs. Can be any mix of systems, datastreams, and controlstreams. :param resource_ids: list of resource IDs (internal UUID)
- initialize_resource_groups(resource_ids=None)[source]¶
Initializes the datastreams that are specified.
- Parameters:
resource_ids (list)
- start_datastreams(dsid_list=None)[source]¶
Starts the datastreams that are specified.
- Parameters:
dsid_list (list)
- start_systems(sysid_list=None)[source]¶
Starts the systems that are specified.
- Parameters:
sysid_list (list)
- on_observation(callback, datastream_id=None)[source]¶
Subscribe to incoming observation events.
- Parameters:
- Returns:
CallbackListener— pass toevent_bus.unregister_listener()to cancel.- Return type:
CallbackListener
- on_system_added(callback)[source]¶
Subscribe to system-discovered / system-added events.
- Parameters:
callback (Callable) –
fn(event: Event)whereevent.datais theSystem.- Returns:
CallbackListenerfor later removal.- Return type:
CallbackListener
- property event_bus: EventHandler¶
Direct access to the EventHandler for advanced subscriptions.
—
Streamable Resources¶
These are the primary objects for interacting with systems, datastreams, and control streams on an OSH node.
Includes Node, System, Datastream, ControlStream, and supporting enums.
Backward-compatible re-export shim.
The classes that used to live in this module have moved into focused sibling modules:
Node, SessionManager, OSHClientSession, Endpoints, Utilities → oshconnect.node
StreamableResource, Status, StreamableModes, SchemaFetchWarning → oshconnect.resources.base
System → oshconnect.resources.system
Datastream → oshconnect.resources.datastream
ControlStream → oshconnect.resources.controlstream
Existing from oshconnect.streamableresource import X paths continue
to resolve through this shim. Prefer importing from oshconnect directly
or from the new sibling modules in new code.
- class oshconnect.streamableresource.ControlStream(node=None, controlstream_resource=None)[source]¶
Bases:
StreamableResource[ControlStreamResource]An input channel of a System: accepts commands and emits status.
Unlike Datastream, a control stream has TWO MQTT topics — one for commands (
self._topic) and one for status updates (self._status_topic) — and two pairs of inbound/outbound deques to match. Construct from a parsed ControlStreamResource (typically from System.discover_controlstreams) or build locally and insert via System.add_and_insert_control_stream.- Parameters:
node (Node) – The Node this control stream lives under.
controlstream_resource (ControlStreamResource) – The pydantic ControlStreamResource model that backs this stream.
- add_underlying_resource(resource)[source]¶
Replace the underlying ControlStreamResource model.
- Parameters:
resource (ControlStreamResource)
- init_mqtt()[source]¶
Set
self._topicto the control stream’s command data topic. When this control stream has acommand_schemathe topic is suffixed with the matching format subtopic (e.g.…/commands:data/swe-json); otherwise a bare:datatopic is used and the server’s default format applies.
- get_mqtt_status_topic()[source]¶
Return the topic/subject for command status updates. Status payloads are always
application/json, so it is suffixed with thejsonformat subtopic (…/status:data/jsonfor MQTT, or the nested…commands... status:data.jsonequivalent for NATS).- Return type:
- start()[source]¶
Start the control stream. PULL/BIDIRECTIONAL subscribes to the command topic; PUSH spawns the async MQTT write loop. Requires an active asyncio event loop for PUSH mode.
- get_status_deque_outbound()[source]¶
Return the deque feeding outbound status publishes.
- Return type:
- publish_command(payload)[source]¶
Publish
payloadto the command MQTT topic. Convenience wrapper forpublish(payload, APIResourceTypes.COMMAND.value).
- publish_status(payload)[source]¶
Publish
payloadto the status MQTT topic. Convenience wrapper forpublish(payload, APIResourceTypes.STATUS.value).
- publish(payload, topic='Command')[source]¶
Publishes data to the MQTT topic associated with this control stream resource.
- Parameters:
payload – Data to be published; subclass determines specifically allowed types.
topic (str) – One of
APIResourceTypes.COMMAND.value("Command", the default) orAPIResourceTypes.STATUS.value("Status"). Pass the enum value rather than a lowercase shorthand — the comparison is case-sensitive against the canonical CS API resource-type strings.
- subscribe(topic=None, callback=None, qos=0)[source]¶
Subscribes to the MQTT topic associated with this control stream resource.
- Parameters:
topic –
None(defaults to the command topic),APIResourceTypes.COMMAND.value("Command"), orAPIResourceTypes.STATUS.value("Status"). Comparison is case-sensitive against the canonical CS API resource-type strings.callback – Optional callback function to handle incoming messages, if None the default handler is used.
qos – Quality of Service level for the subscription, default is 0.
- to_storage_dict()[source]¶
Return a JSON-safe snapshot of this control stream — local identity, connection state, status topic, and the dumped underlying ControlStreamResource — for OSHConnect’s persistence layer.
Not a CS API server-shaped payload — the
underlying_resourceblock is the only piece that matches the CS API control-stream shape.- Return type:
- classmethod from_storage_dict(data, node)[source]¶
Build a ControlStream from a dict produced by to_storage_dict. The embedded
underlying_resourceis parsed via ControlStreamResource.model_validate, so that nested block can also be a CS API server response body for the control stream.- Parameters:
- Return type:
- class oshconnect.streamableresource.Datastream(parent_node=None, datastream_resource=None)[source]¶
Bases:
StreamableResource[DatastreamResource]An output channel of a System: produces observations.
Created from a parsed DatastreamResource (typically returned by System.discover_datastreams) or built locally and inserted via System.add_insert_datastream. Subscribes to its observation MQTT topic when started.
- Parameters:
parent_node (Node) – The Node this datastream lives under.
datastream_resource (DatastreamResource) – The pydantic DatastreamResource model.
- static from_resource(ds_resource, parent_node)[source]¶
Build a Datastream from an already-parsed DatastreamResource.
Deprecated since version 0.5.1: Use the constructor directly instead:
Datastream(parent_node=node, datastream_resource=ds_resource). For raw JSON, parse first viaDatastreamResource.from_csapi_dict(data).- Parameters:
ds_resource (DatastreamResource)
parent_node (Node)
- Return type:
- set_resource(resource)[source]¶
Replace the underlying DatastreamResource model.
- Parameters:
resource (DatastreamResource)
- create_observation(obs_data)[source]¶
Build an ObservationResource from a result dict, validating against this datastream’s record schema if one is set.
Does NOT insert the observation server-side — pair with insert_observation_dict if you want to POST it.
- Parameters:
obs_data (dict)
- Return type:
- insert_observation_dict(obs_data)[source]¶
POST an observation dict to
/datastreams/{id}/observations.
- start()[source]¶
Start the datastream. PULL/BIDIRECTIONAL subscribes to the observation topic; PUSH spawns the async MQTT write loop. Requires an active asyncio event loop for PUSH mode.
- init_mqtt()[source]¶
Set
self._topicto the datastream’s observation data topic (CS API Part 3:datasuffix). When this datastream has arecord_schemathe topic is suffixed with the matching format subtopic (e.g.…/observations:data/swe-binary); otherwise a bare:datatopic is used and the server’s default format applies.
- insert(data)[source]¶
Encode
dataand publish it to this datastream’s observation MQTT topic. Bypasses the outbound deque.Encoding is chosen from the datastream’s record schema:
application/swe+binary→ uses SWEBinaryCodec to pack a dict (or Sequence in declared member order) into the binary wire form. Rawbytes/bytearray/memoryviewpayloads are passed through verbatim — useful when the caller has already framed a record (e.g. a pre-encoded H.264 NAL unit with the standard[ts][size][bytes]blob framing fromoshconnect.swe_binary.encode_swe_binary_blob).everything else (incl.
application/swe+json,application/om+json) →json.dumpsof a dict.
- decode_observation(raw, obs_format=None)[source]¶
Decode one observation off the wire using this datastream’s schema.
For
application/swe+binarydatastreams: walks the record encoding’s members and returns a dict keyed by field name. Block members come back asbytes(opaque — the codec does not demux H.264 / JPEG / etc.).For JSON-family datastreams: returns
json.loads(raw).- Parameters:
obs_format (str | None) – Optional MIME content-type overriding the datastream’s own schema format. Use this to decode data received via a NATS format-wildcard subscription, where the concrete format is only known per-message from the delivered subject (pass the result of
nats_content_type_from_subject()).application/swe+flatbuffersis schemaless and decodes regardless of the datastream’s own schema type.raw (bytes)
- Raises:
ValueError – if no schema has been fetched.
- Return type:
- to_storage_dict()[source]¶
Return a JSON-safe snapshot of this datastream — local identity, connection state, polling flag, and the dumped underlying DatastreamResource — for OSHConnect’s persistence layer.
Not a CS API server-shaped payload — the
underlying_resourceblock is the only piece that matches the CS API datastream shape.- Return type:
- classmethod from_storage_dict(data, node)[source]¶
Build a Datastream from a dict produced by to_storage_dict. The embedded
underlying_resourceis parsed via DatastreamResource.model_validate, so that nested block can also be a CS API server response body for the datastream.- Parameters:
- Return type:
- subscribe(topic=None, callback=None, qos=0)[source]¶
Subscribe to this datastream’s observation MQTT topic.
- Parameters:
topic –
Noneor"observation"— both resolve to the datastream’s data topic. Any other string raises.callback – Override the default callback (which appends payloads to
_inbound_deque).qos – MQTT QoS level. Default 0.
- Raises:
ValueError – if
topicis anything other than None /"observation".
- class oshconnect.streamableresource.Endpoints(*, root='sensorhub', sos='sensorhub/sos', connected_systems='sensorhub/api')[source]¶
Bases:
objectDefault URL path segments for an OSH server’s REST APIs.
- class oshconnect.streamableresource.Node(protocol, address, port, username=None, password=None, server_root='sensorhub', api_root='api', mqtt_topic_root=None, session_manager=None, enable_mqtt=False, mqtt_port=1883, enable_nats=False, nats_port=4222, nats_token=None, mqtt_legacy_topics=False)[source]¶
Bases:
objectOne connection to a single OSH server.
A Node is the unit of “where to talk to”. It owns the APIHelper that builds and executes HTTP requests, an optional MQTTCommClient for Pub/Sub, and the list of System objects discovered from or inserted into that server. Most user code creates a Node and then either calls discover_systems() or attaches user-built systems via add_system().
- Parameters:
protocol (str) –
"http"or"https".address (str) – Hostname or IP (no scheme).
port (int) – HTTP port the server is listening on.
username (str) – Optional Basic-Auth username.
password (str) – Optional Basic-Auth password.
server_root (str) – First path segment of the server URL (default
"sensorhub").api_root (str) – Second path segment under
server_root(default"api").mqtt_topic_root (str) – Override for the MQTT topic root if it diverges from the HTTP api root (CS API Part 3 § A.1).
session_manager (SessionManager) – Optional SessionManager; if given the node registers itself and gets a fresh OSHClientSession.
enable_mqtt (bool) – If True, connects an MQTT client to
address.mqtt_port (int) – MQTT broker port. Default 1883.
enable_nats (bool)
nats_port (int)
nats_token (str)
mqtt_legacy_topics (bool)
- add_basicauth(username, password)[source]¶
Attach Basic-Auth credentials and mark the node as secure.
- get_decoded_auth()[source]¶
Return the Base64 Basic-Auth header value as a UTF-8 string.
- Return type:
- get_mqtt_client()[source]¶
Return the connected MQTTCommClient or
Noneif MQTT was not enabled at construction (enable_mqtt=True).- Return type:
- get_nats_client()[source]¶
Return the connected NatsCommClient or
Noneif NATS was not enabled at construction (enable_nats=True).- Return type:
- get_comm_client()[source]¶
Return the active pub/sub transport client for this node.
Prefers NATS when it was enabled, otherwise falls back to MQTT (and
Noneif neither was enabled). StreamableResource reads this so it can drive whichever transport the node was configured with.
- discover_systems()[source]¶
GET
/systems?f=application/sml+jsonand create a System for each entry.We pin SML+JSON because the GeoJSON listing variant (OSH’s default when no format is specified) is a summary that drops SensorML detail —
identifiers,classifiers,keywords,characteristics,definition,typeOf,configuration,contacts,documentation,inputs/outputs/parameters,modes,method,featuresOfInterest. SML+JSON delivers all of those, which cross-node sync and any caller round-tripping_underlying_resourceneed.Accept: application/sml+jsonis ignored by the OSH listing endpoint (still returns GeoJSON), so the format is selected via the?f=query parameter — the OGC API standard format selector.SystemResource.model_validateparses both shapes, so the wrapper still copes if a server returns GeoJSON anyway.The new systems are appended to this node’s internal list and also returned for convenience.
- add_system(system, insert_resource=False)[source]¶
Attach a system to this node.
When
insert_resource=True, the system is first POSTed to the server viasystem.insert_self()(which populates its server-assigned resource id), then attached locally — so the system enters this node’s collection already carrying its real id. Withinsert_resource=Falsethe system is attached in-memory only; useful when reconstructing state from a datastore or staging a system before a deferred POST.
- register_with_session_manager(session_manager)[source]¶
Registers this node with the provided session manager, creating a new client session. :param session_manager: SessionManager instance
- Parameters:
session_manager (SessionManager)
- register_streamable(streamable)[source]¶
Register a streamable with this node’s session so its lifecycle is driven by OSHClientSession.connect_streamables / close_streamables.
Soft no-op when no SessionManager was attached at construction; the caller can still drive the streamable manually via initialize() / start() / stop().
- Parameters:
streamable (StreamableResource)
- to_storage_dict()[source]¶
Return a JSON-safe dict snapshot of this node — connection params, attached systems / streamables, and any locally-tracked state — for OSHConnect’s persistence layer (see OSHConnect.save_config, oshconnect.datastores.sqlite_store).
Not a CS API server-shaped payload; the dict format is OSHConnect’s own. For a CS API-shaped representation, use the underlying pydantic resource model’s
model_dump(by_alias=True).- Return type:
- classmethod from_storage_dict(data, session_manager=None)[source]¶
Build a Node from a dict produced by to_storage_dict (i.e., from OSHConnect’s persistence layer, not from a CS API server response).
Expects connection params (
protocol,address,port, optionalusername/password/server_root/api_root/mqtt_topic_root), an_id, and a_systemslist.- Parameters:
data (dict) – Source dict.
session_manager (SessionManager) – Optional SessionManager to register the rebuilt node with — required if any child StreamableResource in
_systemswas originally registered.
- Return type:
- class oshconnect.streamableresource.OSHClientSession(base_url, *args, verify_ssl=True, **kwargs)[source]¶
Bases:
objectOne client session against a Node, owning its registered streamables.
Created by SessionManager.register_session and used by Node to manage the lifecycle (start/stop) of every StreamableResource attached to that node. Holds the streamables in a dict keyed by streamable ID.
- Parameters:
base_url – Base URL of the OSH server (passed by Node, not used directly by this class today).
verify_ssl – Whether to verify TLS certificates. Default True.
- verify_ssl = True¶
- register_streamable(streamable)[source]¶
Track a streamable so its lifecycle is driven by this session.
- Parameters:
streamable (StreamableResource)
- exception oshconnect.streamableresource.SchemaFetchWarning[source]¶
Bases:
UserWarningA datastream/control-stream schema fetch or parse failed during Node.discover_systems / System.discover_datastreams / System.discover_controlstreams.
Discovery deliberately does not raise on per-resource schema failures — one broken schema would otherwise poison the entire listing. The matching wrapper is still appended (with record_schema / command_schema left as
None), but the original exception is surfaced both here (viawarnings.warn) and in the root logger at ERROR level (with a full traceback viaexc_info=True). Filter or capture this category if you want to react programmatically.
- class oshconnect.streamableresource.SessionManager(session_tokens=None)[source]¶
Bases:
objectTop-level registry for OSHClientSession instances, one per Node.
The application owns one SessionManager; passing it to
Node(...)causes the node to call register_session and bind itself to a fresh OSHClientSession. start_session_streams / start_all_streams are convenience entry points for booting streams on a single node or all nodes at once.- Parameters:
session_tokens (dict[str, str]) – Optional dict of session tokens keyed by ID (reserved for future auth schemes; currently unused).
- sessions: dict[str, OSHClientSession] = None¶
- register_session(session_id, session)[source]¶
Store
sessionundersession_idand return it.- Parameters:
session (OSHClientSession)
- Return type:
- get_session(session_id)[source]¶
Return the session for
session_idorNoneif unknown.- Return type:
OSHClientSession | None
- start_session_streams(session_id)[source]¶
Start every streamable on the session identified by
session_id.- Raises:
ValueError – if no session is registered for that ID.
- class oshconnect.streamableresource.Status(*values)[source]¶
Bases:
EnumLifecycle states a StreamableResource transitions through:
STOPPED → INITIALIZING → INITIALIZED → STARTING → STARTED → STOPPING → STOPPED.- INITIALIZING = 'initializing'¶
- INITIALIZED = 'initialized'¶
- STARTING = 'starting'¶
- STARTED = 'started'¶
- STOPPING = 'stopping'¶
- STOPPED = 'stopped'¶
- class oshconnect.streamableresource.StreamableModes(*values)[source]¶
Bases:
EnumDirection(s) in which a streamable resource exchanges messages.
PUSH: this client publishes outbound messages only.PULL: this client subscribes to inbound messages only.BIDIRECTIONAL: both publish and subscribe.
- PUSH = 'push'¶
- PULL = 'pull'¶
- BIDIRECTIONAL = 'bidirectional'¶
- class oshconnect.streamableresource.StreamableResource(node, connection_mode='push')[source]¶
-
Abstract base for System, Datastream, and ControlStream.
Encapsulates the streaming machinery shared by all three: MQTT subscribe/ publish, optional WebSocket I/O, inbound and outbound message deques, and lifecycle (initialize → start → stop). Subclasses set
_underlying_resource(a SystemResource / DatastreamResource / ControlStreamResource pydantic model) and override init_mqtt to derive the appropriate topic.- Parameters:
node (Node) – The parent Node this resource lives under.
connection_mode (StreamableModes) – One of StreamableModes. Default
PUSH.
- get_streamable_id()[source]¶
Return the local UUID assigned at construction (not the server-side ID).
- Return type:
- initialize()[source]¶
Build the WebSocket URL, allocate I/O queues, and configure MQTT.
Must be called before start. Inspects
_underlying_resourceto determine the right resource type and constructs the WS URL via the parent node’s APIHelper.- Raises:
ValueError – if
_underlying_resourceis not set or is not one of System / Datastream / ControlStream.
- start()[source]¶
Subclasses override to also kick off MQTT subscribe / async write tasks. Logs and returns silently if initialize hasn’t been called.
- async stream()[source]¶
Open a WebSocket to
ws_urland run read/write loops in parallel.Used as an alternative to MQTT for resources that prefer WS streaming. Reads incoming frames into the message handler and drains
_msg_writer_queueto the socket.
- init_mqtt()[source]¶
Wire the MQTT subscribe-acknowledged callback if a client exists.
Subclasses override to additionally derive their resource-specific topic into
self._topic(see Datastream.init_mqtt / ControlStream.init_mqtt).
- get_mqtt_topic(subresource=None, data_topic=True, format=None)[source]¶
Retrieves the MQTT topic for this streamable resource based on its underlying resource type. By default, returns a Resource Data Topic (:data suffix per CS API Part 3). :param subresource: Optional subresource type to get the topic for, defaults to None :param data_topic: If True (default), produces a Resource Data Topic with ‘:data’ suffix. Set False for Resource Event Topics. :param format: Optional MIME content-type for the
:data/<token>format subtopic.None(default) emits bare:dataso the server’s default format applies. Ignored whendata_topic=False.- Parameters:
subresource (APIResourceTypes | None)
data_topic (bool)
format (str | None)
- uses_nats()[source]¶
True when this resource’s active transport is NATS.
Drives the flat-vs-nested topic choice: NATS data subjects nest under
systems(and need the parent system id) where the MQTT topics are flat. See get_nats_subject.- Return type:
- get_stream_topic(subresource=None, data_topic=True, format=None)[source]¶
Return the data topic/subject for the active transport.
Dispatches to get_nats_subject (nested-under-systems, dot-delimited) when NATS is active, else get_mqtt_topic (flat, slash-delimited). Subclasses call this from
init_mqttso they stay transport-agnostic.- Parameters:
subresource (APIResourceTypes | None)
data_topic (bool)
format (str | None)
- Return type:
- get_subscribe_topic(subresource=None, format=None)[source]¶
Return the topic/subject to subscribe to for inbound data.
For MQTT this is the exact per-format topic (the broker negotiates the format per subscription). For NATS it is a format-wildcard subject (
…:data.*): in PROACTIVE mode the server publishes each stream on a single server-chosen format regardless of the subscriber, so we accept whatever it emits and read the concrete format back from each delivered subject vianats_content_type_from_subject().- Parameters:
subresource (APIResourceTypes | None)
format (str | None)
- Return type:
- get_nats_subject(subresource=None, data_topic=True, format=None, format_wildcard=False)[source]¶
Build the CS API Part 3 NATS data subject for this resource.
Unlike the flat MQTT topics, NATS data subjects are the canonical nested-under-systems resource path, dot-delimited, with a
:data[.<token>]suffix — e.g.api.systems.{sysId}.datastreams.{dsId}.observations:data.swe-proto. This mirrorsConSysApiNatsConnector.getResourceUrion the server, which reverses a subject back into/systems/.../observationsby stripping the:datasuffix and replacing.with/.When
format_wildcardis set, the format subtopic is a NATS single-token wildcard (…:data.*) instead of a concrete token. This is used to subscribe in PROACTIVE mode, where the server publishes on one server-chosen format subtopic regardless of the datastream’s own obs format — the actual format is then read back from each delivered subject’s trailing token (seenats_content_type_from_subject()).The parent system id required for the nesting is read from the datastream’s
system_id(system@id) or — for control streams and locally-created datastreams — from_parent_resource_id.- Raises:
ValueError – if the underlying resource type is unsupported or the parent system id cannot be resolved.
- Parameters:
subresource (APIResourceTypes | None)
data_topic (bool)
format (str | None)
format_wildcard (bool)
- Return type:
- get_event_topic()[source]¶
Returns the Resource Event Topic for this streamable resource per CS API Part 3. Event topics point to the resource itself (no ‘:data’ suffix) and are used to receive CloudEvents lifecycle notifications (create/update/delete) published by the server.
For Datastream/ControlStream, includes the parent system path when a parent resource ID is available.
- Return type:
- subscribe_events(callback=None, qos=0)[source]¶
Subscribes to the Resource Event Topic for this streamable resource. Event messages are CloudEvents v1.0 JSON payloads published by the server when the resource is created, updated, or deleted.
- stop()[source]¶
Tear down the streaming process and mark the resource
STOPPED.Note: currently calls
Process.terminate(); cleaner shutdown (graceful drain, auth state preservation) is a known follow-up.
- set_parent_resource_id(res_id)[source]¶
Set the server-side ID of the parent resource (e.g. the parent System for a Datastream / ControlStream).
- Parameters:
res_id (str)
- get_parent_resource_id()[source]¶
Return the server-side ID of the parent resource, if set.
- Return type:
- set_connection_mode(connection_mode)[source]¶
Switch direction (PUSH / PULL / BIDIRECTIONAL).
- Parameters:
connection_mode (StreamableModes)
- fetch(time_period)[source]¶
Fetch data over a TimePeriod. Hook for subclass implementations; no-op here.
- Parameters:
time_period (TimePeriod)
- get_msg_reader_queue()[source]¶
Returns the message queue for this streamable resource. In cases where a custom message handler is used this is not guaranteed to return anything or provided a queue with data. :return: Queue object
- Return type:
Queue
- get_msg_writer_queue()[source]¶
Returns the message queue for writing messages to this streamable resource. :return: Queue object
- Return type:
Queue
- get_underlying_resource()[source]¶
Return the pydantic resource model (System/Datastream/ControlStream) that backs this streamable.
- Return type:
T
- insert_data(data)[source]¶
Inserts data into the message writer queue to be sent over the WebSocket / MQTT connection. Encoding is delegated to _encode_for_wire, which subclasses can override to honour their datastream’s wire format (e.g. Datastream routes through SWEBinaryCodec when its schema is application/swe+binary). No semantic validation is performed. :param data: Data to be sent (dict, sequence, or bytes-like).
- subscribe_mqtt(topic, qos=0)[source]¶
Subscribe to an arbitrary MQTT
topicusing the default callback (appends incoming payloads to_inbound_deque).
- publish(payload, topic=None)[source]¶
Publishes data to the MQTT topic associated with this streamable resource. :param payload: Data to be published, subclass should determine specifically allowed types :param topic: Specific implementation determines the topic from the provided string, if None the default topic is used
- Parameters:
topic (str)
- subscribe(topic=None, callback=None, qos=0)[source]¶
Subscribes to the MQTT topic associated with this streamable resource. :param topic: Specific implementation determines the topic from the provided string, if None the default topic is used :param callback: Optional callback function to handle incoming messages, if None the default handler is used :param qos: Quality of Service level for the subscription, default is 0
- get_inbound_deque()[source]¶
Return the deque that receives inbound MQTT message payloads.
- Return type:
- to_storage_dict()[source]¶
Return a JSON-safe snapshot of the streamable’s identity and connection state, for OSHConnect’s persistence layer. Subclasses extend this with their own fields and the dumped underlying resource. Safely handles missing / None attributes.
Not a CS API server-shaped payload.
- Return type:
- class oshconnect.streamableresource.System(label=None, urn=None, parent_node=None, **kwargs)[source]¶
Bases:
StreamableResource[SystemResource]A sensor system on an OSH server: a logical grouping of one or more Datastream outputs and ControlStream inputs sharing a single URN.
Construct directly to define a new system, or build one from a parsed SystemResource via from_system_resource. Use discover_datastreams / discover_controlstreams to populate child resources from the server, or add_insert_datastream / add_and_insert_control_stream to create new ones server-side.
- __init__(label=None, urn=None, parent_node=None, **kwargs)[source]¶
- Parameters:
label (str) – The display string for the system. Maps to SML’s
labeland GeoJSON’sproperties.nameon the wire — the OGC CS API only carries one display string per system.urn (str) – The URN of the system, typically formed as such:
'urn:general_identifier:specific_identifier:…'.parent_node (Node) – The Node this system attaches to.
kwargs –
‘description’: A description of the system
’resource_id’: The server-assigned ID once known
’name’: Deprecated alias for
label. EmitsDeprecationWarning; iflabelis also supplied,nameis ignored. Will be removed in a future release.
- datastreams: list[Datastream]¶
- control_channels: list[ControlStream]¶
- property name: str¶
Deprecated alias for label. Will be removed in a future release.
SWE Common 3 / OGC CS API only carry one display string per system (SML’s
label, GeoJSON’sproperties.name). The wrapper’s prior name field was always set to the same value as label. Use self.label directly going forward.
- discover_datastreams()[source]¶
GET
/systems/{id}/datastreamsand instantiate Datastream objects for every entry. New datastreams are appended toself.datastreamsand also returned.For each discovered datastream we additionally fetch its record schema (
GET /datastreams/{id}/schema?obsFormat=…) and cache it on_underlying_resource.record_schema. The schema variant is chosen from the datastream’s advertisedformatslist:application/swe+jsonis preferred when available (parsed as SWEDatastreamRecordSchema); otherwiseapplication/swe+binaryis used (parsed as SWEBinaryDatastreamRecordSchema). Datastreams like Axis cameravideo1outputs advertise only the binary variant — without this fallback every video datastream would land without a schema. The CS API listing endpoint omits the inner schema, so without this step every discovered datastream would be missing the schema callers need for observation construction or cross-node sync. A failure on a single datastream’s schema fetch is downgraded to a warning so it doesn’t poison the whole call.- Return type:
- discover_controlstreams()[source]¶
GET
/systems/{id}/controlstreamsand instantiate ControlStream objects for every entry. New control streams are appended toself.control_channelsand also returned.For each discovered control stream we additionally fetch the command schema (
GET /controlstreams/{id}/schema?f=json, which OSH returns asapplication/jsonwith aparametersSchemaSWE Common component) and cache it on_underlying_resource.command_schemaas a JSONCommandSchema.f=jsonis the OGC API standard format-selector and pins the response shape to the JSON variant — without it the server default could change. The CS API listing endpoint omits the inner schema, so without this step every discovered control stream would be missing the schema callers need for command construction or cross-node sync. A failure on a single control stream’s schema fetch is downgraded to a warning so it doesn’t poison the whole call.- Return type:
- classmethod from_resource(system_resource, parent_node)[source]¶
Build a System from an already-parsed SystemResource.
Mirror of Datastream.__init__(parent_node=, datastream_resource=) and ControlStream.__init__(node=, controlstream_resource=) — provides the same “I have a parsed pydantic resource model in memory and want a wrapper attached to a node” entry point for Systems, whose constructor takes individual fields rather than a full resource model.
Handles both wire shapes that round-trip through SystemResource: the GeoJSON form (with a
propertiesblock carryingname/uid) and the SML form (label/uiddirectly on the resource). Source of the resource doesn’t matter — built locally, validated from from_smljson_dict / from_geojson_dict / from_csapi_dict, returned by some other library, etc.- Parameters:
system_resource (SystemResource) – A populated SystemResource instance.
parent_node (Node) – The Node the new System will attach to.
- Returns:
A System wrapper bound to
parent_nodewith_underlying_resourceset tosystem_resource.- Return type:
- static from_system_resource(system_resource, parent_node)[source]¶
Build a System from an already-parsed SystemResource.
Deprecated since version 0.5.1: Use
System.from_resource()instead — same behavior, more consistent name with other wrappers’ resource-taking factories.Handles both shapes the OSH server emits: the GeoJSON form (with a
propertiesblock carryingname/uid) and the SML form (label/uiddirectly on the resource).- Parameters:
system_resource (SystemResource)
parent_node (Node)
- Return type:
- to_system_resource()[source]¶
Render this System as a SystemResource pydantic model suitable for POSTing to the server.
When this wrapper already carries an
_underlying_resource(e.g. populated byfrom_csapi_dict,set_system_resource, or a priorretrieve_resourcecall), all of its fields are preserved into a deep copy — so cross-node sync, partial updates, and re-POSTs round-trip everything the source carried, not justuniqueId/label/ a hardcodedPhysicalSystemtype. Currently-attached datastreams are always reflected intooutputsso newly-added children come along.When no underlying resource is present (i.e. during this wrapper’s own
__init__), a thin shell is built from wrapper attrs and the SML type defaults toPhysicalSystem.- Return type:
- set_system_resource(sys_resource)[source]¶
Replace the underlying SystemResource model.
- Parameters:
sys_resource (SystemResource)
- add_insert_datastream(datastream_schema)[source]¶
Adds a datastream to the system while also inserting it into the system’s parent node via HTTP POST.
- Parameters:
datastream_schema (DatastreamResource) – DataRecordSchema to be used to define the datastream. Must carry a
namematching NameToken (^[A-Za-z][A-Za-z0-9_\-]*$); SWE Common 3 wraps DataStream.elementType in SoftNamedProperty, so the root component requires a name.- Returns:
- add_insert_controlstream(controlstream_resource)[source]¶
Adds a control stream to the system while also inserting it into the system’s parent node via HTTP POST.
Mirrors add_insert_datastream: caller assembles the full ControlStreamResource (including the embedded command_schema) and this method posts it to
/systems/{id}/controlstreams, captures the new resource ID from theLocationheader, and returns a wrapped ControlStream.For the embedded command_schema, prefer JSONCommandSchema (commandFormat: application/json with a
parametersSchema). It matches what OSH returns fromGET /controlstreams/{id}/schema?f=json(the formdiscover_controlstreamsparses), keeps round-trip sync symmetric, and avoids the SWE+JSONencoding-omission deviation documented indocs/osh_spec_deviations.md§1. SWEJSONCommandSchema (application/swe+jsonwithrecordSchemaplusencoding) is also accepted for spec-strict scenarios.- Parameters:
controlstream_resource (ControlStreamResource) – A fully-built ControlStreamResource carrying
name,input_name, andcommand_schema.- Returns:
ControlStream object added to the system.
- Return type:
- add_and_insert_control_stream(control_stream_record_schema, input_name=None, valid_time=None, command_format='application/json')[source]¶
Accepts a DataRecordSchema and creates a ControlStreamResource with the matching command-schema variant, then POSTs it to the parent node.
Per CS API Part 2 §16.x, command schemas come in two wire forms:
application/json→ JSONCommandSchema carrying parametersSchema (the SWE Common component); no encoding. This is the default. It matches what OSH returns fromGET /controlstreams/{id}/schema?f=json(the formdiscover_controlstreamsparses), keeps round-trip sync symmetric, and avoids the SWE+JSONencoding-omission deviation documented indocs/osh_spec_deviations.md§1.application/swe+json→ SWEJSONCommandSchema carrying recordSchema (the SWE Common component) and encoding (JSONEncoding). Spec-canonical; passcommand_format='application/swe+json'to opt in.
- Parameters:
control_stream_record_schema (DataRecordSchema) – DataRecordSchema to wrap. Must carry a
namematching NameToken (^[A-Za-z][A-Za-z0-9_\-]*$); the schema is the root named component required by both command-schema variants.input_name (str) – Name of the input. If None, the schema label is lowercased and whitespace-stripped.
valid_time (TimePeriod) – Optional TimePeriod; defaults to
[now, now + 1 year].command_format (str) –
"application/json"(default) or"application/swe+json". Anything else raisesValueError.
- Returns:
ControlStream object added to the system.
- Return type:
- insert_self()[source]¶
POST this system to the server (Content-Type
application/sml+json) and capture the new resource ID from theLocationresponse header.Server-assigned fields (
id,links) are stripped from the body before POST so a re-POSTed (e.g. cross-node-synced) system doesn’t leak the source server’s identifier or links to the destination — the destination assigns its own.
- retrieve_resource()[source]¶
GET
/systems/{id}and refresh the underlying SystemResource. ReturnsNoneeither way (kept for API symmetry).
- to_storage_dict()[source]¶
Return a JSON-safe snapshot of this system, its child datastreams / control streams, and the dumped underlying SystemResource, for OSHConnect’s persistence layer.
Not a CS API server-shaped payload — the
underlying_resourceblock is the only piece that matches the CS API system shape.- Return type:
- classmethod from_storage_dict(data, node)[source]¶
Build a System from a dict produced by to_storage_dict.
Expects
label,urn, optionaldescription/resource_id, and optionaldatastreams/control_channels/underlying_resourceblocks. The embeddedunderlying_resourceis parsed via SystemResource.model_validate, so that nested block can also be a CS API server response body.For backwards compatibility,
data["name"]is accepted as a legacy alias forlabeliflabelis missing — older snapshots written before the name/label consolidation still load.
- class oshconnect.streamableresource.Utilities[source]¶
Bases:
objectModule-level helper namespace; intentionally just static methods.
—
Resource Data Models¶
Pydantic models that represent CS API resources returned from or sent to an OSH server.
- class oshconnect.resource_datamodels.BoundingBox(*, lower_left_corner, upper_right_corner, min_value=None, max_value=None)[source]¶
Bases:
BaseModel- Parameters:
- lower_left_corner: Point¶
- upper_right_corner: Point¶
- class oshconnect.resource_datamodels.BaseResource(*, id, name, description=None, type=None, links=None)[source]¶
Bases:
BaseModel- links: List[Link]¶
- class oshconnect.resource_datamodels.SystemResource(*, type=None, id=None, properties=None, geometry=None, bbox=None, links=None, description=None, uniqueId=None, label=None, lang=None, keywords=None, identifiers=None, classifiers=None, validTime=None, securityConstraints=None, legalConstraints=None, characteristics=None, capabilities=None, contacts=None, documentation=None, history=None, definition=None, typeOf=None, configuration=None, featuresOfInterest=None, inputs=None, outputs=None, parameters=None, modes=None, method=None, **extra_data)[source]¶
Bases:
BaseModel- Parameters:
type (str)
id (str)
properties (dict)
geometry (Geometry | None)
bbox (BoundingBox)
links (List[Link])
description (str)
uniqueId (str)
label (str)
lang (str)
identifiers (list[Term])
classifiers (list[Term])
validTime (TimePeriod)
characteristics (list[Characteristics])
capabilities (list[Capabilities])
definition (str)
typeOf (str)
configuration (dict)
method (dict)
extra_data (Any)
- bbox: BoundingBox¶
- links: List[Link]¶
- valid_time: TimePeriod¶
- to_smljson_dict()[source]¶
Render this system as an application/sml+json dict (SensorML JSON encoding).
The
typediscriminator (PhysicalSystem,PhysicalComponent,SimpleProcess,AggregateProcess, etc.) is preserved fromself.feature_typewhen set — important for cross-node sync, where the source’s SML kind determines how OSH surfacesfeatureType(e.g.Sensorvs.System). Defaults to"PhysicalSystem"only whenfeature_typeis unset, so callers building a bareSystemResourcestill get a valid SML body. Does not mutateself.- Return type:
- to_geojson_dict()[source]¶
Render this system as an application/geo+json dict.
The
typefield is always set to"Feature"per the GeoJSON spec, regardless ofself.feature_type— that’s the whole point of this rendering variant. Does not mutateself.- Return type:
- classmethod from_smljson_dict(data)[source]¶
Build a SystemResource from an application/sml+json dict (e.g., a CS API server response body for a system in SML form).
- Parameters:
data (dict)
- Return type:
- classmethod from_geojson_dict(data)[source]¶
Build a SystemResource from an application/geo+json dict (e.g., a CS API server response body for a system in GeoJSON form).
- Parameters:
data (dict)
- Return type:
- class oshconnect.resource_datamodels.DatastreamResource(*, id, name, description=None, validTime, outputName=None, procedure_link=None, deployment_link=None, feature_of_interest_link=None, sampling_feature_link=None, parameters=None, phenomenonTime=None, resultTimeInterval=None, type=None, resultType=None, formats=<factory>, observedProperties=<factory>, system_id=None, links=None, schema=None)[source]¶
Bases:
BaseModelThe DatastreamResource class is a Pydantic model that represents a datastream resource in the OGC SensorThings API. It contains all the necessary and optional properties listed in the OGC Connected Systems API documentation. Note that, depending on the format of the request, the fields needed may differ. There may be derived models in a later release that will have different sets of required fields to ease the validation process for users.
- Parameters:
id (str)
name (str)
description (str)
validTime (TimePeriod)
outputName (str)
procedure_link (Link)
deployment_link (Link)
feature_of_interest_link (Link)
sampling_feature_link (Link)
parameters (dict)
phenomenonTime (TimePeriod)
resultTimeInterval (TimePeriod)
type (str)
resultType (str)
system_id (str)
links (List[Link])
schema (SWEDatastreamRecordSchema | SWEBinaryDatastreamRecordSchema | SWEProtobufDatastreamRecordSchema | SWEFlatBuffersDatastreamRecordSchema | OMJSONDatastreamRecordSchema)
- valid_time: TimePeriod¶
- procedure_link: Link¶
- deployment_link: Link¶
- feature_of_interest_link: Link¶
- sampling_feature_link: Link¶
- phenomenon_time: TimePeriod¶
- result_time: TimePeriod¶
- links: List[Link]¶
- record_schema: AnyDatastreamRecordSchema¶
- to_csapi_dict()[source]¶
Render this datastream as the CS API application/json resource body. The embedded
schemafield is dumped polymorphically per whichever variant (SWEDatastreamRecordSchema / OMJSONDatastreamRecordSchema) it holds.- Return type:
- class oshconnect.resource_datamodels.ObservationResource(*, sampling_feature_id=None, procedure_link=None, phenomenonTime=None, resultTime, parameters=None, result, result_link=None)[source]¶
Bases:
BaseModel- Parameters:
sampling_feature_id (str)
procedure_link (Link)
phenomenonTime (TimeInstant)
resultTime (TimeInstant)
parameters (dict)
result (dict)
result_link (Link)
- procedure_link: Link¶
- phenomenon_time: TimeInstant¶
- result_time: TimeInstant¶
- result_link: Link¶
- to_omjson_dict(datastream_id=None)[source]¶
Render this observation as an application/om+json dict (the
ObservationOMJSONInlineshape).
- to_swejson_dict(schema=None)[source]¶
Render this observation as an application/swe+json payload (the SWE Common JSON encoding of one record).
SWE+JSON encodes a single observation as a flat JSON object whose keys are the schema field names;
self.resultis already that dict, so this is essentially a passthrough. The optionalschemaargument is accepted for forward compatibility (when we add field-order / encoding-aware emission).- Parameters:
schema (AnyComponent)
- Return type:
- classmethod from_omjson_dict(data)[source]¶
Build an ObservationResource from an application/om+json dict.
Parses through ObservationOMJSONInline to validate the OM+JSON envelope, then strips the
datastream@id/foi@idenvelope fields (those live on the surrounding context, not the resource) and returns the inner observation.- Parameters:
data (dict)
- Return type:
- classmethod from_swejson_dict(data, schema=None, result_time=None)[source]¶
Build an ObservationResource from an application/swe+json observation payload.
SWE+JSON observations don’t carry an envelope (no
resultTime/phenomenonTimefields); passresult_timeexplicitly when you have it, otherwise the current UTC time is used.- Parameters:
- Return type:
- class oshconnect.resource_datamodels.ControlStreamResource(*, id=None, name, description=None, validTime=None, inputName=None, procedure_link=None, deployment_link=None, feature_of_interest_link=None, sampling_feature_link=None, issueTime=None, executionTime=None, live=None, asynchronous=True, schema=None, links=None)[source]¶
Bases:
BaseModel- Parameters:
id (str)
name (str)
description (str)
validTime (TimePeriod)
inputName (str)
procedure_link (Link)
deployment_link (Link)
feature_of_interest_link (Link)
sampling_feature_link (Link)
issueTime (TimePeriod)
executionTime (TimePeriod)
live (bool)
asynchronous (bool)
schema (SWEJSONCommandSchema | JSONCommandSchema)
links (List[Link])
- valid_time: TimePeriod¶
- procedure_link: Link¶
- deployment_link: Link¶
- feature_of_interest_link: Link¶
- sampling_feature_link: Link¶
- issue_time: TimePeriod¶
- execution_time: TimePeriod¶
- command_schema: AnyCommandSchema¶
- links: List[Link]¶
- to_csapi_dict()[source]¶
Render this control stream as the CS API application/json resource body. The embedded
schemafield is dumped polymorphically per whichever variant (SWEJSONCommandSchema / JSONCommandSchema) it holds.- Return type:
—
SWE Schema Components¶
Builder classes for constructing datastream and command schemas using SWE Common data types.
- oshconnect.swe_components.check_named(component, location)[source]¶
Validate that a component bound via SoftNamedProperty carries a NameToken name.
- Parameters:
location (str)
- Return type:
None
- class oshconnect.swe_components.AnyComponentSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
BaseModel- Parameters:
- class oshconnect.swe_components.DataRecordSchema(*, type='DataRecord', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None, fields)[source]¶
Bases:
AnyComponentSchema- Parameters:
type (Literal['DataRecord'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
fields (Annotated[list[Annotated[DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]], MinLen(min_length=1)])
- type: Literal['DataRecord']¶
- class oshconnect.swe_components.VectorSchema(*, type='Vector', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition, referenceFrame, localFrame=None, coordinates)[source]¶
Bases:
AnyComponentSchema- Parameters:
- type: Literal['Vector']¶
- coordinates: list[CountSchema] | list[QuantitySchema] | list[TimeSchema]¶
- class oshconnect.swe_components.DataArraySchema(*, type='DataArray', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None, elementCount, elementType, encoding=None, values=None)[source]¶
Bases:
AnyComponentSchema- Parameters:
type (Literal['DataArray'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
elementCount (dict | str | CountSchema)
elementType (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
encoding (str)
values (list)
- type: Literal['DataArray']¶
- element_count: dict | str | CountSchema¶
- element_type: AnyComponent¶
- class oshconnect.swe_components.MatrixSchema(*, type='Matrix', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None, elementCount, elementType, encoding=None, values=None, reference_frame=None, local_frame=None)[source]¶
Bases:
AnyComponentSchema- Parameters:
type (Literal['Matrix'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
elementCount (dict | str | CountSchema)
elementType (list[Annotated[DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])
encoding (str)
values (list)
reference_frame (str)
local_frame (str)
- type: Literal['Matrix']¶
- element_count: dict | str | CountSchema¶
- class oshconnect.swe_components.DataChoiceSchema(*, type='DataChoice', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None, choiceValue=None, items)[source]¶
Bases:
AnyComponentSchema- Parameters:
type (Literal['DataChoice'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
choiceValue (CategorySchema)
items (list[Annotated[DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])
- type: Literal['DataChoice']¶
- choice_value: CategorySchema¶
- class oshconnect.swe_components.GeometrySchema(*, type='Geometry', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition, constraint=<factory>, nilValues=None, srs, value=None)[source]¶
Bases:
AnyComponentSchema- Parameters:
- type: Literal['Geometry']¶
- value: Geometry¶
- class oshconnect.swe_components.AnySimpleComponentSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyComponentSchema- Parameters:
- quality: list[Annotated[QuantitySchema | QuantityRangeSchema | CategorySchema | TextSchema, Field(discriminator='type')]]¶
- constraint: Any¶
- value: Any¶
- class oshconnect.swe_components.AnyScalarComponentSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnySimpleComponentSchemaA base class for all scalar components. The structure is essentially that of AnySimpleComponent
- class oshconnect.swe_components.BooleanSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Boolean']¶
- class oshconnect.swe_components.CountSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Count']¶
- class oshconnect.swe_components.QuantitySchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Quantity']¶
- uom: UCUMCode | URI¶
- class oshconnect.swe_components.TimeSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Time']¶
- uom: UCUMCode | URI¶
- class oshconnect.swe_components.CategorySchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Category']¶
- class oshconnect.swe_components.TextSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnyScalarComponentSchema- Parameters:
- type: Literal['Text']¶
- class oshconnect.swe_components.CountRangeSchema(*, type, id=None, name=None, label=None, description=None, updatable=False, optional=False, definition=None)[source]¶
Bases:
AnySimpleComponentSchema- Parameters:
- type: Literal['CountRange']¶
- uom: UCUMCode | URI¶
- class oshconnect.swe_components.QuantityRangeSchema(*, type='QuantityRange', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition, referenceFrame=None, axisID=None, quality=None, nilValues=None, constraint=None, value=None, uom)[source]¶
Bases:
AnySimpleComponentSchema- Parameters:
type (Literal['QuantityRange'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
referenceFrame (str)
axisID (str)
quality (list[Annotated[QuantitySchema | QuantityRangeSchema | CategorySchema | TextSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])
nilValues (list)
constraint (Any)
uom (UCUMCode | URI)
- type: Literal['QuantityRange']¶
- uom: UCUMCode | URI¶
- class oshconnect.swe_components.TimeRangeSchema(*, type='TimeRange', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition, referenceFrame=None, axisID=None, quality=None, nilValues=None, constraint=None, value=None, referenceTime=None, local_frame=None, uom)[source]¶
Bases:
AnySimpleComponentSchema- Parameters:
type (Literal['TimeRange'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
referenceFrame (str)
axisID (str)
quality (list[Annotated[QuantitySchema | QuantityRangeSchema | CategorySchema | TextSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])
nilValues (list)
constraint (Any)
referenceTime (str)
local_frame (str)
uom (UCUMCode | URI)
- type: Literal['TimeRange']¶
- uom: UCUMCode | URI¶
- class oshconnect.swe_components.CategoryRangeSchema(*, type='CategoryRange', id=None, name=None, label=None, description=None, updatable=False, optional=False, definition, referenceFrame=None, axisID=None, quality=None, nilValues=None, constraint=None, value=None, codeSpace=None)[source]¶
Bases:
AnySimpleComponentSchema- Parameters:
type (Literal['CategoryRange'])
id (str)
name (str)
label (str)
description (str)
updatable (bool)
optional (bool)
definition (str)
referenceFrame (str)
axisID (str)
quality (list[Annotated[QuantitySchema | QuantityRangeSchema | CategorySchema | TextSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])
nilValues (list)
constraint (Any)
codeSpace (str)
- type: Literal['CategoryRange']¶
- class oshconnect.schema_datamodels.CommandJSON(*, control_id=None, issue_time=<factory>, sender=None, parameters=None)[source]¶
Bases:
BaseModelA class to represent a command in JSON format
- Parameters:
- class oshconnect.schema_datamodels.CommandSchema(*, commandFormat)[source]¶
Bases:
BaseModelBase class representation for control streams’ command schemas
- Parameters:
commandFormat (str)
- class oshconnect.schema_datamodels.SWEJSONCommandSchema(*, commandFormat='application/swe+json', encoding, recordSchema)[source]¶
Bases:
CommandSchemaSWE+JSON command schema
- Parameters:
commandFormat (Literal['application/swe+json'])
encoding (JSONEncoding)
recordSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
- command_format: Literal['application/swe+json']¶
- encoding: JSONEncoding¶
- record_schema: AnyComponent¶
- class oshconnect.schema_datamodels.JSONCommandSchema(*, commandFormat='application/json', parametersSchema, resultSchema=None, feasibilityResultSchema=None)[source]¶
Bases:
CommandSchemaJSON command schema
- Parameters:
commandFormat (Literal['application/json'])
parametersSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
resultSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
feasibilityResultSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
- command_format: Literal['application/json']¶
- params_schema: AnyComponent¶
- result_schema: AnyComponent¶
- feasibility_schema: AnyComponent¶
- class oshconnect.schema_datamodels.DatastreamRecordSchema(*, obsFormat)[source]¶
Bases:
BaseModelA class to represent the schema of a datastream
- Parameters:
obsFormat (str)
- class oshconnect.schema_datamodels.SWEDatastreamRecordSchema(*, obsFormat, encoding=None, recordSchema)[source]¶
Bases:
DatastreamRecordSchema- Parameters:
obsFormat (Literal['application/swe+json', 'application/swe+csv', 'application/swe+text'])
encoding (JSONEncoding)
recordSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
- obs_format: Literal['application/swe+json', 'application/swe+csv', 'application/swe+text']¶
- encoding: JSONEncoding¶
- record_schema: AnyComponent¶
- to_swejson_dict()[source]¶
Render as an application/swe+json datastream-schema document.
- Return type:
- class oshconnect.schema_datamodels.SWEBinaryDatastreamRecordSchema(*, obsFormat='application/swe+binary', recordSchema, recordEncoding)[source]¶
Bases:
DatastreamRecordSchemaDatastream observation schema for application/swe+binary.
Split from SWEDatastreamRecordSchema because the encoding block is a BinaryEncoding (with a members list mapping component refs to dataType / compression), not a JSONEncoding. The recordSchema side mirrors the SWE+JSON form — it describes the semantic shape of the record. The recordEncoding side describes the wire shape, overriding the semantic shape where needed (e.g. a DataArray in the recordSchema may be replaced by a single Block member with
compression="H264"on the wire, as Axis cameras do for video).Use
oshconnect.swe_binary.SWEBinaryCodec(schema)to encode dicts to bytes and decode bytes back to dicts.- Parameters:
obsFormat (Literal['application/swe+binary'])
recordSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
recordEncoding (BinaryEncoding)
- obs_format: Literal['application/swe+binary']¶
- record_schema: AnyComponent¶
- record_encoding: BinaryEncoding¶
- to_swebinary_dict()[source]¶
Render as an application/swe+binary datastream-schema document.
- Return type:
- class oshconnect.schema_datamodels.SWEProtobufDatastreamRecordSchema(*, obsFormat='application/swe+proto', fileDescriptorSet, messageType=None, recordEncoding=<factory>)[source]¶
Bases:
DatastreamRecordSchemaDatastream observation schema for
application/swe+proto.application/swe+protois the per-datastream descriptor Protobuf encoding: each DataStream ships a pre-compiled Protobuf schema (a serializedgoogle.protobuf.FileDescriptorSet) describing one per-datastream observation message — envelope fields 1–5 (id, datastream_id, foi_id, phenomenon/result time) plus the SWE Common record at fields 6+. An observation on the wire is a serialized instance of that message; receivers register the descriptor in aDescriptorPooland decode dynamically (noprotoc).This carries the descriptor itself rather than a SWE
recordSchematree — the descriptor is the source of truth for the wire layout, and SWE semantics (uom, definition, …) travel as field options inside it. The codec lives inoshconnect.swe_protobuf.SWEProtobufCodec.Note
The JSON envelope that delivers the descriptor over the
/datastreams/{id}/schemaendpoint is a “meet in the middle” contract with the OSH node side — currently assumed to be{"obsFormat", "messageType", "fileDescriptorSet": <base64>}. Seedocs/osh_spec_deviations.md(swe-proto-descriptor-format).- Parameters:
- obs_format: Literal['application/swe+proto']¶
- record_encoding: ProtobufEncoding¶
- to_sweproto_dict()[source]¶
Render as an application/swe+proto datastream-schema document (
fileDescriptorSetbase64-encoded).- Return type:
- classmethod from_sweproto_dict(data)[source]¶
Build from an application/swe+proto datastream-schema dict.
- Parameters:
data (dict)
- Return type:
- classmethod from_record_schema(record, *, message_name='Observation', package='oshconnect.sweproto', datatype_by_path=None)[source]¶
Generate a swe+proto schema from a SWE Common
DataRecord.Builds the per-datastream observation descriptor (envelope fields 1–5 + the record’s components as result fields 6+, nested records and vectors recursed) — the inverse of OSH’s
ProtoSchemaWriter— and wraps it in this schema model. Use this to produce a swe+proto datastream schema from therecord_schemayou already hold for a SWE+JSON or SWE+Binary datastream.- Parameters:
record (Annotated[DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema, FieldInfo(annotation=NoneType, required=True, discriminator='type')]) – a
DataRecordSchemadescribing the observation.message_name (str) – generated message name (e.g.
f"Observation_{ds_id}").package (str) – proto package for the generated message.
datatype_by_path (dict) – optional
{ref: dataType_uri}map (same refs aBinaryEncodinguses) so float32 / int-width leaves map to the matching proto wire type instead of the defaults.
- Return type:
- classmethod from_other_schema(other, *, message_name='Observation', package='oshconnect.sweproto')[source]¶
Translate another datastream schema into swe+proto.
Accepts any record-bearing datastream schema (
SWEDatastreamRecordSchema,SWEBinaryDatastreamRecordSchema, …) — pulling itsrecord_schema— or a bareDataRecordSchema. When the source is SWE+Binary, therecordEncodingmembers are mined for each leaf’s OGCdataTypeso the generated proto fields use the matching wire type (e.g. float32 →float); SWE+JSON / SWE+CSV / SWE+text sources carry no dataType, so the node defaults apply.- Parameters:
- Return type:
- to_proto_source()[source]¶
Render this schema’s descriptor as editable
.protosource text.Works for any swe+proto schema — one generated here or one delivered by the node — since it renders the carried
FileDescriptorSet. Edit the text and recompile it withfrom_proto_source()to apply changes.- Return type:
- classmethod from_proto_source(proto_text, *, message_type=None, protoc='protoc')[source]¶
Build a schema from
.protosource text (compiles viaprotoc).The round-trip companion to
to_proto_source(): generate the text, hand-edit it (add/rename fields, tweak types, add annotations), then compile it back into a schema. Requiresprotocon PATH (or passprotoc=<path>); the binary-descriptor paths (from_record_schema / from_other_schema) need no protoc.message_typedefaults to the first message in the compiled file.- Parameters:
- Return type:
- class oshconnect.schema_datamodels.SWEFlatBuffersDatastreamRecordSchema(*, obsFormat='application/swe+flatbuffers', recordSchema, recordEncoding=<factory>)[source]¶
Bases:
DatastreamRecordSchemaDatastream observation schema for
application/swe+flatbuffers.Mirrors SWEProtobufDatastreamRecordSchema. The wire format is a FlatBuffers-serialized SWE Common 3 message; the codec lives in
oshconnect.swe_flatbuffers.SWEFlatBuffersCodec.Warning
The FlatBuffers codec is not currently functional — flatc –python does not yet support vectors-of-unions, which the SWE Common 3 schema uses for BinaryEncoding.members. The schema class is provided so the SDK can already parse and round-trip schemas that name this format; calling
SWEFlatBuffersCodec.encode/decoderaises NotImplementedError. Seedocs/osh_spec_deviations.md(flatc-python-vector-of-union).- Parameters:
obsFormat (Literal['application/swe+flatbuffers'])
recordSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
recordEncoding (FlatBuffersEncoding)
- obs_format: Literal['application/swe+flatbuffers']¶
- record_schema: AnyComponent¶
- record_encoding: FlatBuffersEncoding¶
- to_sweflatbuffers_dict()[source]¶
Render as an application/swe+flatbuffers datastream-schema document.
- Return type:
- class oshconnect.schema_datamodels.OMJSONDatastreamRecordSchema(*, obsFormat='application/om+json', resultSchema=None, parametersSchema=None, resultLink=None)[source]¶
Bases:
DatastreamRecordSchemaDatastream observation schema for the OM+JSON media type (application/om+json, also accepts application/json as a synonym on parse since OSH treats them equivalently for datastream schemas).
Per CS API Part 2 §16.1.4, this form does not carry a SWE encoding block; structure is fully described by resultSchema (inline result) or resultLink (out-of-band). parametersSchema is optional.
- Parameters:
obsFormat (Literal['application/om+json', 'application/json'])
resultSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
parametersSchema (DataRecordSchema | VectorSchema | DataArraySchema | MatrixSchema | DataChoiceSchema | GeometrySchema | BooleanSchema | CountSchema | QuantitySchema | TimeSchema | CategorySchema | TextSchema | CountRangeSchema | QuantityRangeSchema | TimeRangeSchema | CategoryRangeSchema)
resultLink (dict)
- obs_format: Literal['application/om+json', 'application/json']¶
- result_schema: AnyComponent¶
- parameters_schema: AnyComponent¶
- class oshconnect.schema_datamodels.LogicalProperty(*, title=None, type, format=None, enum=None, items=None, properties=None, ogc_definition=None, ogc_ref_frame=None, ogc_unit=None, ogc_axis=None, **extra_data)[source]¶
Bases:
BaseModelOne entry in LogicalDatastreamRecordSchema.properties.
The logical schema is OSH’s JSON-Schema-flavored representation of a SWE Common DataRecord. Each property is a JSON Schema field with OGC extension keywords (x-ogc-definition, x-ogc-refFrame, x-ogc-unit, x-ogc-axis) that carry the SWE Common metadata.
Permissive:
extra='allow'accepts JSON Schema fields we haven’t modeled (e.g.description,default,minimum,maximum, nesteditemsfor arrays).- Parameters:
- class oshconnect.schema_datamodels.LogicalDatastreamRecordSchema(*, type, title=None, properties, required=None, **extra_data)[source]¶
Bases:
BaseModelLogical schema document — OSH’s obsFormat=logical representation.
Returned by
GET /datastreams/{id}/schema?obsFormat=logical. Distinct from SWEDatastreamRecordSchema and OMJSONDatastreamRecordSchema:No
obsFormatenvelope fieldNo
recordSchemawrapper — the schema is the documentJSON Schema flavor (
type: "object"+properties) instead of a SWE Common AnyComponent treeEach property carries SWE Common metadata via
x-ogc-*extension keywords
OSH-specific (not in the OGC CS API spec) but useful for tooling that speaks JSON Schema natively. Permissive (
extra='allow') so future JSON Schema fields don’t break parsing.- Parameters:
- properties: dict[str, LogicalProperty]¶
- class oshconnect.schema_datamodels.ObservationOMJSONInline(*, datastream_id=None, foi_id=None, phenomenonTime=None, resultTime='2026-07-09T22:19:18.127423', parameters=None, result, result_links=None)[source]¶
Bases:
BaseModelA class to represent an observation in OM-JSON format
- Parameters:
- result_links: List[Link]¶
- class oshconnect.schema_datamodels.SystemEventOMJSON(*, label, description=None, definition, identifiers=None, classifiers=None, contacts=None, documentation=None, time, properties=None, configuration=None, links=None)[source]¶
Bases:
BaseModelA class to represent the schema of a system event
- Parameters:
- definition: HttpUrl¶
- class oshconnect.schema_datamodels.SystemHistoryGeoJSON(**data)[source]¶
Bases:
BaseModelA class to represent the schema of a system history
- Parameters:
data (Any)
- properties: SystemHistoryProperties¶
- geometry: Geometry¶
- class oshconnect.schema_datamodels.SystemHistoryProperties(*, feature_type, uid, name, description=None, asset_type=None, valid_time=None, parent_system_link=None, procedure_link=None)[source]¶
Bases:
BaseModel- Parameters:
- uid: URI¶
- oshconnect.schema_datamodels.AnyDatastreamRecordSchema¶
obs_format.
- Type:
Public alias for DatastreamResource.record_schema. Discriminator
alias of
Annotated[SWEDatastreamRecordSchema|SWEBinaryDatastreamRecordSchema|SWEProtobufDatastreamRecordSchema|SWEFlatBuffersDatastreamRecordSchema|OMJSONDatastreamRecordSchema, FieldInfo(annotation=NoneType, required=True, discriminator=’obs_format’)]
- oshconnect.schema_datamodels.AnyCommandSchema¶
command_format.
- Type:
Public alias for ControlStreamResource.command_schema. Discriminator
alias of
Annotated[SWEJSONCommandSchema|JSONCommandSchema, FieldInfo(annotation=NoneType, required=True, discriminator=’command_format’)]
—
Event System¶
Pub/sub event bus for in-process notifications. Implement IEventListener to receive events.
The names below are re-exported from oshconnect.events.core,
oshconnect.events.handler, etc.; :no-index: keeps Sphinx from
reporting them as duplicate object descriptions.
- class oshconnect.eventbus.Event(*, timestamp, type, topic, data, producer)[source]
Bases:
BaseModel- timestamp: datetime.datetime
- type: DefaultEventTypes
- topic: str
- data: Any
- producer: Any
- classmethod blank_event()[source]
- Return type:
Event
- class oshconnect.eventbus.DefaultEventTypes(*values)[source]
Bases:
Enum- ADD_NODE: str = 'add_node'
- REMOVE_NODE: str = 'remove_node'
- ADD_SYSTEM: str = 'add_system'
- REMOVE_SYSTEM: str = 'remove_system'
- ADD_DATASTREAM: str = 'add_datastream'
- REMOVE_DATASTREAM: str = 'remove_datastream'
- ADD_CONTROLSTREAM: str = 'add_controlstream'
- REMOVE_CONTROLSTREAM: str = 'remove_controlstream'
- NEW_OBSERVATION: str = 'new_observation'
- NEW_COMMAND: str = 'new_command'
- NEW_COMMAND_STATUS: str = 'new_command_status'
- class oshconnect.eventbus.AtomicEventTypes(*values)[source]
Bases:
EnumDefines atomic event types for local resource operations.
- CREATE
Creating a resource within OSHConnect (local, in-app).
- Type:
- POST
Posting a resource to an external server.
- Type:
- GET
Retrieving a resource from an external server.
- Type:
- MODIFY
Modifying a resource within OSHConnect (local, in-app).
- Type:
- UPDATE
Updating a resource on an external server.
- Type:
- REMOVE
Removing a resource within OSHConnect (local, in-app).
- Type:
- DELETE
Deleting a resource from an external server.
- Type:
- CREATE: str = 'create'
- POST: str = 'post'
- GET: str = 'get'
- MODIFY: str = 'modify'
- UPDATE: str = 'update'
- REMOVE: str = 'remove'
- DELETE: str = 'delete'
- class oshconnect.eventbus.EventHandler[source]
Bases:
objectSingleton event bus. Manages listener registration and event dispatch.
Listeners are filtered by type and topic before dispatch — a listener only receives events whose type is in
listener.types(empty = all types) AND whose topic is inlistener.topics(empty = all topics).Usage — functional style (no subclassing):
handler = EventHandler() def on_obs(event: Event): print(event.data) listener = handler.subscribe(on_obs, types=[DefaultEventTypes.NEW_OBSERVATION]) # later: handler.unregister_listener(listener)
Usage — subclass style:
class MyListener(IEventListener): def handle_events(self, event: Event): ... handler.register_listener(MyListener(types=[DefaultEventTypes.ADD_SYSTEM]))
- listeners: list[IEventListener] = []
- to_add: list[IEventListener] = []
- to_remove: list[IEventListener] = []
- event_queue: deque[Event] = deque([])
- publish_lock: bool = False
- register_listener(listener)[source]
- Parameters:
listener (IEventListener)
- unregister_listener(listener)[source]
- Parameters:
listener (IEventListener)
- subscribe(callback, types=None, topics=None)[source]
Register a plain callable as a listener.
- Parameters:
- Returns:
The
CallbackListener— keep a reference to unregister later.- Return type:
CallbackListener
- publish(evt)[source]
- Parameters:
evt (Event)
- commit_changes()[source]
- commit_adds()[source]
- commit_removes()[source]
- clear_listeners()[source]
- class oshconnect.eventbus.IEventListener(topics=<factory>, types=<factory>)[source]
Bases:
ABCInterface for event listeners. Subscribe to specific event types and/or topics. Empty lists mean “subscribe to all” — the handler filters before dispatching.
- types: list[DefaultEventTypes]
- abstractmethod handle_events(event)[source]
- Parameters:
event (Event)
- class oshconnect.eventbus.CallbackListener(topics=<factory>, types=<factory>, callback=None)[source]
Bases:
IEventListenerConcrete IEventListener that wraps a Python callable. The primary user-facing subscription mechanism — no subclassing required.
Example:
def my_handler(event: Event): print(event.data) listener = CallbackListener( types=[DefaultEventTypes.NEW_OBSERVATION], callback=my_handler, ) EventHandler().register_listener(listener)
- handle_events(event)[source]
- Parameters:
event (Event)
- class oshconnect.eventbus.EventBuilder[source]
Bases:
ABC- with_type(event_type)[source]
- Parameters:
event_type (DefaultEventTypes)
- Return type:
EventBuilder
- build()[source]
- Return type:
Event
- reset()[source]
- Return type:
None
—
Time Management¶
- class oshconnect.timemanagement.TemporalModes(*values)[source]¶
Bases:
Enum- REAL_TIME = 'realtime'¶
- ARCHIVE = 'archive'¶
- BATCH = 'batch'¶
- RT_SYNC = 'realtimesync'¶
- ARCHIVE_SYNC = ('archivesync',)¶
- class oshconnect.timemanagement.State(*values)[source]¶
Bases:
Enum- UNINITIALIZED = 0¶
- INITIALIZED = 1¶
- STOPPED = 2¶
- BUFFERING = 3¶
- PLAYING = 4¶
- FAST_FORWARDING = 5¶
- REWINDING = 6¶
- class oshconnect.timemanagement.TimeUtils[source]¶
Bases:
object- iso_format = '%Y-%m-%dT%H:%M:%S.%fZ'¶
- static to_epoch_time(a_time)[source]¶
Convert a datetime or string to epoch time :param a_time: :return:
- static to_utc_time(a_time)[source]¶
Convert epoch time or string to UTC time object :param a_time: :return:
- static time_to_iso(a_time)[source]¶
Convert a datetime object to iso format :param a_time: datetime object in UTC timezone or epoch time (float) :return:
- static compare_time_instants_or_indeterminate(time1, time2)[source]¶
Compare two time instants or indeterminate times. This coerces the indeterminate time ‘now’ to the current time. This may cause unexpected behavior if the times are very close together. :param time1: TimeInstant or IndeterminateTime :param time2: TimeInstant or IndeterminateTime :return: 0 if equal, -1 if time1 < time2, 1 if time1 > time2
- Parameters:
time1 (TimeInstant | str)
time2 (TimeInstant | str)
- Return type:
- class oshconnect.timemanagement.TimeInstant(epoch_time=None, utc_time=None)[source]¶
Bases:
object- Parameters:
epoch_time (float)
utc_time (datetime)
- property epoch_time¶
- class oshconnect.timemanagement.IndeterminateTime(*values)[source]¶
Bases:
Enum- NOW = 'now'¶
- LATEST = 'latest'¶
- FIRST = 'first'¶
- class oshconnect.timemanagement.TimePeriod(*, start, end)[source]¶
Bases:
BaseModel- Parameters:
start (TimeInstant | str)
end (TimeInstant | str)
- start: TimeInstant | str¶
- end: TimeInstant | str¶
- classmethod compare_start_lt_end(start, end)[source]¶
- Parameters:
start (TimeInstant | str)
end (TimeInstant | str)
- Return type:
- does_timeperiod_overlap(checked_timeperiod)[source]¶
Checks if the provided TimePeriod overlaps with the TimePeriod instance.
Note: This method does not check for some edge cases, but the TimePeriods should never be valid in those situations.
- Parameters:
checked_timeperiod (TimePeriod)
- Returns:
True if the TimePeriods overlap, False otherwise
- Return type:
- class oshconnect.timemanagement.TimeManagement(time_range)[source]¶
Bases:
object- Parameters:
time_range (TimePeriod)
- time_range: TimePeriod¶
- time_controller: TimeController¶
- class oshconnect.timemanagement.TimeController(*args, **kwargs)[source]¶
Bases:
object- set_temporal_mode(mode)[source]¶
- Parameters:
mode (TemporalMode)
- skip(a_time)[source]¶
- Parameters:
a_time (TimeInstant)
- set_timeline_start(a_time)[source]¶
- Parameters:
a_time (TimeInstant)
- set_timeline_end(a_time)[source]¶
- Parameters:
a_time (TimeInstant)
- set_current_time(a_time)[source]¶
- Parameters:
a_time (TimeInstant)
—
CS API Integration (csapi4py)¶
Constants and Enums¶
- class oshconnect.csapi4py.constants.APITerms(*values)[source]¶
Bases:
EnumDefines common endpoint terms used in the API
- API = 'api'¶
- COLLECTIONS = 'collections'¶
- COMMANDS = 'commands'¶
- COMPONENTS = 'components'¶
- CONFORMANCE = 'conformance'¶
- CONTROL_STREAMS = 'controlstreams'¶
- DATASTREAMS = 'datastreams'¶
- DEPLOYMENTS = 'deployments'¶
- EVENTS = 'events'¶
- FOIS = 'featuresOfInterest'¶
- HISTORY = 'history'¶
- ITEMS = 'items'¶
- OBSERVATIONS = 'observations'¶
- PROCEDURES = 'procedures'¶
- PROPERTIES = 'properties'¶
- SAMPLING_FEATURES = 'samplingFeatures'¶
- SCHEMA = 'schema'¶
- STATUS = 'status'¶
- SYSTEMS = 'systems'¶
- SYSTEM_EVENTS = 'systemEvents'¶
- TASKING = 'controls'¶
- UNDEFINED = ''¶
- class oshconnect.csapi4py.constants.SystemTypes(*values)[source]¶
Bases:
EnumDefines the system types
- FEATURE = 'Feature'¶
- class oshconnect.csapi4py.constants.ObservationFormat(*values)[source]¶
Bases:
EnumDefines common observation formats
- JSON = 'application/om+json'¶
- XML = 'application/om+xml'¶
- SWE_XML = 'application/swe+xml'¶
- SWE_JSON = 'application/swe+json'¶
- SWE_CSV = 'application/swe+csv'¶
- SWE_BINARY = 'application/swe+binary'¶
- SWE_TEXT = 'application/swe+text'¶
- class oshconnect.csapi4py.constants.DatastreamResultTypes(*values)[source]¶
Bases:
EnumDefines the datastream result types
- MEASURE = 'measure'¶
- VECTOR = 'vector'¶
- RECORD = 'record'¶
- COVERAGE_1D = 'coverage1D'¶
- COVERAGE_2D = 'coverage2D'¶
- COVERAGE_3D = 'coverage3D'¶
- class oshconnect.csapi4py.constants.GeometryTypes(*values)[source]¶
Bases:
EnumDefines the geometry types
- POINT = 'Point'¶
- LINESTRING = 'LineString'¶
- POLYGON = 'Polygon'¶
- MULTI_POINT = 'MultiPoint'¶
- MULTI_LINESTRING = 'MultiLineString'¶
- MULTI_POLYGON = 'MultiPolygon'¶
- class oshconnect.csapi4py.constants.APIResourceTypes(*values)[source]¶
Bases:
EnumDefines the resource types
- ROOT = ''¶
- COLLECTION = 'Collection'¶
- COMMAND = 'Command'¶
- COMPONENT = 'Component'¶
- CONTROL_CHANNEL = 'ControlChannel'¶
- DATASTREAM = 'Datastream'¶
- DEPLOYMENT = 'Deployment'¶
- OBSERVATION = 'Observation'¶
- PROCEDURE = 'Procedure'¶
- PROPERTY = 'Property'¶
- SAMPLING_FEATURE = 'SamplingFeature'¶
- SYSTEM = 'System'¶
- SYSTEM_EVENT = 'SystemEvent'¶
- SYSTEM_HISTORY = 'SystemHistory'¶
- STATUS = 'Status'¶
- SCHEMA = 'Schema'¶
- class oshconnect.csapi4py.constants.ContentTypes(*values)[source]¶
Bases:
EnumDefines the encoding formats
- JSON = 'application/json'¶
- XML = 'application/xml'¶
- SWE_XML = 'application/swe+xml'¶
- SWE_JSON = 'application/swe+json'¶
- SWE_CSV = 'application/swe+csv'¶
- SWE_BINARY = 'application/swe+binary'¶
- SWE_TEXT = 'application/swe+text'¶
- GEO_JSON = 'application/geo+json'¶
- SML_JSON = 'application/sml+json'¶
- OM_JSON = 'application/om+json'¶
Request Builder¶
- class oshconnect.csapi4py.con_sys_api.APIRequest(*, url, headers=None, auth=None)[source]¶
Bases:
BaseModelBase for per-verb request classes.
Holds the fields every HTTP method shares:
url(required),headers,auth. Subclasses (GetRequest, PostRequest, PutRequest, DeleteRequest) extend with verb-specific fields —paramsfor GET/DELETE,bodyfor POST/PUT — so the type system rejects incoherent shapes (e.g. a GET carrying a body) at construction time instead of silently sending them.Subclasses implement
execute()to dispatch through the matchingrequest_wrappersfunction.
- class oshconnect.csapi4py.con_sys_api.GetRequest(*, url, headers=None, auth=None, params=None)[source]¶
Bases:
APIRequestGET — query parameters only; no body.
- class oshconnect.csapi4py.con_sys_api.PostRequest(*, url, headers=None, auth=None, body=None)[source]¶
Bases:
APIRequestPOST — body, optional.
dictlands injson,strindata.
- class oshconnect.csapi4py.con_sys_api.PutRequest(*, url, headers=None, auth=None, body=None)[source]¶
Bases:
APIRequestPUT — body, optional. Same body routing as POST.
- class oshconnect.csapi4py.con_sys_api.DeleteRequest(*, url, headers=None, auth=None, params=None)[source]¶
Bases:
APIRequestDELETE — query parameters only. HTTP allows a body but the project’s wrapper doesn’t pass one, so we don’t model it here.
- class oshconnect.csapi4py.con_sys_api.ConnectedSystemAPIRequest(*, url=None, body=None, params=None, request_method='GET', headers=None, auth=None)[source]¶
Bases:
BaseModelLegacy single-class request shape used by the fluent
ConnectedSystemsRequestBuilderand the free helper functions inoshconnect.api_helpers. New code inAPIHelperuses the per-verb subclasses above.- Parameters:
- class oshconnect.csapi4py.con_sys_api.ConnectedSystemsRequestBuilder(*, api_request=<factory>, base_url=None, endpoint=<factory>)[source]¶
Bases:
BaseModel- Parameters:
api_request (ConnectedSystemAPIRequest)
base_url (HttpUrl)
endpoint (Endpoint)
- api_request: ConnectedSystemAPIRequest¶
- endpoint: Endpoint¶
- build_url_from_base()[source]¶
Builds the full API endpoint URL from the base URL and the endpoint parameters that have been previously provided.
- with_api_root(api_root)[source]¶
Optional: Set the API root for the request. This is useful if you want to use a different API root than the default one (api). :param api_root: :return:
- Parameters:
api_root (str)
- with_basic_auth(auth)[source]¶
Set HTTP Basic Auth credentials as a (username, password) tuple. When
authisNone, leaves any previously set credentials untouched — no-ops cleanly so callers can pass an optional auth value through the fluent chain without anifbranch.- Parameters:
auth (tuple | None)
API Helper¶
- oshconnect.csapi4py.default_api_helpers.determine_parent_type(res_type)[source]¶
- Parameters:
res_type (APIResourceTypes)
- oshconnect.csapi4py.default_api_helpers.resource_type_to_endpoint(res_type, parent_type=None)[source]¶
- Parameters:
res_type (APIResourceTypes)
parent_type (APIResourceTypes)
- class oshconnect.csapi4py.default_api_helpers.APIHelper(server_url: 'str' = None, port: 'int' = None, protocol: 'str' = 'https', server_root: 'str' = 'sensorhub', api_root: 'str' = 'api', mqtt_topic_root: 'str' = None, username: 'str' = None, password: 'str' = None, user_auth: 'bool' = False, legacy_topics: 'bool' = False)[source]¶
Bases:
ABC- Parameters:
- get_mqtt_root()[source]¶
Returns the root path segment used when building MQTT topic strings. Defaults to
api_rootwhenmqtt_topic_roothas not been set explicitly, so existing callers that only configureapi_rootare unaffected.- Return type:
- create_resource(res_type, json_data, parent_res_id=None, from_collection=False, url_endpoint=None, req_headers=None)[source]¶
Creates a resource of the given type with the given data, will attempt to create a sub-resource if parent_res_id is provided. :param req_headers: :param res_type: :param json_data: :param parent_res_id: :param from_collection: :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. :return:
- Parameters:
res_type (APIResourceTypes)
json_data (any)
parent_res_id (str)
from_collection (bool)
url_endpoint (str)
req_headers (dict)
- retrieve_resource(res_type, res_id=None, parent_res_id=None, from_collection=False, collection_id=None, url_endpoint=None, req_headers=None)[source]¶
Retrieves a resource or list of resources if no res_id is provided, will attempt to retrieve a sub-resource if parent_res_id is provided. :param req_headers: :param res_type: :param res_id: :param parent_res_id: :param from_collection: :param collection_id: :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. :return:
- get_resource(resource_type, resource_id=None, subresource_type=None, req_headers=None, params=None)[source]¶
Helper to get resources by type, specifically by id, and optionally a sub-resource collection of a specified resource. :param resource_type: :param resource_id: :param subresource_type: :param req_headers: :param params: Optional query-string parameters (e.g.,
{"obsFormat": "logical"}for schema variants). :return:- Parameters:
resource_type (APIResourceTypes)
resource_id (str)
subresource_type (APIResourceTypes)
req_headers (dict)
params (dict)
- update_resource(res_type, res_id, json_data, parent_res_id=None, from_collection=False, url_endpoint=None, req_headers=None)[source]¶
Updates a resource of the given type by its id, if necessary, will attempt to update a sub-resource if parent_res_id is provided. :param req_headers: :param res_type: :param res_id: :param json_data: :param parent_res_id: :param from_collection: :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. :return:
- delete_resource(res_type, res_id, parent_res_id=None, from_collection=False, url_endpoint=None, req_headers=None)[source]¶
Deletes a resource of the given type by its id, if necessary, will attempt to delete a sub-resource if parent_res_id is provided. :param req_headers: :param res_type: :param res_id: :param parent_res_id: :param from_collection: :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. :return:
- resource_url_resolver(subresource_type, subresource_id=None, resource_id=None, from_collection=False)[source]¶
Helper to generate a URL endpoint for a given resource type and id by matching the resource type to an appropriate parent endpoint and inserting the resource ids as necessary. :param subresource_type: :param subresource_id: :param resource_id: :param from_collection: :return:
- Parameters:
subresource_type (APIResourceTypes)
subresource_id (str)
resource_id (str)
from_collection (bool)
- construct_url(resource_type, subresource_id, subresource_type, resource_id, for_socket=False)[source]¶
Constructs an API endpoint url from the given parameters :param resource_type: :param subresource_id: :param subresource_type: :param resource_id: :param for_socket: If true, will construct a WebSocket URL (ws:// or wss://) instead of HTTP/HTTPS. :return:
- Parameters:
resource_type (APIResourceTypes)
for_socket (bool)
- get_api_root_url(socket=False)[source]¶
Returns the full API root URL including protocol, server address, port (if applicable), and API root path. :param socket: If true, will return a WebSocket URL (ws:// or wss://) instead of HTTP/HTTPS. :return:
- Parameters:
socket (bool)
- get_mqtt_topic(resource_type, subresource_type, resource_id, subresource_id=None, data_topic=True, format=None, legacy=None)[source]¶
Returns the MQTT topic for the resource type, does not check for validity of the resource type combination :param resource_type: The API resource type of the resource that comes first in the URL, cannot be None :param subresource_type: The API resource type of the sub-resource that comes second in the URL, optional if there is no sub-resource. :param resource_id: The ID of the primary resource, can be none if the request is being made for all resources of the given type. :param subresource_id: The ID of the sub-resource, can be none if the request is being made for all sub-resources of the given type. :param data_topic: If True (default), appends ‘:data’ to the subresource collection endpoint per CS API Part 3 spec for Resource Data Topics. Set to False for Resource Event Topics (no suffix). :param format: Optional MIME content-type that selects the
:data/<token>format subtopic per CS API Part 3 §Resource Data Messages Content Negotiation.None(default) emits a bare:datatopic so the server’s default format applies. Ignored whendata_topic=False. RaisesValueErrorfor unmapped MIME types — seeoshconnect.csapi4py.mqtt.mqtt_topic_format_token(). :param legacy: Force the pre-Part-3 topic form (leading slash, no:datasuffix, no format subtopic).None(default) uses this helper’slegacy_topicssetting; passTrue/Falseto override per-call. In legacy modedata_topicandformatare ignored. :return:
- class oshconnect.csapi4py.default_api_helpers.ResponseParserHelper(*, default_object_reps: 'DefaultObjectRepresentations')[source]¶
Bases:
object- Parameters:
default_object_reps (DefaultObjectRepresentations)
- default_object_reps: DefaultObjectRepresentations¶
- class oshconnect.csapi4py.default_api_helpers.DefaultObjectRepresentations(*, collections='application/json', deployments='application/geo+json', procedures='application/geo+json', properties='application/sml+json', sampling_features='application/geo+json', systems='application/geo+json', datastreams='application/json', observations='application/json', control_channels='application/json', commands='application/json', system_events='application/om+json', system_history='application/geo+json')[source]¶
Bases:
BaseModelIntended to be used as a way to determine which formats should be used when serializing and deserializing objects. Should work in tandem with planned Serializer/Deserializer classes.
- Parameters:
MQTT Client¶
- oshconnect.csapi4py.mqtt.mqtt_topic_format_token(content_type)[source]¶
Return the hyphen-token for a CS API Part 3
:data/<token>subtopic.- Parameters:
content_type (str) – MIME type string, e.g.
"application/swe+binary".- Raises:
ValueError – if
content_typeis not inMQTT_TOPIC_FORMAT_TOKENS. Callers must register a token for every format they intend to stream — the server raisesInvalidTopicExceptionon unknown subtopic tokens.- Return type:
- class oshconnect.csapi4py.mqtt.MQTTCommClient(url, port=1883, username=None, password=None, path='mqtt', client_id_suffix='', transport='tcp', use_tls=False, reconnect_delay=5)[source]¶
Bases:
object- __init__(url, port=1883, username=None, password=None, path='mqtt', client_id_suffix='', transport='tcp', use_tls=False, reconnect_delay=5)[source]¶
Wraps a paho mqtt client to provide a simple interface for interacting with the mqtt server that is customized for this library.
- Parameters:
url – url of the mqtt server
port – port the mqtt server is communicating over, default is 1883 or whichever port the main node is using if in websocket mode
username – used if node is requiring authentication to access this service
password – used if node is requiring authentication to access this service
path – used for setting the path when using websockets (usually sensorhub/mqtt by default)
transport – ‘tcp’ (default) or ‘websockets’
use_tls – explicitly enable TLS; when False (default), credentials are sent without TLS
reconnect_delay – seconds between automatic reconnect attempts on disconnect (0 disables)
- Raises:
RuntimeError – if the
paho-mqttpackage is not installed (pip install oshconnect[mqtt]).
- subscribe(topic, qos=0, msg_callback=None)[source]¶
Subscribe to a topic, and optionally set a callback for when a message is received on that topic. To actually retrieve any information you must set a callback.
- Parameters:
topic – MQTT topic to subscribe to (example/topic)
qos – quality of service, 0, 1, or 2
msg_callback – callback with the form: callback(client, userdata, msg)
- Returns:
- set_on_connect(on_connect)[source]¶
Set the on_connect callback for the MQTT client.
- Parameters:
on_connect
- Returns:
- set_on_disconnect(on_disconnect)[source]¶
Set the on_disconnect callback for the MQTT client.
- Parameters:
on_disconnect
- Returns:
- set_on_subscribe(on_subscribe)[source]¶
Set the on_subscribe callback for the MQTT client.
- Parameters:
on_subscribe
- Returns:
- set_on_unsubscribe(on_unsubscribe)[source]¶
Set the on_unsubscribe callback for the MQTT client.
- Parameters:
on_unsubscribe
- Returns:
- set_on_publish(on_publish)[source]¶
Set the on_publish callback for the MQTT client.
- Parameters:
on_publish
- Returns:
- set_on_message(on_message)[source]¶
Set the on_message callback for the MQTT client. It is recommended to set individual callbacks for each subscribed topic.
- Parameters:
on_message
- Returns:
- set_on_log(on_log)[source]¶
Set the on_log callback for the MQTT client.
- Parameters:
on_log
- Returns:
NATS Client¶
NATS.io transport for the CS API Part 3 Pub/Sub binding.
NatsCommClient is a drop-in twin of
oshconnect.csapi4py.mqtt.MQTTCommClient: it exposes the same
synchronous connect/start/subscribe/publish/stop
interface (including the paho-style msg_callback(client, userdata, msg)
signature, where msg.topic and msg.payload are read) so that
StreamableResource can drive either
transport without change.
Internally the client owns an asyncio event loop running on a
background thread; the nats-py client is asyncio-native, so each
synchronous method marshals its work onto that loop via
asyncio.run_coroutine_threadsafe(). Callbacks fire on the loop
thread — the same “not the main thread” contract paho already imposes.
Subject conventions. The OSH NATS binding (sensorhub-service-consys-nats)
maps a subject to a REST resource path by stripping the {nodeId} prefix
and the :data suffix and replacing . with / (see
ConSysApiNatsConnector.getResourceUri). Data subjects are therefore the
canonical nested-under-systems resource path, dot-delimited, e.g.:
api.systems.{sysId}.datastreams.{dsId}.observations:data.swe-proto
This differs from the client’s flat MQTT topics — the nesting (and the
parent system id it requires) is built at the resource layer in
StreamableResource.get_nats_subject(). This module only handles the
delimiter mapping (nats_subject_from_topic()) as a safety net for
callers that hand it an MQTT-style topic string.
Only PROACTIVE-mode plain publish/subscribe is implemented (matching the
server’s default dataStreamingMode); the optional _control.*
request/reply flow-control channel and JetStream durable consumers are out
of scope for this transport twin.
- oshconnect.csapi4py.nats.nats_content_type_from_subject(subject)[source]¶
Return the MIME content-type named by a data subject’s format subtopic.
Parses the trailing
:data.<token>of a NATS data subject and maps the token back to its MIME type (e.g.…observations:data.swe-flatbuffers→application/swe+flatbuffers). ReturnsNonefor a bare:datasubject (server-default format), an unknown token, or a subject with no:datasuffix. Used to decode messages received via a format-wildcard subscription, where the concrete format is only known per-message.
- oshconnect.csapi4py.nats.nats_subject_from_topic(topic)[source]¶
Translate an MQTT-style topic into a NATS subject.
NATS uses
.as the token separator,*as the single-token wildcard and>as the multi-token (tail) wildcard, where MQTT uses/,+and#respectively. A subject that is already in NATS form (no/,+or#) passes through unchanged, so this is safe to call on subjects built directly byStreamableResource.get_nats_subject().
- class oshconnect.csapi4py.nats.NatsCommClient(url, port=4222, username=None, password=None, token=None, client_id_suffix='', connect_timeout=5, max_reconnects=-1)[source]¶
Bases:
objectSynchronous, thread-backed NATS client mirroring
MQTTCommClient.- Parameters:
url – NATS server host (or full
nats://host:portURL).port – server port, default
4222(ignored whenurlalready carries a scheme/port).username – optional user for user/password auth.
password – optional password for user/password auth.
token – optional auth token (takes precedence over user/password, matching the Java
ConSysApiNatsServiceprecedence).client_id_suffix – appended to the connection name for traceability.
connect_timeout – seconds to wait for the initial connect.
max_reconnects – reconnect attempts (
-1= unlimited, matching the server default).
- Raises:
RuntimeError – if the
nats-pypackage is not importable.
- connect(keepalive=60)[source]¶
Open the connection to the NATS server (blocks until connected).
keepaliveis accepted for MQTTCommClient signature parity and is unused — nats-py manages ping/pong keepalive internally.
- start()[source]¶
No-op for interface parity.
The background event loop is already running (started in
__init__) and I/O is serviced by nats-py on that loop as soon asconnect()returns; there is no separate network loop to start as there is with paho’sloop_start.
- subscribe(topic, qos=0, msg_callback=None)[source]¶
Subscribe to topic (an MQTT-style or native NATS subject).
- Parameters:
topic – subject to subscribe to; MQTT-style separators/wildcards are translated via
nats_subject_from_topic().qos – accepted for MQTTCommClient parity and ignored (NATS core has no QoS levels).
msg_callback –
callback(client, userdata, msg)invoked on the loop thread for each message, wheremsgexposestopicandpayload. Without it, messages are received but dropped.
Warning
The callback runs on this client’s event-loop thread. Do not call
publish()(or any other blocking method here) from inside it — each of those blocks onrun_coroutine_threadsafewaiting for the same loop, which would deadlock. Hand work off to another thread / the application loop instead (the built-in resource callbacks already do this via the inbound deque).
- publish(topic, payload=None, qos=0, retain=False)[source]¶
Publish payload to topic.
- Parameters:
payload –
bytes(orstr, encoded UTF-8);Nonesends an empty message.qos – accepted for parity and ignored.
retain – accepted for parity and ignored (NATS core has no retained messages).
- set_on_connect(on_connect)[source]¶
Set the connect callback
fn(client, userdata, flags, rc, props).
- set_on_disconnect(on_disconnect)[source]¶
Set the disconnect callback
fn(client, userdata, flag, rc, props).
- set_on_subscribe(on_subscribe)[source]¶
Stored for parity; NATS has no subscribe-acknowledged callback.
- set_on_unsubscribe(on_unsubscribe)[source]¶
Stored for parity; NATS has no unsubscribe-acknowledged callback.