plexus-python 0.1.0__py3-none-any.whl → 0.2.0__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.
Files changed (51) hide show
  1. plexus/__init__.py +4 -22
  2. plexus/client.py +4 -4
  3. plexus/config.py +11 -29
  4. plexus_python-0.2.0.dist-info/METADATA +140 -0
  5. plexus_python-0.2.0.dist-info/RECORD +8 -0
  6. plexus/__main__.py +0 -4
  7. plexus/adapters/__init__.py +0 -122
  8. plexus/adapters/base.py +0 -409
  9. plexus/adapters/ble.py +0 -257
  10. plexus/adapters/can.py +0 -439
  11. plexus/adapters/can_detect.py +0 -174
  12. plexus/adapters/mavlink.py +0 -642
  13. plexus/adapters/mavlink_detect.py +0 -192
  14. plexus/adapters/modbus.py +0 -622
  15. plexus/adapters/mqtt.py +0 -350
  16. plexus/adapters/opcua.py +0 -607
  17. plexus/adapters/registry.py +0 -206
  18. plexus/adapters/serial_adapter.py +0 -547
  19. plexus/cameras/__init__.py +0 -57
  20. plexus/cameras/auto.py +0 -239
  21. plexus/cameras/base.py +0 -189
  22. plexus/cameras/picamera.py +0 -171
  23. plexus/cameras/usb.py +0 -143
  24. plexus/cli.py +0 -783
  25. plexus/connector.py +0 -666
  26. plexus/deps.py +0 -246
  27. plexus/detect.py +0 -1238
  28. plexus/importers/__init__.py +0 -25
  29. plexus/importers/rosbag.py +0 -778
  30. plexus/sensors/__init__.py +0 -118
  31. plexus/sensors/ads1115.py +0 -164
  32. plexus/sensors/adxl345.py +0 -179
  33. plexus/sensors/auto.py +0 -290
  34. plexus/sensors/base.py +0 -412
  35. plexus/sensors/bh1750.py +0 -102
  36. plexus/sensors/bme280.py +0 -241
  37. plexus/sensors/gps.py +0 -317
  38. plexus/sensors/ina219.py +0 -149
  39. plexus/sensors/magnetometer.py +0 -239
  40. plexus/sensors/mpu6050.py +0 -162
  41. plexus/sensors/sht3x.py +0 -139
  42. plexus/sensors/spi_scan.py +0 -164
  43. plexus/sensors/system.py +0 -261
  44. plexus/sensors/vl53l0x.py +0 -109
  45. plexus/streaming.py +0 -743
  46. plexus/tui.py +0 -642
  47. plexus_python-0.1.0.dist-info/METADATA +0 -470
  48. plexus_python-0.1.0.dist-info/RECORD +0 -50
  49. plexus_python-0.1.0.dist-info/entry_points.txt +0 -2
  50. {plexus_python-0.1.0.dist-info → plexus_python-0.2.0.dist-info}/WHEEL +0 -0
  51. {plexus_python-0.1.0.dist-info → plexus_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
plexus/__init__.py CHANGED
@@ -1,31 +1,13 @@
1
1
  """
2
- Plexus Agent - Send sensor data to Plexus in one line of code.
2
+ Plexus thin Python SDK for sending telemetry to the Plexus gateway.
3
3
 
4
- Basic Usage:
5
4
  from plexus import Plexus
6
5
 
7
- px = Plexus()
6
+ px = Plexus(api_key="plx_xxx", source_id="device-001")
8
7
  px.send("temperature", 72.5)
9
-
10
- With Sensors (pip install plexus-python[sensors]):
11
- from plexus import Plexus
12
- from plexus.sensors import SensorHub, MPU6050, BME280
13
-
14
- hub = SensorHub()
15
- hub.add(MPU6050(sample_rate=100))
16
- hub.add(BME280(sample_rate=1))
17
- hub.run(Plexus())
18
-
19
- Auto-Detection:
20
- from plexus import Plexus
21
- from plexus.sensors import auto_sensors
22
-
23
- hub = auto_sensors() # Finds all connected sensors
24
- hub.run(Plexus())
25
8
  """
26
9
 
27
10
  from plexus.client import Plexus
28
- from plexus.config import load_config, save_config
29
11
 
30
- __version__ = "0.1.0"
31
- __all__ = ["Plexus", "load_config", "save_config"]
12
+ __version__ = "0.2.0"
13
+ __all__ = ["Plexus"]
plexus/client.py CHANGED
@@ -49,7 +49,6 @@ from plexus.config import (
49
49
  get_endpoint,
50
50
  get_gateway_url,
51
51
  get_source_id,
52
- require_login,
53
52
  )
54
53
  logger = logging.getLogger(__name__)
55
54
 
@@ -98,10 +97,11 @@ class Plexus:
98
97
  buffer_path: Optional[str] = None,
99
98
  ):
