ics-wivi-analytics-ingest 0.1.1__tar.gz → 0.1.2__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.
Potentially problematic release.
This version of ics-wivi-analytics-ingest might be problematic. Click here for more details.
- {ics_wivi_analytics_ingest-0.1.1/src/ics_wivi_analytics_ingest.egg-info → ics_wivi_analytics_ingest-0.1.2}/PKG-INFO +111 -15
- ics_wivi_analytics_ingest-0.1.2/README.md +327 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/pyproject.toml +2 -2
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/ingest_config_schema.py +1 -3
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2/src/ics_wivi_analytics_ingest.egg-info}/PKG-INFO +111 -15
- ics_wivi_analytics_ingest-0.1.1/README.md +0 -231
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/LICENSE +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/setup.cfg +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/__init__.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/ingest_client.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/__init__.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/__init__.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/configuration_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/dtc_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/gps_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/message_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/network_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/schemas/signal_schema.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/__init__.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/batching.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/configuration.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/dtc.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/gps.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/graphql_executor.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/message.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/mutations.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/network.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/serialization.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/internal/utils/signal_buffer_manager.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/__init__.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/configuration.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/dtc.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/gps.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/init_schema_factory.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/message.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/network_stats.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/signal.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/ics_wivi_analytics_ingest.egg-info/SOURCES.txt +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/ics_wivi_analytics_ingest.egg-info/dependency_links.txt +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/ics_wivi_analytics_ingest.egg-info/requires.txt +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/ics_wivi_analytics_ingest.egg-info/top_level.txt +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_add_signal.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_buffer.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_client_init.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_dtc.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_executer.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_gps.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_network_stats.py +0 -0
- {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_settings.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ics-wivi-analytics-ingest
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: -
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: - README Updated.
|
|
5
5
|
Author-email: Haseeb Saif Ullah <hsaif@intrepidcs.com>, Scott VanDeWater <svandewater@intrepidcs.com>
|
|
6
6
|
License: Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
|
|
7
7
|
|
|
@@ -74,9 +74,19 @@ A lightweight Python library to batch and send automotive telemetry — like sig
|
|
|
74
74
|
```bash
|
|
75
75
|
pip install ics-wivi-analytics-ingest
|
|
76
76
|
```
|
|
77
|
-
|
|
78
77
|
---
|
|
79
78
|
|
|
79
|
+
## 🔑 Setting JWT & Endpoint via Environment Variables
|
|
80
|
+
|
|
81
|
+
You can avoid hardcoding sensitive values like JWT tokens and GraphQL endpoints by using environment variables.
|
|
82
|
+
|
|
83
|
+
### Example (Linux / macOS)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export SEC_AUTH_TOKEN="your-jwt-token-here"
|
|
87
|
+
export GRAPHQL_ENDPOINT="https://0.0.0.0:8092/graphql"
|
|
88
|
+
```
|
|
89
|
+
|
|
80
90
|
## 🚀 Quick Usage
|
|
81
91
|
|
|
82
92
|
```python
|
|
@@ -87,7 +97,8 @@ client = IcsAnalytics(
|
|
|
87
97
|
vehicle_id=456,
|
|
88
98
|
fleet_id=789,
|
|
89
99
|
org_id=1011,
|
|
90
|
-
graphql_endpoint="https://
|
|
100
|
+
graphql_endpoint="https://0.0.0.0:8092/graphql", #default endpoint
|
|
101
|
+
jwt_token="token",
|
|
91
102
|
batch_size=100,
|
|
92
103
|
batch_interval_seconds=10,
|
|
93
104
|
max_signal_count=100
|
|
@@ -128,6 +139,10 @@ client.add_dtc({
|
|
|
128
139
|
'description': 'Head-Up Display - Internal Electronic Failure',
|
|
129
140
|
'status': '2F',
|
|
130
141
|
'time': '2025-07-15T01:42:15.979524'
|
|
142
|
+
'extended':[{'bytes':'3214"31241234123412'} # more bytes
|
|
143
|
+
]
|
|
144
|
+
'snapshot':[{'bytes':'3214"31241234123412'} # more bytes
|
|
145
|
+
]
|
|
131
146
|
}, # more data objects.
|
|
132
147
|
]
|
|
133
148
|
})
|
|
@@ -151,17 +166,6 @@ client.add_gps({
|
|
|
151
166
|
})
|
|
152
167
|
|
|
153
168
|
# Add Network Stats
|
|
154
|
-
client.add_network_stats({
|
|
155
|
-
"name": "CAN1",
|
|
156
|
-
"vehicleId": 456,
|
|
157
|
-
"uploadId": 1,
|
|
158
|
-
"totalMessages": 1000,
|
|
159
|
-
"matchedMessages": 950,
|
|
160
|
-
"unmatchedMessages": 50,
|
|
161
|
-
"errorMessages": 0,
|
|
162
|
-
"longMessageParts": 0,
|
|
163
|
-
"rate": 500.0
|
|
164
|
-
})
|
|
165
169
|
|
|
166
170
|
client.add_network_stats({
|
|
167
171
|
'name': 'jacobs',
|
|
@@ -198,6 +202,98 @@ Set through constructor or environment variables.
|
|
|
198
202
|
| `batch_size` | Max items per batch | 100 |
|
|
199
203
|
| `batch_interval_seconds` | Time-based flush interval | 10 |
|
|
200
204
|
| `max_signal_count` | Max signals before flush | 100 |
|
|
205
|
+
| `jwt_token` | JWT token | '' |
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### 🔧 Payload Reference
|
|
213
|
+
|
|
214
|
+
#### `add_signal` Payload
|
|
215
|
+
|
|
216
|
+
| Key | Description | Required / Optional |
|
|
217
|
+
| ------------- | ---------------------------------- | ------------------- |
|
|
218
|
+
| `name` | Signal name | **Required** |
|
|
219
|
+
| `unit` | Measurement unit (e.g. °C, km/h) | **Required** |
|
|
220
|
+
| `messageName` | Message name in DB | **Required** |
|
|
221
|
+
| `networkName` | Network name | **Required** |
|
|
222
|
+
| `ecuName` | ECU name | Optional |
|
|
223
|
+
| `arbId` | Arbitration ID | Optional |
|
|
224
|
+
| `fileId` | File ID for trace reference | **Required** |
|
|
225
|
+
| `paramType` | Parameter type (`TEXT`, `NUMBER`, `ENCODED`, `RAW`, `STRING`) | Optional |
|
|
226
|
+
| `signalType` | Signal type (`DID`, `PID`, `DMR`, `SIGNAL`)| Optional |
|
|
227
|
+
| `messageDate` | Message timestamp (ISO 8601) | **Required** |
|
|
228
|
+
| `paramId` | Parameter ID (DID identifier) | Optional |
|
|
229
|
+
| `data` | List of data objects | **Required** |
|
|
230
|
+
|
|
231
|
+
**Inside `data`:**
|
|
232
|
+
|
|
233
|
+
| Key | Description | Required / Optional |
|
|
234
|
+
| -------- | ------------------------- | ------------------- |
|
|
235
|
+
| `value` | Numeric value | Optional |
|
|
236
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
237
|
+
| `svalue` | String value (if textual) | Optional |
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
#### `add_dtc` Payload
|
|
242
|
+
|
|
243
|
+
| Key | Description | Required / Optional |
|
|
244
|
+
| ------------- | ---------------------------- | ------------------- |
|
|
245
|
+
| `messageName` | DTC message name | **Required** |
|
|
246
|
+
| `name` | DTC display name | Optional |
|
|
247
|
+
| `networkName` | Network name | **Required** |
|
|
248
|
+
| `ecuName` | ECU name | Optional |
|
|
249
|
+
| `ecuId` | ECU ID | Optional |
|
|
250
|
+
| `messageDate` | Message timestamp (ISO 8601) | Optional |
|
|
251
|
+
| `fileId` | File ID for trace reference | Optional |
|
|
252
|
+
| `data` | List of DTC data objects | **Required** |
|
|
253
|
+
|
|
254
|
+
**Inside `data`:**
|
|
255
|
+
|
|
256
|
+
| Key | Description | Required / Optional |
|
|
257
|
+
| ------------- | -------------------------- | ------------------- |
|
|
258
|
+
| `dtcId` | DTC identifier | **Required** |
|
|
259
|
+
| `description` | Human-readable description | **Required** |
|
|
260
|
+
| `status` | Status code | **Required** |
|
|
261
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
262
|
+
| `extended` | List of bytes's objects | Optional |
|
|
263
|
+
| `snapshot` | List of bytes's objects | Optional |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
#### `add_gps` Payload
|
|
268
|
+
|
|
269
|
+
| Key | Description | Required / Optional |
|
|
270
|
+
| ----------- | ---------------------------------- | ------------------- |
|
|
271
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
272
|
+
| `latitude` | Latitude | Optional |
|
|
273
|
+
| `longitude` | Longitude | Optional |
|
|
274
|
+
| `accuracy` | GPS accuracy (meters) | Optional |
|
|
275
|
+
| `altitude` | Altitude (meters) | Optional |
|
|
276
|
+
| `speed` | Speed (m/s or chosen unit) | Optional |
|
|
277
|
+
| `bearing` | Bearing (degrees) | Optional |
|
|
278
|
+
| `available` | Object describing available fields, all of them are optional | Optional |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
#### `add_network_stats` Payload
|
|
283
|
+
|
|
284
|
+
| Key | Description | Required / Optional |
|
|
285
|
+
| ------------------- | ------------------------ | ------------------- |
|
|
286
|
+
| `name` | Network name | **Required** |
|
|
287
|
+
| `vehicleId` | Vehicle ID | **Required** |
|
|
288
|
+
| `uploadId` | Upload session ID | **Required** |
|
|
289
|
+
| `totalMessages` | Total number of messages | **Required** |
|
|
290
|
+
| `matchedMessages` | Number of matched msgs | **Required** |
|
|
291
|
+
| `unmatchedMessages` | Number of unmatched msgs | **Required** |
|
|
292
|
+
| `errorMessages` | Number of errors | **Required** |
|
|
293
|
+
| `longMessageParts` | Number of long msgs | **Required** |
|
|
294
|
+
| `rate` | Message rate | **Required** |
|
|
295
|
+
| `maxTime` | Max timestamp (ISO 8601) | Optional |
|
|
296
|
+
| `minTime` | Min timestamp (ISO 8601) | Optional |
|
|
201
297
|
|
|
202
298
|
---
|
|
203
299
|
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# 🚗 Analytics Ingest Client
|
|
2
|
+
|
|
3
|
+
A lightweight Python library to batch and send automotive telemetry — like signals, DTCs, GPS, and network stats — to a GraphQL backend, with optional JWT.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🔧 Features
|
|
8
|
+
|
|
9
|
+
* Python 3.11+ support
|
|
10
|
+
* Clean, single-class interface: `IcsAnalytics`
|
|
11
|
+
* In-memory caching for resolved IDs
|
|
12
|
+
* Smart batching (by time, count, or signal limit)
|
|
13
|
+
* Async-safe request queuing (1 request at a time)
|
|
14
|
+
* Minimal dependencies
|
|
15
|
+
* Easy to integrate and test
|
|
16
|
+
* Supports Signals, DTCs, GPS, and Network Stats ingestion
|
|
17
|
+
* JWT (`SEC_AUTH_TOKEN`)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install ics-wivi-analytics-ingest
|
|
25
|
+
```
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🔑 Setting JWT & Endpoint via Environment Variables
|
|
29
|
+
|
|
30
|
+
You can avoid hardcoding sensitive values like JWT tokens and GraphQL endpoints by using environment variables.
|
|
31
|
+
|
|
32
|
+
### Example (Linux / macOS)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
export SEC_AUTH_TOKEN="your-jwt-token-here"
|
|
36
|
+
export GRAPHQL_ENDPOINT="https://0.0.0.0:8092/graphql"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 🚀 Quick Usage
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from analytics_ingest import IcsAnalytics
|
|
43
|
+
|
|
44
|
+
client = IcsAnalytics(
|
|
45
|
+
device_id=123,
|
|
46
|
+
vehicle_id=456,
|
|
47
|
+
fleet_id=789,
|
|
48
|
+
org_id=1011,
|
|
49
|
+
graphql_endpoint="https://0.0.0.0:8092/graphql", #default endpoint
|
|
50
|
+
jwt_token="token",
|
|
51
|
+
batch_size=100,
|
|
52
|
+
batch_interval_seconds=10,
|
|
53
|
+
max_signal_count=100
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Add a signal
|
|
57
|
+
client.add_signal({
|
|
58
|
+
'name': 'VehicleIdentificationNumber',
|
|
59
|
+
'unit': '',
|
|
60
|
+
'messageName': 'BusQuery_IDDecoding_F190_VSSAL',
|
|
61
|
+
'networkName': 'Cluster_6_TestTool',
|
|
62
|
+
'ecuName': '',
|
|
63
|
+
'arbId': '',
|
|
64
|
+
'fileId': '1234',
|
|
65
|
+
'paramType': 'TEXT',
|
|
66
|
+
'signalType': 'DID',
|
|
67
|
+
'messageDate': '2025-07-15T01:40:00.000000',
|
|
68
|
+
'paramId': 'F190',
|
|
69
|
+
'data': [{
|
|
70
|
+
'value': 0.04,
|
|
71
|
+
'time': '1970-01-07T18:28:54Z',
|
|
72
|
+
'svalue':''
|
|
73
|
+
}, # more data objects
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
# Add DTCs
|
|
78
|
+
client.add_dtc({
|
|
79
|
+
'messageName': 'DTC Message99B049',
|
|
80
|
+
'name': 'DTC Message99B049',
|
|
81
|
+
'networkName': 'Cluster_6_TestTool',
|
|
82
|
+
'ecuName': 'VCU_Android_GAS',
|
|
83
|
+
'ecuId': '14DA80F1',
|
|
84
|
+
'messageDate': '2025-07-15T01:42:20.385429',
|
|
85
|
+
'fileId': '1234',
|
|
86
|
+
'data': [{
|
|
87
|
+
'dtcId': 'B19B0-49',
|
|
88
|
+
'description': 'Head-Up Display - Internal Electronic Failure',
|
|
89
|
+
'status': '2F',
|
|
90
|
+
'time': '2025-07-15T01:42:15.979524'
|
|
91
|
+
'extended':[{'bytes':'3214"31241234123412'} # more bytes
|
|
92
|
+
]
|
|
93
|
+
'snapshot':[{'bytes':'3214"31241234123412'} # more bytes
|
|
94
|
+
]
|
|
95
|
+
}, # more data objects.
|
|
96
|
+
]
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
# Add GPS
|
|
100
|
+
client.add_gps({
|
|
101
|
+
"time": "2025-07-28T12:34:56.789Z",
|
|
102
|
+
"latitude": 37.7749,
|
|
103
|
+
"longitude": -122.4194,
|
|
104
|
+
"accuracy": 10.5,
|
|
105
|
+
"altitude": 120.3,
|
|
106
|
+
"speed": 45.2,
|
|
107
|
+
"bearing": 75.0,
|
|
108
|
+
"available": {
|
|
109
|
+
"accuracy": True,
|
|
110
|
+
"altitude": True,
|
|
111
|
+
"bearing": False,
|
|
112
|
+
"speed": True,
|
|
113
|
+
"time": True
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
# Add Network Stats
|
|
118
|
+
|
|
119
|
+
client.add_network_stats({
|
|
120
|
+
'name': 'jacobs',
|
|
121
|
+
'vehicleId': 9539366,
|
|
122
|
+
'uploadId': 4255,
|
|
123
|
+
'totalMessages': 222,
|
|
124
|
+
'matchedMessages': 139,
|
|
125
|
+
'unmatchedMessages': 0,
|
|
126
|
+
'errorMessages': 27,
|
|
127
|
+
'longMessageParts': 21,
|
|
128
|
+
'maxTime': '2025-08-01T11:06:53.947Z',
|
|
129
|
+
'minTime': '2025-08-01T11:06:53.947Z',
|
|
130
|
+
'rate': 59.44
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
# Flush remaining data before exit
|
|
134
|
+
client.flush()
|
|
135
|
+
client.close()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## ⚙️ Config Options
|
|
141
|
+
|
|
142
|
+
Set through constructor or environment variables.
|
|
143
|
+
|
|
144
|
+
| Param | Description | Default |
|
|
145
|
+
| ------------------------ | ------------------------- | ------- |
|
|
146
|
+
| `device_id` | Device ID (required) | – |
|
|
147
|
+
| `vehicle_id` | Vehicle ID (required) | – |
|
|
148
|
+
| `fleet_id` | Fleet ID (required) | – |
|
|
149
|
+
| `org_id` | Org ID (required) | – |
|
|
150
|
+
| `graphql_endpoint` | GraphQL endpoint | – |
|
|
151
|
+
| `batch_size` | Max items per batch | 100 |
|
|
152
|
+
| `batch_interval_seconds` | Time-based flush interval | 10 |
|
|
153
|
+
| `max_signal_count` | Max signals before flush | 100 |
|
|
154
|
+
| `jwt_token` | JWT token | '' |
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### 🔧 Payload Reference
|
|
162
|
+
|
|
163
|
+
#### `add_signal` Payload
|
|
164
|
+
|
|
165
|
+
| Key | Description | Required / Optional |
|
|
166
|
+
| ------------- | ---------------------------------- | ------------------- |
|
|
167
|
+
| `name` | Signal name | **Required** |
|
|
168
|
+
| `unit` | Measurement unit (e.g. °C, km/h) | **Required** |
|
|
169
|
+
| `messageName` | Message name in DB | **Required** |
|
|
170
|
+
| `networkName` | Network name | **Required** |
|
|
171
|
+
| `ecuName` | ECU name | Optional |
|
|
172
|
+
| `arbId` | Arbitration ID | Optional |
|
|
173
|
+
| `fileId` | File ID for trace reference | **Required** |
|
|
174
|
+
| `paramType` | Parameter type (`TEXT`, `NUMBER`, `ENCODED`, `RAW`, `STRING`) | Optional |
|
|
175
|
+
| `signalType` | Signal type (`DID`, `PID`, `DMR`, `SIGNAL`)| Optional |
|
|
176
|
+
| `messageDate` | Message timestamp (ISO 8601) | **Required** |
|
|
177
|
+
| `paramId` | Parameter ID (DID identifier) | Optional |
|
|
178
|
+
| `data` | List of data objects | **Required** |
|
|
179
|
+
|
|
180
|
+
**Inside `data`:**
|
|
181
|
+
|
|
182
|
+
| Key | Description | Required / Optional |
|
|
183
|
+
| -------- | ------------------------- | ------------------- |
|
|
184
|
+
| `value` | Numeric value | Optional |
|
|
185
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
186
|
+
| `svalue` | String value (if textual) | Optional |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
#### `add_dtc` Payload
|
|
191
|
+
|
|
192
|
+
| Key | Description | Required / Optional |
|
|
193
|
+
| ------------- | ---------------------------- | ------------------- |
|
|
194
|
+
| `messageName` | DTC message name | **Required** |
|
|
195
|
+
| `name` | DTC display name | Optional |
|
|
196
|
+
| `networkName` | Network name | **Required** |
|
|
197
|
+
| `ecuName` | ECU name | Optional |
|
|
198
|
+
| `ecuId` | ECU ID | Optional |
|
|
199
|
+
| `messageDate` | Message timestamp (ISO 8601) | Optional |
|
|
200
|
+
| `fileId` | File ID for trace reference | Optional |
|
|
201
|
+
| `data` | List of DTC data objects | **Required** |
|
|
202
|
+
|
|
203
|
+
**Inside `data`:**
|
|
204
|
+
|
|
205
|
+
| Key | Description | Required / Optional |
|
|
206
|
+
| ------------- | -------------------------- | ------------------- |
|
|
207
|
+
| `dtcId` | DTC identifier | **Required** |
|
|
208
|
+
| `description` | Human-readable description | **Required** |
|
|
209
|
+
| `status` | Status code | **Required** |
|
|
210
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
211
|
+
| `extended` | List of bytes's objects | Optional |
|
|
212
|
+
| `snapshot` | List of bytes's objects | Optional |
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
#### `add_gps` Payload
|
|
217
|
+
|
|
218
|
+
| Key | Description | Required / Optional |
|
|
219
|
+
| ----------- | ---------------------------------- | ------------------- |
|
|
220
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
221
|
+
| `latitude` | Latitude | Optional |
|
|
222
|
+
| `longitude` | Longitude | Optional |
|
|
223
|
+
| `accuracy` | GPS accuracy (meters) | Optional |
|
|
224
|
+
| `altitude` | Altitude (meters) | Optional |
|
|
225
|
+
| `speed` | Speed (m/s or chosen unit) | Optional |
|
|
226
|
+
| `bearing` | Bearing (degrees) | Optional |
|
|
227
|
+
| `available` | Object describing available fields, all of them are optional | Optional |
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
#### `add_network_stats` Payload
|
|
232
|
+
|
|
233
|
+
| Key | Description | Required / Optional |
|
|
234
|
+
| ------------------- | ------------------------ | ------------------- |
|
|
235
|
+
| `name` | Network name | **Required** |
|
|
236
|
+
| `vehicleId` | Vehicle ID | **Required** |
|
|
237
|
+
| `uploadId` | Upload session ID | **Required** |
|
|
238
|
+
| `totalMessages` | Total number of messages | **Required** |
|
|
239
|
+
| `matchedMessages` | Number of matched msgs | **Required** |
|
|
240
|
+
| `unmatchedMessages` | Number of unmatched msgs | **Required** |
|
|
241
|
+
| `errorMessages` | Number of errors | **Required** |
|
|
242
|
+
| `longMessageParts` | Number of long msgs | **Required** |
|
|
243
|
+
| `rate` | Message rate | **Required** |
|
|
244
|
+
| `maxTime` | Max timestamp (ISO 8601) | Optional |
|
|
245
|
+
| `minTime` | Min timestamp (ISO 8601) | Optional |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 🛠️ Error Handling & Logging
|
|
250
|
+
|
|
251
|
+
* Raises exceptions for bad input or backend failures
|
|
252
|
+
* Use logging instead of print in production
|
|
253
|
+
* Automatically retries failed batches on next interval
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 🧪 Testing
|
|
258
|
+
|
|
259
|
+
Run all tests:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
PYTHONPATH=src python3 -m unittest discover -s tests -v
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Build and publish:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# change version and description in .toml file
|
|
269
|
+
rm -rf dist/
|
|
270
|
+
python3 -m build
|
|
271
|
+
python -m twine upload dist/*
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 💡 Improvements & Roadmap
|
|
277
|
+
|
|
278
|
+
* Full async API support
|
|
279
|
+
* Runtime config updates
|
|
280
|
+
* More usage examples
|
|
281
|
+
* Metrics & monitoring hooks
|
|
282
|
+
* Linting/type-checking in CI
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 🤝 Contributing
|
|
287
|
+
|
|
288
|
+
We welcome PRs and issues! Please follow PEP8 and include tests with any changes.
|
|
289
|
+
|
|
290
|
+
### One-Time Setup
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
pip install pre-commit
|
|
294
|
+
pre-commit install
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 🏁 Dev Quick Start
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
git clone http://lustra.intrepidcs.corp/ics/wivi/ipa-py-library.git
|
|
303
|
+
cd analytics-ingest
|
|
304
|
+
|
|
305
|
+
# Setup virtual environment
|
|
306
|
+
python3.11 -m venv venv3.11
|
|
307
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
308
|
+
|
|
309
|
+
# Install dependencies
|
|
310
|
+
# Uses pyproject.toml – no requirements.txt
|
|
311
|
+
pip install -e .[dev]
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Test ingestion logic:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
PYTHONPATH=src python3 integeration_test.py
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 📄 License
|
|
324
|
+
|
|
325
|
+
MIT License
|
|
326
|
+
Readme.txt
|
|
327
|
+
4 KB
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ics-wivi-analytics-ingest"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = """
|
|
5
|
-
-
|
|
5
|
+
- README Updated.
|
|
6
6
|
"""
|
|
7
7
|
authors = [{ name = "Haseeb Saif Ullah", email = "hsaif@intrepidcs.com" }, { name = "Scott VanDeWater", email = "svandewater@intrepidcs.com" }]
|
|
8
8
|
readme = "README.md"
|
|
@@ -24,7 +24,5 @@ class IngestConfigSchema(BaseModel):
|
|
|
24
24
|
@model_validator(mode="after")
|
|
25
25
|
def validate_env_or_param(self):
|
|
26
26
|
if not self.graphql_endpoint:
|
|
27
|
-
|
|
28
|
-
"Missing GraphQL endpoint. Set via param or GRAPH_ENDPOINT env."
|
|
29
|
-
)
|
|
27
|
+
self.graphql_endpoint = "https://0.0.0.0:8092/graphql"
|
|
30
28
|
return self
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ics-wivi-analytics-ingest
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: -
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: - README Updated.
|
|
5
5
|
Author-email: Haseeb Saif Ullah <hsaif@intrepidcs.com>, Scott VanDeWater <svandewater@intrepidcs.com>
|
|
6
6
|
License: Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
|
|
7
7
|
|
|
@@ -74,9 +74,19 @@ A lightweight Python library to batch and send automotive telemetry — like sig
|
|
|
74
74
|
```bash
|
|
75
75
|
pip install ics-wivi-analytics-ingest
|
|
76
76
|
```
|
|
77
|
-
|
|
78
77
|
---
|
|
79
78
|
|
|
79
|
+
## 🔑 Setting JWT & Endpoint via Environment Variables
|
|
80
|
+
|
|
81
|
+
You can avoid hardcoding sensitive values like JWT tokens and GraphQL endpoints by using environment variables.
|
|
82
|
+
|
|
83
|
+
### Example (Linux / macOS)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export SEC_AUTH_TOKEN="your-jwt-token-here"
|
|
87
|
+
export GRAPHQL_ENDPOINT="https://0.0.0.0:8092/graphql"
|
|
88
|
+
```
|
|
89
|
+
|
|
80
90
|
## 🚀 Quick Usage
|
|
81
91
|
|
|
82
92
|
```python
|
|
@@ -87,7 +97,8 @@ client = IcsAnalytics(
|
|
|
87
97
|
vehicle_id=456,
|
|
88
98
|
fleet_id=789,
|
|
89
99
|
org_id=1011,
|
|
90
|
-
graphql_endpoint="https://
|
|
100
|
+
graphql_endpoint="https://0.0.0.0:8092/graphql", #default endpoint
|
|
101
|
+
jwt_token="token",
|
|
91
102
|
batch_size=100,
|
|
92
103
|
batch_interval_seconds=10,
|
|
93
104
|
max_signal_count=100
|
|
@@ -128,6 +139,10 @@ client.add_dtc({
|
|
|
128
139
|
'description': 'Head-Up Display - Internal Electronic Failure',
|
|
129
140
|
'status': '2F',
|
|
130
141
|
'time': '2025-07-15T01:42:15.979524'
|
|
142
|
+
'extended':[{'bytes':'3214"31241234123412'} # more bytes
|
|
143
|
+
]
|
|
144
|
+
'snapshot':[{'bytes':'3214"31241234123412'} # more bytes
|
|
145
|
+
]
|
|
131
146
|
}, # more data objects.
|
|
132
147
|
]
|
|
133
148
|
})
|
|
@@ -151,17 +166,6 @@ client.add_gps({
|
|
|
151
166
|
})
|
|
152
167
|
|
|
153
168
|
# Add Network Stats
|
|
154
|
-
client.add_network_stats({
|
|
155
|
-
"name": "CAN1",
|
|
156
|
-
"vehicleId": 456,
|
|
157
|
-
"uploadId": 1,
|
|
158
|
-
"totalMessages": 1000,
|
|
159
|
-
"matchedMessages": 950,
|
|
160
|
-
"unmatchedMessages": 50,
|
|
161
|
-
"errorMessages": 0,
|
|
162
|
-
"longMessageParts": 0,
|
|
163
|
-
"rate": 500.0
|
|
164
|
-
})
|
|
165
169
|
|
|
166
170
|
client.add_network_stats({
|
|
167
171
|
'name': 'jacobs',
|
|
@@ -198,6 +202,98 @@ Set through constructor or environment variables.
|
|
|
198
202
|
| `batch_size` | Max items per batch | 100 |
|
|
199
203
|
| `batch_interval_seconds` | Time-based flush interval | 10 |
|
|
200
204
|
| `max_signal_count` | Max signals before flush | 100 |
|
|
205
|
+
| `jwt_token` | JWT token | '' |
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
### 🔧 Payload Reference
|
|
213
|
+
|
|
214
|
+
#### `add_signal` Payload
|
|
215
|
+
|
|
216
|
+
| Key | Description | Required / Optional |
|
|
217
|
+
| ------------- | ---------------------------------- | ------------------- |
|
|
218
|
+
| `name` | Signal name | **Required** |
|
|
219
|
+
| `unit` | Measurement unit (e.g. °C, km/h) | **Required** |
|
|
220
|
+
| `messageName` | Message name in DB | **Required** |
|
|
221
|
+
| `networkName` | Network name | **Required** |
|
|
222
|
+
| `ecuName` | ECU name | Optional |
|
|
223
|
+
| `arbId` | Arbitration ID | Optional |
|
|
224
|
+
| `fileId` | File ID for trace reference | **Required** |
|
|
225
|
+
| `paramType` | Parameter type (`TEXT`, `NUMBER`, `ENCODED`, `RAW`, `STRING`) | Optional |
|
|
226
|
+
| `signalType` | Signal type (`DID`, `PID`, `DMR`, `SIGNAL`)| Optional |
|
|
227
|
+
| `messageDate` | Message timestamp (ISO 8601) | **Required** |
|
|
228
|
+
| `paramId` | Parameter ID (DID identifier) | Optional |
|
|
229
|
+
| `data` | List of data objects | **Required** |
|
|
230
|
+
|
|
231
|
+
**Inside `data`:**
|
|
232
|
+
|
|
233
|
+
| Key | Description | Required / Optional |
|
|
234
|
+
| -------- | ------------------------- | ------------------- |
|
|
235
|
+
| `value` | Numeric value | Optional |
|
|
236
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
237
|
+
| `svalue` | String value (if textual) | Optional |
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
#### `add_dtc` Payload
|
|
242
|
+
|
|
243
|
+
| Key | Description | Required / Optional |
|
|
244
|
+
| ------------- | ---------------------------- | ------------------- |
|
|
245
|
+
| `messageName` | DTC message name | **Required** |
|
|
246
|
+
| `name` | DTC display name | Optional |
|
|
247
|
+
| `networkName` | Network name | **Required** |
|
|
248
|
+
| `ecuName` | ECU name | Optional |
|
|
249
|
+
| `ecuId` | ECU ID | Optional |
|
|
250
|
+
| `messageDate` | Message timestamp (ISO 8601) | Optional |
|
|
251
|
+
| `fileId` | File ID for trace reference | Optional |
|
|
252
|
+
| `data` | List of DTC data objects | **Required** |
|
|
253
|
+
|
|
254
|
+
**Inside `data`:**
|
|
255
|
+
|
|
256
|
+
| Key | Description | Required / Optional |
|
|
257
|
+
| ------------- | -------------------------- | ------------------- |
|
|
258
|
+
| `dtcId` | DTC identifier | **Required** |
|
|
259
|
+
| `description` | Human-readable description | **Required** |
|
|
260
|
+
| `status` | Status code | **Required** |
|
|
261
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
262
|
+
| `extended` | List of bytes's objects | Optional |
|
|
263
|
+
| `snapshot` | List of bytes's objects | Optional |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
#### `add_gps` Payload
|
|
268
|
+
|
|
269
|
+
| Key | Description | Required / Optional |
|
|
270
|
+
| ----------- | ---------------------------------- | ------------------- |
|
|
271
|
+
| `time` | Timestamp (ISO 8601) | **Required** |
|
|
272
|
+
| `latitude` | Latitude | Optional |
|
|
273
|
+
| `longitude` | Longitude | Optional |
|
|
274
|
+
| `accuracy` | GPS accuracy (meters) | Optional |
|
|
275
|
+
| `altitude` | Altitude (meters) | Optional |
|
|
276
|
+
| `speed` | Speed (m/s or chosen unit) | Optional |
|
|
277
|
+
| `bearing` | Bearing (degrees) | Optional |
|
|
278
|
+
| `available` | Object describing available fields, all of them are optional | Optional |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
#### `add_network_stats` Payload
|
|
283
|
+
|
|
284
|
+
| Key | Description | Required / Optional |
|
|
285
|
+
| ------------------- | ------------------------ | ------------------- |
|
|
286
|
+
| `name` | Network name | **Required** |
|
|
287
|
+
| `vehicleId` | Vehicle ID | **Required** |
|
|
288
|
+
| `uploadId` | Upload session ID | **Required** |
|
|
289
|
+
| `totalMessages` | Total number of messages | **Required** |
|
|
290
|
+
| `matchedMessages` | Number of matched msgs | **Required** |
|
|
291
|
+
| `unmatchedMessages` | Number of unmatched msgs | **Required** |
|
|
292
|
+
| `errorMessages` | Number of errors | **Required** |
|
|
293
|
+
| `longMessageParts` | Number of long msgs | **Required** |
|
|
294
|
+
| `rate` | Message rate | **Required** |
|
|
295
|
+
| `maxTime` | Max timestamp (ISO 8601) | Optional |
|
|
296
|
+
| `minTime` | Min timestamp (ISO 8601) | Optional |
|
|
201
297
|
|
|
202
298
|
---
|
|
203
299
|
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
# 🚗 Analytics Ingest Client
|
|
2
|
-
|
|
3
|
-
A lightweight Python library to batch and send automotive telemetry — like signals, DTCs, GPS, and network stats — to a GraphQL backend, with optional JWT.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🔧 Features
|
|
8
|
-
|
|
9
|
-
* Python 3.11+ support
|
|
10
|
-
* Clean, single-class interface: `IcsAnalytics`
|
|
11
|
-
* In-memory caching for resolved IDs
|
|
12
|
-
* Smart batching (by time, count, or signal limit)
|
|
13
|
-
* Async-safe request queuing (1 request at a time)
|
|
14
|
-
* Minimal dependencies
|
|
15
|
-
* Easy to integrate and test
|
|
16
|
-
* Supports Signals, DTCs, GPS, and Network Stats ingestion
|
|
17
|
-
* JWT (`SEC_AUTH_TOKEN`)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 📦 Installation
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
pip install ics-wivi-analytics-ingest
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 🚀 Quick Usage
|
|
30
|
-
|
|
31
|
-
```python
|
|
32
|
-
from analytics_ingest import IcsAnalytics
|
|
33
|
-
|
|
34
|
-
client = IcsAnalytics(
|
|
35
|
-
device_id=123,
|
|
36
|
-
vehicle_id=456,
|
|
37
|
-
fleet_id=789,
|
|
38
|
-
org_id=1011,
|
|
39
|
-
graphql_endpoint="https://your-backend/graphql",
|
|
40
|
-
batch_size=100,
|
|
41
|
-
batch_interval_seconds=10,
|
|
42
|
-
max_signal_count=100
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
# Add a signal
|
|
46
|
-
client.add_signal({
|
|
47
|
-
'name': 'VehicleIdentificationNumber',
|
|
48
|
-
'unit': '',
|
|
49
|
-
'messageName': 'BusQuery_IDDecoding_F190_VSSAL',
|
|
50
|
-
'networkName': 'Cluster_6_TestTool',
|
|
51
|
-
'ecuName': '',
|
|
52
|
-
'arbId': '',
|
|
53
|
-
'fileId': '1234',
|
|
54
|
-
'paramType': 'TEXT',
|
|
55
|
-
'signalType': 'DID',
|
|
56
|
-
'messageDate': '2025-07-15T01:40:00.000000',
|
|
57
|
-
'paramId': 'F190',
|
|
58
|
-
'data': [{
|
|
59
|
-
'value': 0.04,
|
|
60
|
-
'time': '1970-01-07T18:28:54Z',
|
|
61
|
-
'svalue':''
|
|
62
|
-
}, # more data objects
|
|
63
|
-
]
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
# Add DTCs
|
|
67
|
-
client.add_dtc({
|
|
68
|
-
'messageName': 'DTC Message99B049',
|
|
69
|
-
'name': 'DTC Message99B049',
|
|
70
|
-
'networkName': 'Cluster_6_TestTool',
|
|
71
|
-
'ecuName': 'VCU_Android_GAS',
|
|
72
|
-
'ecuId': '14DA80F1',
|
|
73
|
-
'messageDate': '2025-07-15T01:42:20.385429',
|
|
74
|
-
'fileId': '1234',
|
|
75
|
-
'data': [{
|
|
76
|
-
'dtcId': 'B19B0-49',
|
|
77
|
-
'description': 'Head-Up Display - Internal Electronic Failure',
|
|
78
|
-
'status': '2F',
|
|
79
|
-
'time': '2025-07-15T01:42:15.979524'
|
|
80
|
-
}, # more data objects.
|
|
81
|
-
]
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
# Add GPS
|
|
85
|
-
client.add_gps({
|
|
86
|
-
"time": "2025-07-28T12:34:56.789Z",
|
|
87
|
-
"latitude": 37.7749,
|
|
88
|
-
"longitude": -122.4194,
|
|
89
|
-
"accuracy": 10.5,
|
|
90
|
-
"altitude": 120.3,
|
|
91
|
-
"speed": 45.2,
|
|
92
|
-
"bearing": 75.0,
|
|
93
|
-
"available": {
|
|
94
|
-
"accuracy": True,
|
|
95
|
-
"altitude": True,
|
|
96
|
-
"bearing": False,
|
|
97
|
-
"speed": True,
|
|
98
|
-
"time": True
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
# Add Network Stats
|
|
103
|
-
client.add_network_stats({
|
|
104
|
-
"name": "CAN1",
|
|
105
|
-
"vehicleId": 456,
|
|
106
|
-
"uploadId": 1,
|
|
107
|
-
"totalMessages": 1000,
|
|
108
|
-
"matchedMessages": 950,
|
|
109
|
-
"unmatchedMessages": 50,
|
|
110
|
-
"errorMessages": 0,
|
|
111
|
-
"longMessageParts": 0,
|
|
112
|
-
"rate": 500.0
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
client.add_network_stats({
|
|
116
|
-
'name': 'jacobs',
|
|
117
|
-
'vehicleId': 9539366,
|
|
118
|
-
'uploadId': 4255,
|
|
119
|
-
'totalMessages': 222,
|
|
120
|
-
'matchedMessages': 139,
|
|
121
|
-
'unmatchedMessages': 0,
|
|
122
|
-
'errorMessages': 27,
|
|
123
|
-
'longMessageParts': 21,
|
|
124
|
-
'maxTime': '2025-08-01T11:06:53.947Z',
|
|
125
|
-
'minTime': '2025-08-01T11:06:53.947Z',
|
|
126
|
-
'rate': 59.44
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
# Flush remaining data before exit
|
|
130
|
-
client.flush()
|
|
131
|
-
client.close()
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## ⚙️ Config Options
|
|
137
|
-
|
|
138
|
-
Set through constructor or environment variables.
|
|
139
|
-
|
|
140
|
-
| Param | Description | Default |
|
|
141
|
-
| ------------------------ | ------------------------- | ------- |
|
|
142
|
-
| `device_id` | Device ID (required) | – |
|
|
143
|
-
| `vehicle_id` | Vehicle ID (required) | – |
|
|
144
|
-
| `fleet_id` | Fleet ID (required) | – |
|
|
145
|
-
| `org_id` | Org ID (required) | – |
|
|
146
|
-
| `graphql_endpoint` | GraphQL endpoint | – |
|
|
147
|
-
| `batch_size` | Max items per batch | 100 |
|
|
148
|
-
| `batch_interval_seconds` | Time-based flush interval | 10 |
|
|
149
|
-
| `max_signal_count` | Max signals before flush | 100 |
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## 🛠️ Error Handling & Logging
|
|
154
|
-
|
|
155
|
-
* Raises exceptions for bad input or backend failures
|
|
156
|
-
* Use logging instead of print in production
|
|
157
|
-
* Automatically retries failed batches on next interval
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## 🧪 Testing
|
|
162
|
-
|
|
163
|
-
Run all tests:
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
PYTHONPATH=src python3 -m unittest discover -s tests -v
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Build and publish:
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
# change version and description in .toml file
|
|
173
|
-
rm -rf dist/
|
|
174
|
-
python3 -m build
|
|
175
|
-
python -m twine upload dist/*
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## 💡 Improvements & Roadmap
|
|
181
|
-
|
|
182
|
-
* Full async API support
|
|
183
|
-
* Runtime config updates
|
|
184
|
-
* More usage examples
|
|
185
|
-
* Metrics & monitoring hooks
|
|
186
|
-
* Linting/type-checking in CI
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## 🤝 Contributing
|
|
191
|
-
|
|
192
|
-
We welcome PRs and issues! Please follow PEP8 and include tests with any changes.
|
|
193
|
-
|
|
194
|
-
### One-Time Setup
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
pip install pre-commit
|
|
198
|
-
pre-commit install
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## 🏁 Dev Quick Start
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
git clone http://lustra.intrepidcs.corp/ics/wivi/ipa-py-library.git
|
|
207
|
-
cd analytics-ingest
|
|
208
|
-
|
|
209
|
-
# Setup virtual environment
|
|
210
|
-
python3.11 -m venv venv3.11
|
|
211
|
-
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
212
|
-
|
|
213
|
-
# Install dependencies
|
|
214
|
-
# Uses pyproject.toml – no requirements.txt
|
|
215
|
-
pip install -e .[dev]
|
|
216
|
-
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
Test ingestion logic:
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
PYTHONPATH=src python3 integeration_test.py
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
---
|
|
226
|
-
|
|
227
|
-
## 📄 License
|
|
228
|
-
|
|
229
|
-
MIT License
|
|
230
|
-
Readme.txt
|
|
231
|
-
4 KB
|
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/analytics_ingest/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/__init__.py
RENAMED
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/message.py
RENAMED
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/src/factories/network_stats.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_add_signal.py
RENAMED
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_client_init.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.2}/tests/test_network_stats.py
RENAMED
|
File without changes
|
|
File without changes
|