ics-wivi-analytics-ingest 0.1.1__tar.gz → 0.1.3__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.

Files changed (49) hide show
  1. {ics_wivi_analytics_ingest-0.1.1/src/ics_wivi_analytics_ingest.egg-info → ics_wivi_analytics_ingest-0.1.3}/PKG-INFO +111 -15
  2. ics_wivi_analytics_ingest-0.1.3/README.md +327 -0
  3. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/pyproject.toml +2 -2
  4. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/ingest_config_schema.py +1 -3
  5. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3/src/ics_wivi_analytics_ingest.egg-info}/PKG-INFO +111 -15
  6. ics_wivi_analytics_ingest-0.1.1/README.md +0 -231
  7. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/LICENSE +0 -0
  8. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/setup.cfg +0 -0
  9. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/__init__.py +0 -0
  10. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/ingest_client.py +0 -0
  11. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/__init__.py +0 -0
  12. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/__init__.py +0 -0
  13. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/configuration_schema.py +0 -0
  14. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/dtc_schema.py +0 -0
  15. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/gps_schema.py +0 -0
  16. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/message_schema.py +0 -0
  17. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/network_schema.py +0 -0
  18. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/schemas/signal_schema.py +0 -0
  19. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/__init__.py +0 -0
  20. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/batching.py +0 -0
  21. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/configuration.py +0 -0
  22. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/dtc.py +0 -0
  23. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/gps.py +0 -0
  24. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/graphql_executor.py +0 -0
  25. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/message.py +0 -0
  26. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/mutations.py +0 -0
  27. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/network.py +0 -0
  28. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/serialization.py +0 -0
  29. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/analytics_ingest/internal/utils/signal_buffer_manager.py +0 -0
  30. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/__init__.py +0 -0
  31. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/configuration.py +0 -0
  32. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/dtc.py +0 -0
  33. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/gps.py +0 -0
  34. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/init_schema_factory.py +0 -0
  35. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/message.py +0 -0
  36. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/network_stats.py +0 -0
  37. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/factories/signal.py +0 -0
  38. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/ics_wivi_analytics_ingest.egg-info/SOURCES.txt +0 -0
  39. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/ics_wivi_analytics_ingest.egg-info/dependency_links.txt +0 -0
  40. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/ics_wivi_analytics_ingest.egg-info/requires.txt +0 -0
  41. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/src/ics_wivi_analytics_ingest.egg-info/top_level.txt +0 -0
  42. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_add_signal.py +0 -0
  43. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_buffer.py +0 -0
  44. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_client_init.py +0 -0
  45. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_dtc.py +0 -0
  46. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_executer.py +0 -0
  47. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_gps.py +0 -0
  48. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/tests/test_network_stats.py +0 -0
  49. {ics_wivi_analytics_ingest-0.1.1 → ics_wivi_analytics_ingest-0.1.3}/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.1
4
- Summary: - JWT token added in the header.
3
+ Version: 0.1.3
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://your-backend/graphql",
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 | Optional |
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 | Optional |
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.1"
3
+ version = "0.1.3"
4
4
  description = """
5
- - JWT token added in the header.
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
- raise ValueError(
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.1
4
- Summary: - JWT token added in the header.
3
+ Version: 0.1.3
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://your-backend/graphql",
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 | Optional |
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