100
99
  self.api_key = api_key or get_api_key()
101
-
102
- # Require login if no API key provided
103
100
  if not self.api_key:
104
- require_login()
101
+ raise ValueError(
102
+ "No API key. Pass api_key=... or set PLEXUS_API_KEY. "
103
+ "Get a key at app.plexus.company/devices."
104
+ )
105
105
 
106
106
  self.endpoint = (endpoint or get_endpoint()).rstrip("/")
107
107
  self.gateway_url = get_gateway_url()
plexus/config.py CHANGED
@@ -50,15 +50,12 @@ CONFIG_FILE = CONFIG_DIR / "config.json"
50
50
 
51
51
  PLEXUS_ENDPOINT = "https://app.plexus.company"
52
52
  PLEXUS_GATEWAY_URL = "https://plexus-gateway.fly.dev"
53
+ PLEXUS_GATEWAY_WS_URL = "wss://plexus-gateway.fly.dev"
53
54
 
54
55
  DEFAULT_CONFIG = {
55
56
  "api_key": None,
56
57
  "source_id": None,
57
- "org_id": None,
58
- "source_name": None,
59
- "endpoint": None,
60
58
  "persistent_buffer": True,
61
- "sensors": None,
62
59
  }
63
60
 
64
61
  def get_config_path() -> Path:
@@ -117,7 +114,7 @@ def get_endpoint() -> str:
117
114
 
118
115
 
119
116
  def get_gateway_url() -> str:
120
- """Get the ingest gateway base URL (POST /ingest, GET /ws/device)."""
117
+ """Get the ingest gateway base URL (POST /ingest)."""
121
118
  env_gateway = os.environ.get("PLEXUS_GATEWAY_URL")
122
119
  if env_gateway:
123
120
  return env_gateway.rstrip("/")
@@ -125,6 +122,15 @@ def get_gateway_url() -> str:
125
122
  return (config.get("gateway_url") or PLEXUS_GATEWAY_URL).rstrip("/")
126
123
 
127
124
 
125
+ def get_gateway_ws_url() -> str:
126
+ """Get the gateway WebSocket base URL (/ws/device)."""
127
+ env_ws = os.environ.get("PLEXUS_GATEWAY_WS_URL")
128
+ if env_ws:
129
+ return env_ws.rstrip("/")
130
+ config = load_config()
131
+ return (config.get("gateway_ws_url") or PLEXUS_GATEWAY_WS_URL).rstrip("/")
132
+
133
+
128
134
  def get_source_id() -> Optional[str]:
129
135
  """Get the source ID, generating one if not set."""
130
136
  config = load_config()
@@ -139,30 +145,6 @@ def get_source_id() -> Optional[str]:
139
145
  return source_id
140
146
 
141
147
 
