plexus-python 0.11.3__py3-none-any.whl → 0.11.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
plexus/__init__.py CHANGED
@@ -23,7 +23,7 @@ from plexus.client import (
23
23
  )
24
24
  from plexus.config import RetryConfig
25
25
 
26
- __version__ = "0.11.3"
26
+ __version__ = "0.11.5"
27
27
  __all__ = [
28
28
  "AuthenticationError",
29
29
  "BatchSender",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: plexus
3
- description: Integrate with the Plexus telemetry API — send data, query metrics, subscribe to live streams, send commands to devices. Use when the user mentions Plexus, plexus.company, gateway.plexus.company, plexus-data-api.fly.dev, or plx_ API keys. ALSO USE when the request involves IoT/hardware telemetry, fleet observability, sending sensor data to a backend, querying device time-series, building a fleet dashboard, monitoring drones/satellites/robots/edge devices, or any phrase like "send my sensor readings somewhere", "store telemetry", "track a fleet", "ingest metrics", or "device observability" — even if "Plexus" is never said.
3
+ description: Integrate with the Plexus telemetry API — send data, query metrics, subscribe to live streams. Use when the user mentions Plexus, plexus.company, gateway.plexus.company, plexus-data-api.fly.dev, or plx_ API keys. ALSO USE when the request involves IoT/hardware telemetry, fleet observability, sending sensor data to a backend, querying device time-series, building a fleet dashboard, monitoring drones/satellites/robots/edge devices, or any phrase like "send my sensor readings somewhere", "store telemetry", "track a fleet", "ingest metrics", or "device observability" — even if "Plexus" is never said.
4
4
  tools: Read, Write, Edit, Bash, WebFetch
5
5
  ---
6
6
 
@@ -13,7 +13,7 @@ Plexus is a telemetry/observability platform for hardware fleets (drones, satell
13
13
  Trigger on any of:
14
14
 
15
15
  - The user mentions "Plexus", "plexus.company", `plx_` keys, `gateway.plexus.company`, or `plexus-data-api.fly.dev`
16
- - The user wants to ingest telemetry, query device metrics, stream live points, or send commands to a device
16
+ - The user wants to ingest telemetry, query device metrics, or stream live points
17
17
  - The user is building a dashboard, alert pipeline, or analysis on top of fleet telemetry
18
18
  - The user pastes a Plexus curl example and asks for help
19
19
 
@@ -27,7 +27,7 @@ Two base URLs. Authenticate with an `x-api-key` header on HTTP.
27
27
  | Purpose | Host |
28
28
  | -------------------------------------------------- | -------------------------------- |
29
29
  | Ingest | `https://gateway.plexus.company` |
30
- | Read API (sources, metrics, logs, fleet, commands, live stream) | `https://plexus-data-api.fly.dev` |
30
+ | Read API (sources, metrics, logs, fleet, live stream) | `https://plexus-data-api.fly.dev` |
31
31
 
32
32
  ```
33
33
  x-api-key: plx_...
@@ -141,9 +141,9 @@ You do **not** need to answer application-level pings on this endpoint; keepaliv
141
141
 
142
142
  The gateway's own sockets (`/ws/device`, `/ws/browser`) are for the Python SDK and the Plexus app respectively. Don't write third-party clients against them. There is no `/v1/stream` on the gateway.
143
143
 
144
- ### Control (data API)
144
+ ### Control
145
145
 
146
- `POST /v1/sources/{id}/commands` body `{ command, params? }`, response `{ queued: bool }`. Confirm with the user before sending these hit physical hardware.
146
+ There is no API for sending commands to devices. `POST /v1/sources/{id}/commands` was turned off and returns `410 Gone`. Don't write code that calls it, and don't offer to trigger device behavior through the API.
147
147
 
148
148
  ## Standard scaffolding
149
149
 
@@ -216,7 +216,6 @@ let the pipeline settle first.
216
216
  - **Telemetry frames are batched** — `points` is an array. Handling one frame as one point silently drops data.
217
217
  - `start`/`end` are **ISO date-times on every endpoint** that takes them — `query`, `logs` and `fleet/metrics` alike. `last=1h` is easier and works on all three.
218
218
  - `auto_downsampled: true` in a query response means the bucket size was picked for you — surface it in the UI so users understand what they're looking at.
219
- - Commands queue on the device; they don't execute synchronously. Don't promise the user "it rebooted" — promise "reboot queued".
220
219
 
221
220
  ## When unsure
222
221
 
@@ -61,7 +61,7 @@ Four things the gateway will reject you for. Get these right or nothing lands:
61
61
  1. **The array is `points`.** `"metrics": [...]` returns `400 {"error":"'points' array is required"}`.
62
62
  2. **Every point needs `class`**, either `"metric"` or `"event"`. There is no default.
63
63
  3. **`timestamp` is a number, never a string.** An ISO-8601 string returns `points[i].timestamp must be a number`. Epoch **milliseconds**; a positive value below `1e12` is read as **seconds** and scaled for you, so either unit works as long as it's numeric.
64
- 4. **`source_id` must match `^[a-z0-9][a-z0-9_-]{1,62}$`** and is not deduplicated — two devices declaring the same id merge into one source. This is what SD-card clones do when they all boot as `raspberrypi`.
64
+ 4. **`source_id` must match `^[a-z0-9][a-z0-9._-]*$` (max 256 chars)** and is not deduplicated — two devices declaring the same id merge into one source. This is what SD-card clones do when they all boot as `raspberrypi`.
65
65
 
66
66
  `timestamp` is optional. Omit it and the gateway stamps the point with its receive time — which is the right move on a device whose clock has never been NTP-synced. Per-point `tags` (a flat string→string map) are supported and optional.
67
67
 
plexus/ws.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  WebSocket transport for the Plexus Python SDK.
3
3
 
4
- Wire-compatible with the C SDK (`plexus_ws.c`). Targets the gateway's
4
+ Implements the gateway's device wire protocol. Targets its
5
5
  `/ws/device` endpoint and exchanges the same JSON frames:
6
6
 
7
7
  client → {"type": "device_auth", "api_key": ..., "source_id": ...,
@@ -392,7 +392,7 @@ class WebSocketTransport:
392
392
  command = msg.get("command") or ""
393
393
  params = msg.get("params") or {}
394
394
 
395
- # Ack immediately (matches C SDK: plexus_ws.c:275-280)
395
+ # Ack immediately, per the gateway wire contract
396
396
  self._send_frame({
397
397
  "type": "command_result",
398
398
  "id": cmd_id,
@@ -547,8 +547,7 @@ def _safe_json(raw: Any) -> dict[str, Any]:
547
547
 
548
548
 
549
549
  def _backoff_delay(attempt: int) -> float:
550
- """Exponential backoff with ±25% jitter, capped at BACKOFF_MAX_S.
551
- Matches plexus_ws.c:44-52."""
550
+ """Exponential backoff with ±25% jitter, capped at BACKOFF_MAX_S."""
552
551
  base = min(BACKOFF_BASE_S * (2 ** attempt), BACKOFF_MAX_S)
553
552
  jitter = base * 0.25 * (2 * random.random() - 1)
554
553
  return max(0.1, base + jitter)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: plexus-python
3
- Version: 0.11.3
3
+ Version: 0.11.5
4
4
  Summary: Thin Python SDK for Plexus — send telemetry in one line
5
5
  Project-URL: Homepage, https://plexus.company
6
6
  Project-URL: Documentation, https://docs.plexus.company
@@ -66,7 +66,7 @@ curl -sL https://app.plexus.company/setup | bash -s -- \
66
66
  --key plx_xxx --name drone-01
67
67
  ```
68
68
 
69
- The name must match `^[a-z0-9][a-z0-9_-]{1,62}$`. `setup.sh` refuses to run without `--name` (or without a TTY to prompt for one) — this is deliberate, because the previous `hostname` fallback silently merged telemetry from cloned SD-card images that all booted as `raspberrypi`.
69
+ The name must match `^[a-z0-9][a-z0-9._-]*$` (max 256 chars). `setup.sh` refuses to run without `--name` (or without a TTY to prompt for one) — this is deliberate, because the previous `hostname` fallback silently merged telemetry from cloned SD-card images that all booted as `raspberrypi`.
70
70
 
71
71
  **Names are not auto-deduplicated.** The gateway echoes back whatever `source_id` you declare, unchanged — pick a unique name per device (that's what `--name` and `source_id=...` are for). Two devices that declare the same name write into the same source.
72
72
 
@@ -252,10 +252,10 @@ px.send("temperature", 72.5, timestamp=t) # your timestamp, used as-is, no cor
252
252
 
253
253
  ## Transport
254
254
 
255
- By default the SDK connects over a **WebSocket** to `/ws/device` on the gateway — same wire protocol as the C SDK. This gives you:
255
+ By default the SDK connects over a **WebSocket** to `/ws/device` on the gateway — the gateway's device wire protocol. This gives you:
256
256
 
257
257
  - lower-latency streaming of telemetry,
258
- - live command delivery from the UI / API to the device.
258
+ - the channel that will carry actions triggered from a Plexus dashboard.
259
259
 
260
260
  If the socket is unavailable, sends transparently fall back to `POST /ingest` so no data is lost.
261
261
 
@@ -283,6 +283,8 @@ px.send("temperature", 72.5) # opens the socket, waits for auth
283
283
 
284
284
  The SDK sends an `ack` frame before invoking the handler, then a `result` frame with whatever the handler returns (or an `error` frame if it raises).
285
285
 
286
+ > **Note:** nothing in Plexus can currently trigger a custom handler. The API route for sending commands was turned off on 2026-09-21. Triggering handlers from a dashboard, with permissions and a record of every run, is being rebuilt.
287
+
286
288
  ## Environment Variables
287
289
 
288
290
  | Variable | Description | Default |
@@ -1,19 +1,19 @@
1
- plexus/__init__.py,sha256=CQs5A5m9byvbgba4x0bu0jjqCeav-DGVTxdlygcwNdg,808
1
+ plexus/__init__.py,sha256=m5CEi_FQT7_gW36vrWebsu0F1i8xwvmVu6w6580i8lc,808
2
2
  plexus/_log.py,sha256=3fjXrHFZghQ_17umMcvDUjjTH6aTQB3J4SpVDBiH03w,335
3
3
  plexus/batching.py,sha256=mPMa3m9xK-DCwRmuyL_aqaTltimIOtwoDzz4PfKWyh8,10452
4
4
  plexus/buffer.py,sha256=UNv_jEcrDwbkjJ6uhCehb7uBI2EuFEwO40waDpZn_5I,9579
5
5
  plexus/cli.py,sha256=YFkptze8LRc6mBmDgbsTeU8J6i8MMsdTWvtm3jCINiI,21773
6
6
  plexus/client.py,sha256=H69DR30pj3X8PiURZsViGTDHsIsQ2Kn4muHNECsioKw,53865
7
7
  plexus/config.py,sha256=RuDh5UdVGdVQld5kQlXZO6CVXO4tS0HBalyaoAlXNvc,4416
8
- plexus/ws.py,sha256=2kUCTPkS-tG1XpL9RAzTiytk4Dbck5ypqkbDRSKaTF8,19811
8
+ plexus/ws.py,sha256=xQhJCOizX-V34tF3-r7Zpzs_wnBbNSCeEoZeFFXWH7E,19763
9
9
  plexus/cameras/__init__.py,sha256=AVu1vE1xfYk9lz1cprHlTfi0ieHf84UhQh9Z92E05b8,490
10
10
  plexus/cameras/thermal.py,sha256=-klCEJQG5GlLtELaowWOPYomwMsLK8O5pmmX0PqUrTA,12022
11
11
  plexus/_skills/README.md,sha256=9TNo9mssmBiBPkrYBiA2JJHWOIAEw6DvCWCYAvfzmjM,3243
12
- plexus/_skills/plexus/SKILL.md,sha256=Q1ZYe9YH-gOhMcGYuMG5H9DkHMfQOr3OazCtlxtP9f8,13617
12
+ plexus/_skills/plexus/SKILL.md,sha256=imC6CuWSItyN3j_5YSxfhvMTSxz3Qo5xBN2ewlO4Fdg,13459
13
13
  plexus/_skills/plexus-dashboard/SKILL.md,sha256=8xjdvI3orM31XHTLv1fSAWstCGMwt1HnEbo0SlpTxV4,9508
14
- plexus/_skills/plexus-firmware/SKILL.md,sha256=IkUqNbg5sM5VaZEb189P_aOUkm9_PlSqd4JLH0Nv830,12081
15
- plexus_python-0.11.3.dist-info/METADATA,sha256=9HNLVMyUVehl40sr477LJ1W5_XryDW7RELpbyDysq7k,13517
16
- plexus_python-0.11.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
17
- plexus_python-0.11.3.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
18
- plexus_python-0.11.3.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
19
- plexus_python-0.11.3.dist-info/RECORD,,
14
+ plexus/_skills/plexus-firmware/SKILL.md,sha256=C5tOGu0_LOb76n8US2SLpWSdZdeHQIa4e_5fvkX4DGU,12093
15
+ plexus_python-0.11.5.dist-info/METADATA,sha256=-iTng_ciXZM_KAUTE-9Yb8XfLyFYLRkxmzslRnS7Ve4,13784
16
+ plexus_python-0.11.5.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
17
+ plexus_python-0.11.5.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
18
+ plexus_python-0.11.5.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
19
+ plexus_python-0.11.5.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.32.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any