edgeconductor 0.1.0__tar.gz
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.
- edgeconductor-0.1.0/PKG-INFO +65 -0
- edgeconductor-0.1.0/README.md +43 -0
- edgeconductor-0.1.0/edgeconductor/__init__.py +4 -0
- edgeconductor-0.1.0/edgeconductor/client.py +197 -0
- edgeconductor-0.1.0/edgeconductor.egg-info/PKG-INFO +65 -0
- edgeconductor-0.1.0/edgeconductor.egg-info/SOURCES.txt +9 -0
- edgeconductor-0.1.0/edgeconductor.egg-info/dependency_links.txt +1 -0
- edgeconductor-0.1.0/edgeconductor.egg-info/top_level.txt +1 -0
- edgeconductor-0.1.0/pyproject.toml +24 -0
- edgeconductor-0.1.0/setup.cfg +4 -0
- edgeconductor-0.1.0/setup.py +18 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edgeconductor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the EdgeConductor IoT Platform
|
|
5
|
+
Home-page: https://github.com/edgeconductor-creator/ec-platform
|
|
6
|
+
Author: EdgeConductor
|
|
7
|
+
Author-email: EdgeConductor <edgeconductor@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://edgeconductor.com
|
|
10
|
+
Project-URL: Repository, https://github.com/edgeconductor-creator/ec-platform
|
|
11
|
+
Project-URL: Documentation, https://edgeconductor.com/developers
|
|
12
|
+
Keywords: iot,mqtt,telemetry,device-management,edge-computing
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Topic :: System :: Hardware
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
|
|
23
|
+
# edgeconductor
|
|
24
|
+
|
|
25
|
+
Official Python SDK for the [EdgeConductor IoT Platform](https://edgeconductor.com).
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install edgeconductor
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from edgeconductor import Client
|
|
37
|
+
|
|
38
|
+
ec = Client(
|
|
39
|
+
api_key = "ec_live_xxxxxxxxxxxx", # from /org/settings → API Keys
|
|
40
|
+
base_url = "https://ec-registry.onrender.com",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Register device
|
|
44
|
+
ec.devices.register(serial_no="MY-001", product_type="EC-CLIMATE-V1")
|
|
45
|
+
|
|
46
|
+
# Push telemetry
|
|
47
|
+
ec.telemetry.push("MY-001", temp=24.5, hum=60, co2=850, bat=4.05)
|
|
48
|
+
|
|
49
|
+
# Get current state
|
|
50
|
+
shadow = ec.devices.get_shadow("MY-001")
|
|
51
|
+
print(shadow) # {"temp": 24.5, "hum": 60, ...}
|
|
52
|
+
|
|
53
|
+
# Create automation rule
|
|
54
|
+
ec.rules.threshold(
|
|
55
|
+
org_id, name="CO₂ Alert",
|
|
56
|
+
field="co2", op=">", value=1000,
|
|
57
|
+
action={"key": "relay", "value": True},
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Links
|
|
62
|
+
|
|
63
|
+
- **Docs:** [edgeconductor.com/developers](https://edgeconductor.com/developers)
|
|
64
|
+
- **API Keys:** Login → /org/settings → API Keys
|
|
65
|
+
- **Support:** edgeconductor@gmail.com
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# edgeconductor
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [EdgeConductor IoT Platform](https://edgeconductor.com).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install edgeconductor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from edgeconductor import Client
|
|
15
|
+
|
|
16
|
+
ec = Client(
|
|
17
|
+
api_key = "ec_live_xxxxxxxxxxxx", # from /org/settings → API Keys
|
|
18
|
+
base_url = "https://ec-registry.onrender.com",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Register device
|
|
22
|
+
ec.devices.register(serial_no="MY-001", product_type="EC-CLIMATE-V1")
|
|
23
|
+
|
|
24
|
+
# Push telemetry
|
|
25
|
+
ec.telemetry.push("MY-001", temp=24.5, hum=60, co2=850, bat=4.05)
|
|
26
|
+
|
|
27
|
+
# Get current state
|
|
28
|
+
shadow = ec.devices.get_shadow("MY-001")
|
|
29
|
+
print(shadow) # {"temp": 24.5, "hum": 60, ...}
|
|
30
|
+
|
|
31
|
+
# Create automation rule
|
|
32
|
+
ec.rules.threshold(
|
|
33
|
+
org_id, name="CO₂ Alert",
|
|
34
|
+
field="co2", op=">", value=1000,
|
|
35
|
+
action={"key": "relay", "value": True},
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Links
|
|
40
|
+
|
|
41
|
+
- **Docs:** [edgeconductor.com/developers](https://edgeconductor.com/developers)
|
|
42
|
+
- **API Keys:** Login → /org/settings → API Keys
|
|
43
|
+
- **Support:** edgeconductor@gmail.com
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EdgeConductor Python SDK
|
|
3
|
+
|
|
4
|
+
Official Python SDK for the EdgeConductor IoT Platform.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from edgeconductor import Client
|
|
8
|
+
|
|
9
|
+
ec = Client(api_key="ec_live_xxxx")
|
|
10
|
+
|
|
11
|
+
ec.devices.register(serial_no="MY-001", product_type="EC-CLIMATE-V1")
|
|
12
|
+
ec.telemetry.push("MY-001", temp=24.5, hum=60, co2=850)
|
|
13
|
+
shadow = ec.devices.get_shadow("MY-001")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import urllib.request
|
|
18
|
+
import urllib.error
|
|
19
|
+
from typing import Optional, List, Dict, Any
|
|
20
|
+
|
|
21
|
+
DEFAULT_BASE_URL = "https://ec-registry.onrender.com"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class EdgeConductorError(Exception):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _BaseAPI:
|
|
29
|
+
def __init__(self, client: "Client"):
|
|
30
|
+
self._c = client
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Client:
|
|
34
|
+
def __init__(self, api_key: str, base_url: str = DEFAULT_BASE_URL):
|
|
35
|
+
if not api_key:
|
|
36
|
+
raise ValueError("EdgeConductor: api_key is required")
|
|
37
|
+
self._api_key = api_key
|
|
38
|
+
self._base_url = base_url.rstrip("/")
|
|
39
|
+
self.devices = DevicesAPI(self)
|
|
40
|
+
self.telemetry = TelemetryAPI(self)
|
|
41
|
+
self.rules = RulesAPI(self)
|
|
42
|
+
self.orgs = OrgsAPI(self)
|
|
43
|
+
self.audit = AuditAPI(self)
|
|
44
|
+
|
|
45
|
+
def _request(self, method: str, path: str, body: Optional[Dict] = None) -> Any:
|
|
46
|
+
url = f"{self._base_url}{path}"
|
|
47
|
+
data = json.dumps(body).encode() if body is not None else None
|
|
48
|
+
req = urllib.request.Request(
|
|
49
|
+
url, data=data, method=method,
|
|
50
|
+
headers={
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
"Authorization": f"Bearer {self._api_key}",
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
try:
|
|
56
|
+
with urllib.request.urlopen(req) as res:
|
|
57
|
+
return json.loads(res.read())
|
|
58
|
+
except urllib.error.HTTPError as e:
|
|
59
|
+
msg = e.read().decode()
|
|
60
|
+
try:
|
|
61
|
+
msg = json.loads(msg).get("error", msg)
|
|
62
|
+
except Exception:
|
|
63
|
+
pass
|
|
64
|
+
raise EdgeConductorError(f"EC API {e.code}: {msg}") from e
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class DevicesAPI(_BaseAPI):
|
|
68
|
+
def register(self, serial_no: str, product_type: str, fw_version: str = "1.0.0") -> Dict:
|
|
69
|
+
"""Register a new device."""
|
|
70
|
+
return self._c._request("POST", "/devices/register", {
|
|
71
|
+
"serial_no": serial_no, "product_type": product_type, "fw_version": fw_version,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
def list(self, org_id: Optional[str] = None, tenant_id: Optional[str] = None) -> List[Dict]:
|
|
75
|
+
"""List devices filtered by org or tenant."""
|
|
76
|
+
params = f"org_id={org_id}" if org_id else f"tenant_id={tenant_id}" if tenant_id else ""
|
|
77
|
+
return self._c._request("GET", f"/devices{'?' + params if params else ''}")
|
|
78
|
+
|
|
79
|
+
def get(self, serial: str) -> Dict:
|
|
80
|
+
"""Get device details + shadow."""
|
|
81
|
+
return self._c._request("GET", f"/devices/{serial}")
|
|
82
|
+
|
|
83
|
+
def get_shadow(self, serial: str) -> Optional[Dict]:
|
|
84
|
+
"""Get device reported state (live sensor values)."""
|
|
85
|
+
return self.get(serial).get("shadow_reported")
|
|
86
|
+
|
|
87
|
+
def push_config(self, serial: str, **config) -> Dict:
|
|
88
|
+
"""Push config to device (updates desired state → MQTT command)."""
|
|
89
|
+
return self._c._request("PATCH", f"/devices/{serial}/shadow/desired", config)
|
|
90
|
+
|
|
91
|
+
def push_ota(self, serial: str, firmware_id: str) -> Dict:
|
|
92
|
+
"""Push OTA firmware update."""
|
|
93
|
+
return self._c._request("POST", f"/devices/{serial}/ota", {"firmware_id": firmware_id})
|
|
94
|
+
|
|
95
|
+
def reboot(self, serial: str) -> Dict:
|
|
96
|
+
"""Remote reboot device."""
|
|
97
|
+
return self._c._request("POST", f"/devices/{serial}/reboot")
|
|
98
|
+
|
|
99
|
+
def assign(self, serial: str, org_id: Optional[str] = None, room_id: Optional[str] = None) -> Dict:
|
|
100
|
+
"""Assign device to org/room."""
|
|
101
|
+
body = {}
|
|
102
|
+
if org_id: body["org_id"] = org_id
|
|
103
|
+
if room_id: body["room_id"] = room_id
|
|
104
|
+
return self._c._request("PATCH", f"/devices/{serial}/assign", body)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TelemetryAPI(_BaseAPI):
|
|
108
|
+
def push(self, serial: str, **payload) -> Dict:
|
|
109
|
+
"""
|
|
110
|
+
Push telemetry from device to cloud.
|
|
111
|
+
|
|
112
|
+
Example:
|
|
113
|
+
ec.telemetry.push("MY-001", temp=24.5, hum=60, co2=850, bat=4.05)
|
|
114
|
+
"""
|
|
115
|
+
return self._c._request("POST", f"/devices/{serial}/telemetry", payload)
|
|
116
|
+
|
|
117
|
+
def history(self, serial: str, hours: int = 1, limit: int = 500) -> List[Dict]:
|
|
118
|
+
"""Get historical telemetry (oldest first)."""
|
|
119
|
+
return self._c._request("GET", f"/devices/{serial}/telemetry?hours={hours}&limit={limit}")
|
|
120
|
+
|
|
121
|
+
def recent(self, serial: str, limit: int = 20) -> List[Dict]:
|
|
122
|
+
"""Get last N telemetry records (newest first)."""
|
|
123
|
+
return self._c._request("GET", f"/devices/{serial}/telemetry?limit={limit}")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class RulesAPI(_BaseAPI):
|
|
127
|
+
def list(self, org_id: str) -> List[Dict]:
|
|
128
|
+
return self._c._request("GET", f"/orgs/{org_id}/rules")
|
|
129
|
+
|
|
130
|
+
def threshold(self, org_id: str, name: str, field: str, op: str, value: float,
|
|
131
|
+
action: Dict, room_id: Optional[str] = None, webhook_url: Optional[str] = None) -> Dict:
|
|
132
|
+
"""
|
|
133
|
+
Create threshold rule.
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
ec.rules.threshold(
|
|
137
|
+
org_id, name="CO2 Alert",
|
|
138
|
+
field="co2", op=">", value=1000,
|
|
139
|
+
action={"key": "relay", "value": True}
|
|
140
|
+
)
|
|
141
|
+
"""
|
|
142
|
+
return self._c._request("POST", f"/orgs/{org_id}/rules", {
|
|
143
|
+
"name": name, "rule_type": "threshold",
|
|
144
|
+
"condition": {"field": field, "op": op, "value": value},
|
|
145
|
+
"action": action,
|
|
146
|
+
"room_id": room_id, "webhook_url": webhook_url,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
def schedule(self, org_id: str, name: str, time: str, days: List[str],
|
|
150
|
+
action: Dict, room_id: Optional[str] = None) -> Dict:
|
|
151
|
+
"""
|
|
152
|
+
Create schedule rule.
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
ec.rules.schedule(
|
|
156
|
+
org_id, name="Morning ON",
|
|
157
|
+
time="09:00", days=["mon","tue","wed","thu","fri"],
|
|
158
|
+
action={"key": "relay", "value": True}
|
|
159
|
+
)
|
|
160
|
+
"""
|
|
161
|
+
return self._c._request("POST", f"/orgs/{org_id}/rules", {
|
|
162
|
+
"name": name, "rule_type": "schedule",
|
|
163
|
+
"schedule_time": time, "schedule_days": days,
|
|
164
|
+
"action": action, "room_id": room_id,
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
def enable(self, rule_id: str) -> Dict:
|
|
168
|
+
return self._c._request("PATCH", f"/rules/{rule_id}", {"enabled": True})
|
|
169
|
+
|
|
170
|
+
def disable(self, rule_id: str) -> Dict:
|
|
171
|
+
return self._c._request("PATCH", f"/rules/{rule_id}", {"enabled": False})
|
|
172
|
+
|
|
173
|
+
def delete(self, rule_id: str) -> Dict:
|
|
174
|
+
return self._c._request("DELETE", f"/rules/{rule_id}")
|
|
175
|
+
|
|
176
|
+
def evaluate(self, org_id: str) -> Dict:
|
|
177
|
+
return self._c._request("POST", f"/orgs/{org_id}/rules/evaluate")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class OrgsAPI(_BaseAPI):
|
|
181
|
+
def get(self, org_id: str) -> Dict:
|
|
182
|
+
return self._c._request("GET", f"/orgs/{org_id}")
|
|
183
|
+
|
|
184
|
+
def list(self) -> List[Dict]:
|
|
185
|
+
return self._c._request("GET", "/orgs")
|
|
186
|
+
|
|
187
|
+
def rooms(self, org_id: str) -> List[Dict]:
|
|
188
|
+
return self._c._request("GET", f"/orgs/{org_id}/rooms")
|
|
189
|
+
|
|
190
|
+
def create_room(self, org_id: str, name: str, floor: str = "", building: str = "") -> Dict:
|
|
191
|
+
return self._c._request("POST", f"/orgs/{org_id}/rooms",
|
|
192
|
+
{"name": name, "floor": floor, "building": building})
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class AuditAPI(_BaseAPI):
|
|
196
|
+
def list(self, org_id: str, limit: int = 50) -> List[Dict]:
|
|
197
|
+
return self._c._request("GET", f"/orgs/{org_id}/audit?limit={limit}")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edgeconductor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the EdgeConductor IoT Platform
|
|
5
|
+
Home-page: https://github.com/edgeconductor-creator/ec-platform
|
|
6
|
+
Author: EdgeConductor
|
|
7
|
+
Author-email: EdgeConductor <edgeconductor@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://edgeconductor.com
|
|
10
|
+
Project-URL: Repository, https://github.com/edgeconductor-creator/ec-platform
|
|
11
|
+
Project-URL: Documentation, https://edgeconductor.com/developers
|
|
12
|
+
Keywords: iot,mqtt,telemetry,device-management,edge-computing
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Topic :: System :: Hardware
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Requires-Python: >=3.8
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
|
|
23
|
+
# edgeconductor
|
|
24
|
+
|
|
25
|
+
Official Python SDK for the [EdgeConductor IoT Platform](https://edgeconductor.com).
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install edgeconductor
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from edgeconductor import Client
|
|
37
|
+
|
|
38
|
+
ec = Client(
|
|
39
|
+
api_key = "ec_live_xxxxxxxxxxxx", # from /org/settings → API Keys
|
|
40
|
+
base_url = "https://ec-registry.onrender.com",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Register device
|
|
44
|
+
ec.devices.register(serial_no="MY-001", product_type="EC-CLIMATE-V1")
|
|
45
|
+
|
|
46
|
+
# Push telemetry
|
|
47
|
+
ec.telemetry.push("MY-001", temp=24.5, hum=60, co2=850, bat=4.05)
|
|
48
|
+
|
|
49
|
+
# Get current state
|
|
50
|
+
shadow = ec.devices.get_shadow("MY-001")
|
|
51
|
+
print(shadow) # {"temp": 24.5, "hum": 60, ...}
|
|
52
|
+
|
|
53
|
+
# Create automation rule
|
|
54
|
+
ec.rules.threshold(
|
|
55
|
+
org_id, name="CO₂ Alert",
|
|
56
|
+
field="co2", op=">", value=1000,
|
|
57
|
+
action={"key": "relay", "value": True},
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Links
|
|
62
|
+
|
|
63
|
+
- **Docs:** [edgeconductor.com/developers](https://edgeconductor.com/developers)
|
|
64
|
+
- **API Keys:** Login → /org/settings → API Keys
|
|
65
|
+
- **Support:** edgeconductor@gmail.com
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
edgeconductor
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "edgeconductor"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Python SDK for the EdgeConductor IoT Platform"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "EdgeConductor", email = "edgeconductor@gmail.com" }]
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
|
+
keywords = ["iot", "mqtt", "telemetry", "device-management", "edge-computing"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Topic :: System :: Hardware",
|
|
18
|
+
"Topic :: Software Development :: Libraries",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://edgeconductor.com"
|
|
23
|
+
Repository = "https://github.com/edgeconductor-creator/ec-platform"
|
|
24
|
+
Documentation = "https://edgeconductor.com/developers"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="edgeconductor",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
description="Official Python SDK for the EdgeConductor IoT Platform",
|
|
7
|
+
author="EdgeConductor",
|
|
8
|
+
author_email="edgeconductor@gmail.com",
|
|
9
|
+
url="https://github.com/edgeconductor-creator/ec-platform",
|
|
10
|
+
packages=find_packages(),
|
|
11
|
+
python_requires=">=3.8",
|
|
12
|
+
classifiers=[
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Topic :: Software Development :: Libraries",
|
|
16
|
+
"Topic :: System :: Hardware",
|
|
17
|
+
],
|
|
18
|
+
)
|