142
- def get_org_id() -> Optional[str]:
143
- """Get the organization ID from config or environment variable."""
144
- # Environment variable takes precedence
145
- env_org = os.environ.get("PLEXUS_ORG_ID")
146
- if env_org:
147
- return env_org
148
-
149
- config = load_config()
150
- return config.get("org_id")
151
-
152
-
153
- def is_logged_in() -> bool:
154
- """Check if device is authenticated (has API key)."""
155
- return get_api_key() is not None
156
-
157
-
158
- def require_login() -> None:
159
- """Raise an error if not logged in."""
160
- if not is_logged_in():
161
- raise RuntimeError(
162
- "Not logged in. Run 'plexus start' to connect your account."
163
- )
164
-
165
-
166
148
  def get_persistent_buffer() -> bool:
167
149
  """Get persistent buffer setting. Default True (store-and-forward enabled)."""
168
150
  config = load_config()
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: plexus-python
3
+ Version: 0.2.0
4
+ Summary: Thin Python SDK for Plexus — send telemetry in one line
5
+ Project-URL: Homepage, https://plexus.dev
6
+ Project-URL: Documentation, https://docs.plexus.dev
7
+ Project-URL: Repository, https://github.com/plexus-oss/plexus-python
8
+ Project-URL: Issues, https://github.com/plexus-oss/plexus-python/issues
9
+ Author-email: Plexus <hello@plexus.dev>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: fleet,hardware,iot,monitoring,observability,telemetry
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering
24
+ Classifier: Topic :: System :: Hardware
25
+ Requires-Python: >=3.8
26
+ Requires-Dist: requests>=2.28.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest; extra == 'dev'
29
+ Requires-Dist: pytest-cov; extra == 'dev'
30
+ Requires-Dist: ruff; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # plexus-python
34
+
35
+ **Thin Python SDK for [Plexus](https://plexus.company).** Send telemetry to the Plexus gateway in one line. Storage, dashboards, alerts, and fleet management live in the platform — this package just ships your data.
36
+
37
+ [![PyPI](https://img.shields.io/pypi/v/plexus-python)](https://pypi.org/project/plexus-python/)
38
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
39
+
40
+ ## Quick Start
41
+
42
+ ```bash
43
+ pip install plexus-python
44
+ ```
45
+
46
+ ```python
47
+ from plexus import Plexus
48
+
49
+ px = Plexus(api_key="plx_xxx", source_id="device-001")
50
+ px.send("temperature", 72.5)
51
+ ```
52
+
53
+ Get an API key at [app.plexus.company](https://app.plexus.company) → Devices → Add Device.
54
+
55
+ ## Usage
56
+
57
+ ```python
58
+ from plexus import Plexus
59
+
60
+ px = Plexus(source_id="rig-01") # reads PLEXUS_API_KEY from env
61
+
62
+ # Numbers
63
+ px.send("engine.rpm", 3450)
64
+ px.send("coolant.temperature", 82.3, tags={"unit": "C"})
65
+
66
+ # Strings, bools, objects, arrays — all JSON-serializable
67
+ px.send("vehicle.state", "RUNNING")
68
+ px.send("motor.enabled", True)
69
+ px.send("position", {"x": 1.5, "y": 2.3, "z": 0.8})
70
+
71
+ # Batch
72
+ px.send_batch([
73
+ ("temperature", 72.5),
74
+ ("pressure", 1013.25),
75
+ ])
76
+
77
+ # Named run for grouping related data
78
+ with px.run("thermal-cycle-001"):
79
+ while running:
80
+ px.send("temperature", read_temp())
81
+ ```
82
+
83
+ ## Bring Your Own Protocol
84
+
85
+ This package ships no adapters, auto-detection, or daemons — just the client. Use whatever library you'd use anyway and pipe values into `px.send()`.
86
+
87
+ ```python
88
+ # MAVLink (pymavlink)
89
+ for msg in conn:
90
+ if msg.get_type() == "ATTITUDE":
91
+ px.send("attitude.roll", msg.roll)
92
+
93
+ # CAN (python-can)
94
+ for msg in bus:
95
+ px.send(f"can.0x{msg.arbitration_id:x}", int.from_bytes(msg.data, "big"))
96
+
97
+ # MQTT (paho-mqtt)
98
+ def on_message(_c, _u, msg):
99
+ px.send(msg.topic.replace("/", "."), float(msg.payload))
100
+
101
+ # I2C sensor (Adafruit CircuitPython)
102
+ px.send("temperature", bme.temperature)
103
+ ```
104
+
105
+ See [`examples/`](examples/) for runnable versions of each.
106
+
107
+ ## Reliability
108
+
109
+ Every send buffers locally before hitting the network, retries with exponential backoff, and keeps your data safe across outages. Enable SQLite persistence to survive restarts and power loss:
110
+
111
+ ```python
112
+ px = Plexus(persistent_buffer=True)
113
+ ```
114
+
115
+ Point counts and flush:
116
+
117
+ ```python
118
+ px.buffer_size()
119
+ px.flush_buffer()
120
+ ```
121
+
122
+ ## Environment Variables
123
+
124
+ | Variable | Description | Default |
125
+ | ----------------------- | ---------------------------- | -------------------------------- |
126
+ | `PLEXUS_API_KEY` | API key (required) | none |
127
+ | `PLEXUS_GATEWAY_URL` | HTTP ingest URL | `https://plexus-gateway.fly.dev` |
128
+ | `PLEXUS_GATEWAY_WS_URL` | WebSocket URL (unused in SDK, for compatibility) | `wss://plexus-gateway.fly.dev` |
129
+
130
+ ## Architecture
131
+
132
+ ```
133
+ Your code ── px.send() ── HTTP POST /ingest ──> plexus-gateway ──> ClickHouse + Dashboard
134
+ ```
135
+
136
+ One thin path. No agent, no daemon, no adapters. If you want the full HardwareOps platform — dashboards, alerts, RCA, fleet views — that's the web UI at app.plexus.company. This package gets your data there.
137
+
138
+ ## License
139
+
140
+ Apache 2.0
@@ -0,0 +1,8 @@
1
+ plexus/__init__.py,sha256=Kal4qSrpQ6S8-AE7F9UqFkJMvbhTD82kzkO59O-ruEw,282
2
+ plexus/buffer.py,sha256=3ykybqLs7yMXxQWFajAT8nGe3cs_lW8_6Xvn0vQ69dE,9262
3
+ plexus/client.py,sha256=X6gyFYS-CVwcqJt_VzwHuNtsuJhJJzSxH41T7UBv9dE,16212
4
+ plexus/config.py,sha256=RNym2Fon6JOCVi1rXPSRWjPFAdT8DSmokY5JPEljQOc,4450
5
+ plexus_python-0.2.0.dist-info/METADATA,sha256=51nhbClqTy2w07qn--JyzD8wAOnM7OQQhydvYUgswRI,4528
6
+ plexus_python-0.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
7
+ plexus_python-0.2.0.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
8
+ plexus_python-0.2.0.dist-info/RECORD,,
plexus/__main__.py DELETED
@@ -1,4 +0,0 @@
1
- """Allow running plexus as: python3 -m plexus"""
2
- from plexus.cli import main
3
-
4
- main()
@@ -1,122 +0,0 @@
1
- """
2
- Protocol Adapters - Extensible protocol support for Plexus
3
-
4
- This module provides a plugin system for protocol adapters, enabling
5
- Plexus to ingest data from any protocol without modifying core code.
6
-
7
- Built-in adapters:
8
- - MQTTAdapter: Bridge MQTT brokers to Plexus
9
- - CANAdapter: CAN bus with DBC signal decoding
10
- - MAVLinkAdapter: MAVLink for drones and autonomous vehicles
11
- - OPCUAAdapter: OPC-UA client for industrial automation servers
12
- - SerialAdapter: Serial port (USB/UART/RS-232/RS-485) reader
13
-
14
- Usage:
15
- from plexus.adapters import MQTTAdapter, CANAdapter, MAVLinkAdapter, AdapterRegistry
16
-
17
- # Use built-in adapter
18
- adapter = MQTTAdapter(broker="localhost", topic="sensors/#")
19
- adapter.connect()
20
- adapter.run(on_data=my_callback)
21
-
22
- # CAN bus adapter
23
- adapter = CANAdapter(interface="socketcan", channel="can0", dbc_path="vehicle.dbc")
24
- with adapter:
25
- for metric in adapter.poll():
26
- print(f"{metric.name}: {metric.value}")
27
-
28
- # MAVLink adapter
29
- adapter = MAVLinkAdapter(connection_string="udpin:0.0.0.0:14550")
30
- with adapter:
31
- for metric in adapter.poll():
32
- print(f"{metric.name}: {metric.value}")
33
-
34
- # Create custom adapter
35
- from plexus.adapters import ProtocolAdapter, Metric
36
-
37
- class MyProtocolAdapter(ProtocolAdapter):
38
- def connect(self) -> bool:
39
- # Connect to your protocol
40
- return True
41
-
42
- def poll(self) -> "List[Metric]":
43
- # Read data and return metrics
44
- return [Metric("sensor.temp", 72.5)]
45
-
46
- # Register custom adapter
47
- AdapterRegistry.register("my-protocol", MyProtocolAdapter)
48
- """
49
-
50
- from plexus.adapters.base import (
51
- ProtocolAdapter,
52
- Metric,
53
- AdapterConfig,
54
- AdapterState,
55
- AdapterError,
56
- )
57
- from plexus.adapters.registry import AdapterRegistry
58
- from plexus.adapters.mqtt import MQTTAdapter
59
-
60
- # Import CANAdapter (requires optional [can] extra)
61
- try:
62
- from plexus.adapters.can import CANAdapter
63
- _HAS_CAN = True
64
- except ImportError:
65
- CANAdapter = None # type: ignore
66
- _HAS_CAN = False
67
-
68
- # Import ModbusAdapter (requires optional [modbus] extra)
69
- try:
70
- from plexus.adapters.modbus import ModbusAdapter
71
- _HAS_MODBUS = True
72
- except ImportError:
73
- ModbusAdapter = None # type: ignore
74
- _HAS_MODBUS = False
75
-
76
- # Import MAVLinkAdapter (requires optional [mavlink] extra)
77
- try:
78
- from plexus.adapters.mavlink import MAVLinkAdapter
79
- _HAS_MAVLINK = True
80
- except ImportError:
81
- MAVLinkAdapter = None # type: ignore
82
- _HAS_MAVLINK = False
83
-
84
- # Import OPCUAAdapter (requires optional [opcua] extra)
85
- try:
86
- from plexus.adapters.opcua import OPCUAAdapter
87
- _HAS_OPCUA = True
88
- except ImportError:
89
- OPCUAAdapter = None # type: ignore
90
- _HAS_OPCUA = False
91
-
92
- # Import SerialAdapter (requires optional [serial] extra)
93
- try:
94
- from plexus.adapters.serial_adapter import SerialAdapter
95
- _HAS_SERIAL = True
96
- except ImportError:
97
- SerialAdapter = None # type: ignore
98
- _HAS_SERIAL = False
99
-
100
- # Import BLERelayAdapter (requires optional [ble] extra)
101
- try:
102
- from plexus.adapters.ble import BLERelayAdapter
103
- _HAS_BLE = True
104
- except ImportError:
105
- BLERelayAdapter = None # type: ignore
106
- _HAS_BLE = False
107
-
108
- __all__ = [
109
- "ProtocolAdapter",
110
- "Metric",
111
- "AdapterConfig",
112
- "AdapterState",
113
- "AdapterError",
114
- "AdapterRegistry",
115
- "MQTTAdapter",
116
- "CANAdapter",
117
- "ModbusAdapter",
118
- "MAVLinkAdapter",
119
- "OPCUAAdapter",
120
- "SerialAdapter",
121
- "BLERelayAdapter",
122
- ]