qapu-cli 0.7.1__tar.gz → 0.7.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qapu-cli
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm.
5
5
  Author: OVOO Technology
6
6
  Classifier: Programming Language :: Python :: 3
@@ -48,6 +48,236 @@ Either way installs a `qapu` command (see `pyproject.toml`'s `[project.scripts]`
48
48
 
49
49
  ## Commands
50
50
 
51
+ **Full command reference (100 commands, auto-generated from `main.py`'s docstrings on 2026-09-04 - regenerate the same way if this drifts, don't hand-maintain)**: every command below has `--help` for its full flag list; commands under a resource group (`device`, `variable`, `group`, ...) follow `qapu <group> <command> ...`. The rest of this section gives worked examples and deeper narrative for the commands with more going on (`data`/`trend`/`energy`/`voltage`/`current`/`power`/`ct-check`/`fleet`/`infrastructure`/etc.) - if a command below isn't mentioned again further down, its one-line description here plus `--help` is the whole story, there's nothing more to it.
52
+
53
+ #### Top-level (device-scoped or global)
54
+
55
+ | Command | Description |
56
+ |---|---|
57
+ | `qapu ct-check` | Diagnose CT (current transformer) wiring per phase - reversed polarity vs. wrong phase order - from live PF_R/S/T/AE_R/S/T (GET /hermes/data/{device_id}). |
58
+ | `qapu current` | Current synthesis parameters, grouped (RMS, imbalance, THD, crest factor, fundamental component) (GET /hermes/data/{device_id}). |
59
+ | `qapu data` | Readings per variable for a device - latest value, last N buffered readings (--last), daily min/avg/max (--days), or an explicit --start/--end range (GET /hermes/data/{device_id}). |
60
+ | `qapu energy` | One day's active/reactive energy breakdown per phase (GET /hermes/energy/{device_id}). |
61
+ | `qapu health` | Check CLI/server version, connectivity, and server status (GET /health, no auth required). |
62
+ | `qapu pipeline` | Fleet-wide pipeline throughput for a time window - ingest/data/rule/blockchain packet+event counts (GET /hermes/pipeline/stats). |
63
+ | `qapu power` | Power synthesis parameters, grouped (active/reactive/apparent, imbalance, power factor) (GET /hermes/data/{device_id}). |
64
+ | `qapu timeline` | Get one device's timeline events (GET /hermes/timeline/{device_id}). |
65
+ | `qapu trend` | Trend for one variable on one device: recent readings, daily min/avg/max, or an explicit --start/--end range (GET /hermes/trend/{device_id}/{variable_id}). |
66
+ | `qapu voltage` | Voltage synthesis parameters, grouped (RMS, imbalance, THD, fundamental component) (GET /hermes/data/{device_id}). |
67
+
68
+ #### `device` - device inventory
69
+
70
+ | Command | Description |
71
+ |---|---|
72
+ | `qapu device get` | Get one device's detail (GET /hermes/devices/{device_id}). |
73
+ | `qapu device list` | List every device Qapu knows about (GET /hermes/devices). |
74
+
75
+ #### `variable` - variable catalog
76
+
77
+ | Command | Description |
78
+ |---|---|
79
+ | `qapu variable get` | Get one variable's detail (GET /hermes/variables/{variable_id}). |
80
+ | `qapu variable list` | List the variable catalog (GET /hermes/variables). |
81
+
82
+ #### `group` - device groups
83
+
84
+ | Command | Description |
85
+ |---|---|
86
+ | `qapu group add` | Create a new device group (POST /hermes/groups). |
87
+ | `qapu group assign` | Assign a device to a group (POST /hermes/groups/{group_id}/devices/{device_id}). |
88
+ | `qapu group devices` | List the device IDs assigned to one group (GET /hermes/groups/{group_id}/devices). |
89
+ | `qapu group get` | Get one group's detail (GET /hermes/groups/{group_id}). |
90
+ | `qapu group list` | List device groups (GET /hermes/groups). |
91
+ | `qapu group unassign` | Remove a device's assignment from a group (DELETE /hermes/groups/{group_id}/devices/{device_id}). |
92
+ | `qapu group update` | Update an existing group - only the fields passed are changed (PUT /hermes/groups/{group_id}). |
93
+
94
+ #### `manufacturer` - manufacturer catalog
95
+
96
+ | Command | Description |
97
+ |---|---|
98
+ | `qapu manufacturer add` | Create a new manufacturer (POST /hermes/manufacturers). |
99
+ | `qapu manufacturer delete` | Delete an existing manufacturer (DELETE /hermes/manufacturers/{manufacturer_id}). |
100
+ | `qapu manufacturer get` | Get one manufacturer's detail (GET /hermes/manufacturers/{manufacturer_id}). |
101
+ | `qapu manufacturer list` | List the manufacturer catalog, grouped by category (GET /hermes/manufacturers). |
102
+ | `qapu manufacturer update` | Update an existing manufacturer - only the fields passed are changed (PUT /hermes/manufacturers/{manufacturer_id}). |
103
+
104
+ #### `model` - hardware model catalog
105
+
106
+ | Command | Description |
107
+ |---|---|
108
+ | `qapu model add` | Create a new hardware model, linked to its manufacturer (POST /hermes/models). |
109
+ | `qapu model delete` | Delete an existing hardware model (DELETE /hermes/models/{model_id}). |
110
+ | `qapu model get` | Get one hardware model's detail (GET /hermes/models/{model_id}). |
111
+ | `qapu model list` | List the hardware model catalog, grouped by the same thousands-as-category convention as manufacturers (GET /hermes/models). |
112
+ | `qapu model update` | Update an existing hardware model - only the fields passed are changed (PUT /hermes/models/{model_id}). |
113
+
114
+ #### `modem` - modem inventory
115
+
116
+ | Command | Description |
117
+ |---|---|
118
+ | `qapu modem get` | Get one modem's detail by IMEI (GET /hermes/modems/{imei}). |
119
+ | `qapu modem list` | List the modem inventory (GET /hermes/modems). |
120
+
121
+ #### `sim` - SIM inventory
122
+
123
+ | Command | Description |
124
+ |---|---|
125
+ | `qapu sim get` | Get one SIM's detail by ICCID (GET /hermes/sims/{iccid}). |
126
+ | `qapu sim list` | List the SIM inventory (GET /hermes/sims). |
127
+
128
+ #### `firmware` - firmware catalog
129
+
130
+ | Command | Description |
131
+ |---|---|
132
+ | `qapu firmware get` | Get one firmware version's detail (GET /hermes/firmware/{version}). |
133
+ | `qapu firmware list` | List the firmware catalog (GET /hermes/firmware). |
134
+
135
+ #### `status` - device/modem status catalog
136
+
137
+ | Command | Description |
138
+ |---|---|
139
+ | `qapu status add` | Create a new status (POST /hermes/statuses). |
140
+ | `qapu status delete` | Delete an existing status (DELETE /hermes/statuses/{status_id}). |
141
+ | `qapu status get` | Get one status's detail (GET /hermes/statuses/{status_id}). |
142
+ | `qapu status list` | List the device/modem status catalog, grouped by category (GET /hermes/statuses). |
143
+ | `qapu status update` | Update an existing status - only the fields passed are changed (PUT /hermes/statuses/{status_id}). |
144
+
145
+ #### `equipment-type` - box equipment type catalog
146
+
147
+ | Command | Description |
148
+ |---|---|
149
+ | `qapu equipment-type add` | Create a new equipment type - use before recording box equipment of a kind that doesn't exist in the catalog yet (POST /hermes/equipment_types). |
150
+ | `qapu equipment-type get` | Get one equipment type's detail (GET /hermes/equipment_types/{id}). |
151
+ | `qapu equipment-type list` | List the box equipment type catalog (GET /hermes/equipment_types). |
152
+
153
+ #### `pump-type` - pump type catalog
154
+
155
+ | Command | Description |
156
+ |---|---|
157
+ | `qapu pump-type add` | Create a new pump type - use before recording a pump of a kind that doesn't exist in the catalog yet (POST /hermes/pump_types). |
158
+ | `qapu pump-type delete` | Delete an existing pump type (DELETE /hermes/pump_types/{pump_type_id}). |
159
+ | `qapu pump-type get` | Get one pump type's detail (GET /hermes/pump_types/{id}). |
160
+ | `qapu pump-type list` | List the pump type catalog (GET /hermes/pump_types). |
161
+ | `qapu pump-type update` | Update an existing pump type - only the fields passed are changed (PUT /hermes/pump_types/{pump_type_id}). |
162
+
163
+ #### `infrastructure` - transformer/box/pump/equipment/land plot
164
+
165
+ | Command | Description |
166
+ |---|---|
167
+ | `qapu infrastructure add` | Create standalone infrastructure (transformer/electric box/equipment/pump), or add a land plot to a device's pump. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
168
+ | `qapu infrastructure assign` | Assign a device to control an existing pump, or monitor a transformer directly. Pick exactly one of --pump or --transformer. |
169
+ | `qapu infrastructure delete` | Delete one piece of box equipment (--equipment), or unlink/delete a device's whole infrastructure chain (DELETE /hermes/infrastructure/...). |
170
+ | `qapu infrastructure get` | Get one device's infrastructure - pump/box/transformer/equipment/land plots, or a direct transformer link (GET /hermes/infrastructure/{device_id}). |
171
+ | `qapu infrastructure update` | Update detail fields on a device's infrastructure. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
172
+
173
+ #### `blockchain` - mined block ledger
174
+
175
+ | Command | Description |
176
+ |---|---|
177
+ | `qapu blockchain get` | Get one device's block at a given index, full payload (GET /hermes/blockchain/{device_id}/{index}). |
178
+ | `qapu blockchain list` | List every mined block for a device, genesis to latest (GET /hermes/blockchain/{device_id}). |
179
+ | `qapu blockchain validate` | Validate a device's mined block chain - length, secure/tampered status, and time range (GET /hermes/blockchain/{device_id}/validate). |
180
+
181
+ #### `calibration` - Gain/Offset per variable
182
+
183
+ | Command | Description |
184
+ |---|---|
185
+ | `qapu calibration add` | Create a new calibration row for a device/variable (POST /hermes/calibration). |
186
+ | `qapu calibration delete` | Delete an existing calibration row (DELETE /hermes/calibration/{calibration_id}). |
187
+ | `qapu calibration get` | Get one calibration row's detail (GET /hermes/calibration/detail/{calibration_id}). |
188
+ | `qapu calibration list` | List a device's calibration rows - Gain/Offset per variable (GET /hermes/calibration/{device_id}). |
189
+ | `qapu calibration update` | Update an existing calibration row - only the fields passed are changed (PUT /hermes/calibration/{calibration_id}). |
190
+
191
+ #### `crop-type` - crop type catalog
192
+
193
+ | Command | Description |
194
+ |---|---|
195
+ | `qapu crop-type add` | Create a new crop type - use before recording a land plot growing a crop that doesn't exist in the catalog yet (POST /hermes/crop_types). |
196
+ | `qapu crop-type delete` | Delete an existing crop type (DELETE /hermes/crop_types/{crop_type_id}). |
197
+ | `qapu crop-type get` | Get one crop type's detail (GET /hermes/crop_types/{id}). |
198
+ | `qapu crop-type list` | List the crop type catalog (GET /hermes/crop_types). |
199
+ | `qapu crop-type update` | Update an existing crop type - only the fields passed are changed (PUT /hermes/crop_types/{crop_type_id}). |
200
+
201
+ #### `irrigation-type` - irrigation method catalog
202
+
203
+ | Command | Description |
204
+ |---|---|
205
+ | `qapu irrigation-type add` | Create a new irrigation type - use before recording a land plot using a method that doesn't exist in the catalog yet (POST /hermes/irrigation_types). |
206
+ | `qapu irrigation-type delete` | Delete an existing irrigation type (DELETE /hermes/irrigation_types/{irrigation_type_id}). |
207
+ | `qapu irrigation-type get` | Get one irrigation type's detail (GET /hermes/irrigation_types/{id}). |
208
+ | `qapu irrigation-type list` | List the irrigation type catalog (GET /hermes/irrigation_types). |
209
+ | `qapu irrigation-type update` | Update an existing irrigation type - only the fields passed are changed (PUT /hermes/irrigation_types/{irrigation_type_id}). |
210
+
211
+ #### `setting` - rule thresholds, register, electric box
212
+
213
+ | Command | Description |
214
+ |---|---|
215
+ | `qapu setting get` | Get a device's editable settings - thresholds, register, electric box (GET /hermes/setting/{device_id}). |
216
+ | `qapu setting update` | Update a device's editable settings - only the fields passed are changed (PUT /hermes/setting/{device_id}). |
217
+
218
+ #### `stream` - ingested packet history
219
+
220
+ | Command | Description |
221
+ |---|---|
222
+ | `qapu stream get` | Get one stream row's detail - command name and variable count included (GET /hermes/stream/detail/{stream_id}). |
223
+ | `qapu stream list` | List a device's ingested packet stream history, most recent first (GET /hermes/stream/{device_id}). |
224
+
225
+ #### `synthesis` - derived-metric calculation rules
226
+
227
+ | Command | Description |
228
+ |---|---|
229
+ | `qapu synthesis add` | Create a new synthesis rule (POST /hermes/synthesis). |
230
+ | `qapu synthesis delete` | Delete an existing synthesis rule (DELETE /hermes/synthesis/{rule_id}). |
231
+ | `qapu synthesis get` | Get one synthesis rule's detail (GET /hermes/synthesis/{rule_id}). |
232
+ | `qapu synthesis list` | List derived-metric calculation rules (GET /hermes/synthesis). |
233
+ | `qapu synthesis update` | Update an existing synthesis rule - only the fields passed are changed (PUT /hermes/synthesis/{rule_id}). |
234
+
235
+ #### `user-role` - user role catalog (Admin/User/...)
236
+
237
+ | Command | Description |
238
+ |---|---|
239
+ | `qapu user-role add` | Create a new user role (POST /hermes/user_roles). |
240
+ | `qapu user-role delete` | Delete an existing user role (DELETE /hermes/user_roles/{role_id}). |
241
+ | `qapu user-role get` | Get one user role's detail (GET /hermes/user_roles/{role_id}). |
242
+ | `qapu user-role list` | List the user role catalog, e.g. Admin/User (GET /hermes/user_roles). |
243
+ | `qapu user-role update` | Update an existing user role - only the fields passed are changed (PUT /hermes/user_roles/{role_id}). |
244
+
245
+ #### `irrigation` - irrigation event history
246
+
247
+ | Command | Description |
248
+ |---|---|
249
+ | `qapu irrigation abstract` | Get a device's irrigation summary - last irrigation + 24h/today/30d/month totals (GET /hermes/irrigation/{device_id}/abstract). |
250
+ | `qapu irrigation list` | List a device's irrigation event history - start/end/duration (GET /hermes/irrigation/{device_id}). |
251
+
252
+ #### `project` - project catalog (Cinga, WeatherStat, ...)
253
+
254
+ | Command | Description |
255
+ |---|---|
256
+ | `qapu project add` | Create a new project (POST /hermes/projects). |
257
+ | `qapu project delete` | Delete an existing project (DELETE /hermes/projects/{project_id}). |
258
+ | `qapu project devices` | List every device belonging to one project, full detail (GET /hermes/projects/{project_id}/devices). |
259
+ | `qapu project get` | Get one project's detail (GET /hermes/projects/{project_id}). |
260
+ | `qapu project list` | List the project catalog (GET /hermes/projects). |
261
+ | `qapu project update` | Update an existing project - only the fields passed are changed (PUT /hermes/projects/{project_id}). |
262
+
263
+ #### `fleet` - bulk, multi-device queries
264
+
265
+ | Command | Description |
266
+ |---|---|
267
+ | `qapu fleet data` | Latest reading per variable, across every device in a group or project (GET /hermes/data/fleet). |
268
+
269
+ #### `device-command` - command template catalog (not actuation)
270
+
271
+ | Command | Description |
272
+ |---|---|
273
+ | `qapu device-command add` | Create a new device command template (POST /hermes/device_commands). |
274
+ | `qapu device-command delete` | Delete an existing device command template (DELETE /hermes/device_commands/{command_id}). |
275
+ | `qapu device-command get` | Get one device command template's detail, including its full payload Template (GET /hermes/device_commands/{id}). |
276
+ | `qapu device-command list` | List the device command template catalog (GET /hermes/device_commands). |
277
+ | `qapu device-command update` | Update an existing device command template - only the fields passed are changed (PUT /hermes/device_commands/{command_id}). |
278
+
279
+ ### Worked examples and deeper detail
280
+
51
281
  ```bash
52
282
  qapu --version # print the installed qapu-cli version and exit
53
283
  qapu health # GET /health - no auth, connectivity + CLI/server version + PyPI update check
@@ -130,6 +360,14 @@ Two distinct real installation faults, both diagnosable from `PF_R/S/T` alone (`
130
360
 
131
361
  Both are heuristics, not certainties - flags a phase for physical inspection, doesn't replace it. Detection: baseline = **median** of all three phases' `|PF|` (not "average of the other two" - the first version tried that and broke under a real multi-fault test, since one bad phase polluted the baseline used to judge the *other*, genuinely healthy phases; the median is robust to a single outlier). `deviation = |own |PF|| - baseline|` - `>= 0.15` (`CT_CHECK_DEVIATION_THRESHOLD`) means "FAZ SIRASI ŞÜPHELİ", else a negative sign means "TERS BAĞLI (Polarite)", else "Normal". The 0.15 threshold is a reasonable rule of thumb (a healthy 3-phase load's phases normally track within a few percent of each other), not derived from real fault-case field data - revisit if a real miswiring case doesn't get flagged correctly. Each phase's panel also shows `AE` (cross-referencing the existing rule's own signal) and "son veri: X dk/saat önce" (via the same `_relative_time()` helper used elsewhere). Live-tested against real prod data via deliberately-crafted `PF_R/S/T` packets sent to a disposable test device: healthy (all three ≈0.93-0.94) → all Normal; single reversed-polarity phase → only that phase flagged, others stay Normal; single wrong-phase-order phase → only that phase flagged; **two simultaneous faults** (one reversed + one phase-order, the case that broke the first "average of other two" version) → all three phases correctly classified independently. Device left in a healthy state afterward.
132
362
 
363
+ **`qapu pipeline` (added 2026-09-04)** - fleet-wide pipeline throughput for a time window, per direct request ("son x süre içerisinde ingeste kaç paket gelmiş data ne kadar işlemiş rule ne işlemiş gibi... docker servis özetleri"):
364
+ ```bash
365
+ qapu pipeline # last 60 minutes (default)
366
+ qapu pipeline --minutes 1440 # last 24 hours
367
+ qapu pipeline --json
368
+ ```
369
+ Not device-scoped - a fleet-wide summary across every service in the `ingest -> stream -> calibration -> raw-writer -> synthesis -> ... -> rule` pipeline. Deliberately reads from the real tables each stage actually writes to (`raw_data.stream_time`/`valid_pack` for `hardware`'s ingest, `streams.stream_time` for `data`'s calibration+synthesis completion, `device_timeline.create_time` for `rule`'s observable output, `blockchain.create_time` for mined blocks) rather than any service's own `/health` endpoint - those are point-in-time snapshots (uptime, CPU, last-message-age), not a windowed throughput count. New `common/qapu_common/domain/pipeline.py` (`Pipeline_Stats.get_stats(minutes)`, four plain `SELECT count(*) ... WHERE <time column> >= now() - interval` queries, no caching - these are meant to be live) + `GET /hermes/pipeline/stats` (`services/api/src/routers/hermes.py`, `minutes` query param, 1 to 10080/7 days). **`Rule_Events` deliberately does NOT count rule evaluations** - `rule` evaluates every single stream message 1:1, the same count `Data_Processed` already reports, so repeating it would be redundant; it counts `device_timeline` rows instead, rule's actual observable output (a trigger/reset transition), not every evaluation pass. The CLI prints a bordered summary table plus a soft backlog hint (yellow note, not an error) if `Data_Processed` looks meaningfully behind `Ingest_Valid` (`<80%`) - a sign of consumer lag worth checking, not itself proof of one. Live-tested against real prod DB: `--minutes 60` correctly returned all zeros (no test traffic in the preceding hour at that point in the session), `--minutes 1440` correctly returned real 24h counts, and a fresh real packet sent immediately before a `--minutes 5` check showed up as exactly `+1` across Ingest/Data_Processed/Blockchain_Mined (Rule_Events stayed `0`, correctly - that packet's only variable, `PCB_T`, didn't cross any rule threshold).
370
+
133
371
  `qapu trend` shows a per-variable history plus a simple linear-regression trend line (slope + direction). Three modes, picked by which options you pass:
134
372
  - **Raw readings** (`--last N`, default `N=20`): the measurement cache's rolling buffer - bounded to its own depth (~50 most recent packets), *not* a time window. Good for "what's it doing right now."
135
373
  - **Daily aggregates** (`--days N`): one row per calendar day (min/avg/max/count), from the same cache the `/measurement/{device_id}/history` endpoint reads - this is what actually covers multi-day/month windows, since the raw buffer doesn't go back that far. `--days` wins over `--last` if both are given (and `--start`/`--end` isn't).
@@ -36,6 +36,236 @@ Either way installs a `qapu` command (see `pyproject.toml`'s `[project.scripts]`
36
36
 
37
37
  ## Commands
38
38
 
39
+ **Full command reference (100 commands, auto-generated from `main.py`'s docstrings on 2026-09-04 - regenerate the same way if this drifts, don't hand-maintain)**: every command below has `--help` for its full flag list; commands under a resource group (`device`, `variable`, `group`, ...) follow `qapu <group> <command> ...`. The rest of this section gives worked examples and deeper narrative for the commands with more going on (`data`/`trend`/`energy`/`voltage`/`current`/`power`/`ct-check`/`fleet`/`infrastructure`/etc.) - if a command below isn't mentioned again further down, its one-line description here plus `--help` is the whole story, there's nothing more to it.
40
+
41
+ #### Top-level (device-scoped or global)
42
+
43
+ | Command | Description |
44
+ |---|---|
45
+ | `qapu ct-check` | Diagnose CT (current transformer) wiring per phase - reversed polarity vs. wrong phase order - from live PF_R/S/T/AE_R/S/T (GET /hermes/data/{device_id}). |
46
+ | `qapu current` | Current synthesis parameters, grouped (RMS, imbalance, THD, crest factor, fundamental component) (GET /hermes/data/{device_id}). |
47
+ | `qapu data` | Readings per variable for a device - latest value, last N buffered readings (--last), daily min/avg/max (--days), or an explicit --start/--end range (GET /hermes/data/{device_id}). |
48
+ | `qapu energy` | One day's active/reactive energy breakdown per phase (GET /hermes/energy/{device_id}). |
49
+ | `qapu health` | Check CLI/server version, connectivity, and server status (GET /health, no auth required). |
50
+ | `qapu pipeline` | Fleet-wide pipeline throughput for a time window - ingest/data/rule/blockchain packet+event counts (GET /hermes/pipeline/stats). |
51
+ | `qapu power` | Power synthesis parameters, grouped (active/reactive/apparent, imbalance, power factor) (GET /hermes/data/{device_id}). |
52
+ | `qapu timeline` | Get one device's timeline events (GET /hermes/timeline/{device_id}). |
53
+ | `qapu trend` | Trend for one variable on one device: recent readings, daily min/avg/max, or an explicit --start/--end range (GET /hermes/trend/{device_id}/{variable_id}). |
54
+ | `qapu voltage` | Voltage synthesis parameters, grouped (RMS, imbalance, THD, fundamental component) (GET /hermes/data/{device_id}). |
55
+
56
+ #### `device` - device inventory
57
+
58
+ | Command | Description |
59
+ |---|---|
60
+ | `qapu device get` | Get one device's detail (GET /hermes/devices/{device_id}). |
61
+ | `qapu device list` | List every device Qapu knows about (GET /hermes/devices). |
62
+
63
+ #### `variable` - variable catalog
64
+
65
+ | Command | Description |
66
+ |---|---|
67
+ | `qapu variable get` | Get one variable's detail (GET /hermes/variables/{variable_id}). |
68
+ | `qapu variable list` | List the variable catalog (GET /hermes/variables). |
69
+
70
+ #### `group` - device groups
71
+
72
+ | Command | Description |
73
+ |---|---|
74
+ | `qapu group add` | Create a new device group (POST /hermes/groups). |
75
+ | `qapu group assign` | Assign a device to a group (POST /hermes/groups/{group_id}/devices/{device_id}). |
76
+ | `qapu group devices` | List the device IDs assigned to one group (GET /hermes/groups/{group_id}/devices). |
77
+ | `qapu group get` | Get one group's detail (GET /hermes/groups/{group_id}). |
78
+ | `qapu group list` | List device groups (GET /hermes/groups). |
79
+ | `qapu group unassign` | Remove a device's assignment from a group (DELETE /hermes/groups/{group_id}/devices/{device_id}). |
80
+ | `qapu group update` | Update an existing group - only the fields passed are changed (PUT /hermes/groups/{group_id}). |
81
+
82
+ #### `manufacturer` - manufacturer catalog
83
+
84
+ | Command | Description |
85
+ |---|---|
86
+ | `qapu manufacturer add` | Create a new manufacturer (POST /hermes/manufacturers). |
87
+ | `qapu manufacturer delete` | Delete an existing manufacturer (DELETE /hermes/manufacturers/{manufacturer_id}). |
88
+ | `qapu manufacturer get` | Get one manufacturer's detail (GET /hermes/manufacturers/{manufacturer_id}). |
89
+ | `qapu manufacturer list` | List the manufacturer catalog, grouped by category (GET /hermes/manufacturers). |
90
+ | `qapu manufacturer update` | Update an existing manufacturer - only the fields passed are changed (PUT /hermes/manufacturers/{manufacturer_id}). |
91
+
92
+ #### `model` - hardware model catalog
93
+
94
+ | Command | Description |
95
+ |---|---|
96
+ | `qapu model add` | Create a new hardware model, linked to its manufacturer (POST /hermes/models). |
97
+ | `qapu model delete` | Delete an existing hardware model (DELETE /hermes/models/{model_id}). |
98
+ | `qapu model get` | Get one hardware model's detail (GET /hermes/models/{model_id}). |
99
+ | `qapu model list` | List the hardware model catalog, grouped by the same thousands-as-category convention as manufacturers (GET /hermes/models). |
100
+ | `qapu model update` | Update an existing hardware model - only the fields passed are changed (PUT /hermes/models/{model_id}). |
101
+
102
+ #### `modem` - modem inventory
103
+
104
+ | Command | Description |
105
+ |---|---|
106
+ | `qapu modem get` | Get one modem's detail by IMEI (GET /hermes/modems/{imei}). |
107
+ | `qapu modem list` | List the modem inventory (GET /hermes/modems). |
108
+
109
+ #### `sim` - SIM inventory
110
+
111
+ | Command | Description |
112
+ |---|---|
113
+ | `qapu sim get` | Get one SIM's detail by ICCID (GET /hermes/sims/{iccid}). |
114
+ | `qapu sim list` | List the SIM inventory (GET /hermes/sims). |
115
+
116
+ #### `firmware` - firmware catalog
117
+
118
+ | Command | Description |
119
+ |---|---|
120
+ | `qapu firmware get` | Get one firmware version's detail (GET /hermes/firmware/{version}). |
121
+ | `qapu firmware list` | List the firmware catalog (GET /hermes/firmware). |
122
+
123
+ #### `status` - device/modem status catalog
124
+
125
+ | Command | Description |
126
+ |---|---|
127
+ | `qapu status add` | Create a new status (POST /hermes/statuses). |
128
+ | `qapu status delete` | Delete an existing status (DELETE /hermes/statuses/{status_id}). |
129
+ | `qapu status get` | Get one status's detail (GET /hermes/statuses/{status_id}). |
130
+ | `qapu status list` | List the device/modem status catalog, grouped by category (GET /hermes/statuses). |
131
+ | `qapu status update` | Update an existing status - only the fields passed are changed (PUT /hermes/statuses/{status_id}). |
132
+
133
+ #### `equipment-type` - box equipment type catalog
134
+
135
+ | Command | Description |
136
+ |---|---|
137
+ | `qapu equipment-type add` | Create a new equipment type - use before recording box equipment of a kind that doesn't exist in the catalog yet (POST /hermes/equipment_types). |
138
+ | `qapu equipment-type get` | Get one equipment type's detail (GET /hermes/equipment_types/{id}). |
139
+ | `qapu equipment-type list` | List the box equipment type catalog (GET /hermes/equipment_types). |
140
+
141
+ #### `pump-type` - pump type catalog
142
+
143
+ | Command | Description |
144
+ |---|---|
145
+ | `qapu pump-type add` | Create a new pump type - use before recording a pump of a kind that doesn't exist in the catalog yet (POST /hermes/pump_types). |
146
+ | `qapu pump-type delete` | Delete an existing pump type (DELETE /hermes/pump_types/{pump_type_id}). |
147
+ | `qapu pump-type get` | Get one pump type's detail (GET /hermes/pump_types/{id}). |
148
+ | `qapu pump-type list` | List the pump type catalog (GET /hermes/pump_types). |
149
+ | `qapu pump-type update` | Update an existing pump type - only the fields passed are changed (PUT /hermes/pump_types/{pump_type_id}). |
150
+
151
+ #### `infrastructure` - transformer/box/pump/equipment/land plot
152
+
153
+ | Command | Description |
154
+ |---|---|
155
+ | `qapu infrastructure add` | Create standalone infrastructure (transformer/electric box/equipment/pump), or add a land plot to a device's pump. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
156
+ | `qapu infrastructure assign` | Assign a device to control an existing pump, or monitor a transformer directly. Pick exactly one of --pump or --transformer. |
157
+ | `qapu infrastructure delete` | Delete one piece of box equipment (--equipment), or unlink/delete a device's whole infrastructure chain (DELETE /hermes/infrastructure/...). |
158
+ | `qapu infrastructure get` | Get one device's infrastructure - pump/box/transformer/equipment/land plots, or a direct transformer link (GET /hermes/infrastructure/{device_id}). |
159
+ | `qapu infrastructure update` | Update detail fields on a device's infrastructure. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
160
+
161
+ #### `blockchain` - mined block ledger
162
+
163
+ | Command | Description |
164
+ |---|---|
165
+ | `qapu blockchain get` | Get one device's block at a given index, full payload (GET /hermes/blockchain/{device_id}/{index}). |
166
+ | `qapu blockchain list` | List every mined block for a device, genesis to latest (GET /hermes/blockchain/{device_id}). |
167
+ | `qapu blockchain validate` | Validate a device's mined block chain - length, secure/tampered status, and time range (GET /hermes/blockchain/{device_id}/validate). |
168
+
169
+ #### `calibration` - Gain/Offset per variable
170
+
171
+ | Command | Description |
172
+ |---|---|
173
+ | `qapu calibration add` | Create a new calibration row for a device/variable (POST /hermes/calibration). |
174
+ | `qapu calibration delete` | Delete an existing calibration row (DELETE /hermes/calibration/{calibration_id}). |
175
+ | `qapu calibration get` | Get one calibration row's detail (GET /hermes/calibration/detail/{calibration_id}). |
176
+ | `qapu calibration list` | List a device's calibration rows - Gain/Offset per variable (GET /hermes/calibration/{device_id}). |
177
+ | `qapu calibration update` | Update an existing calibration row - only the fields passed are changed (PUT /hermes/calibration/{calibration_id}). |
178
+
179
+ #### `crop-type` - crop type catalog
180
+
181
+ | Command | Description |
182
+ |---|---|
183
+ | `qapu crop-type add` | Create a new crop type - use before recording a land plot growing a crop that doesn't exist in the catalog yet (POST /hermes/crop_types). |
184
+ | `qapu crop-type delete` | Delete an existing crop type (DELETE /hermes/crop_types/{crop_type_id}). |
185
+ | `qapu crop-type get` | Get one crop type's detail (GET /hermes/crop_types/{id}). |
186
+ | `qapu crop-type list` | List the crop type catalog (GET /hermes/crop_types). |
187
+ | `qapu crop-type update` | Update an existing crop type - only the fields passed are changed (PUT /hermes/crop_types/{crop_type_id}). |
188
+
189
+ #### `irrigation-type` - irrigation method catalog
190
+
191
+ | Command | Description |
192
+ |---|---|
193
+ | `qapu irrigation-type add` | Create a new irrigation type - use before recording a land plot using a method that doesn't exist in the catalog yet (POST /hermes/irrigation_types). |
194
+ | `qapu irrigation-type delete` | Delete an existing irrigation type (DELETE /hermes/irrigation_types/{irrigation_type_id}). |
195
+ | `qapu irrigation-type get` | Get one irrigation type's detail (GET /hermes/irrigation_types/{id}). |
196
+ | `qapu irrigation-type list` | List the irrigation type catalog (GET /hermes/irrigation_types). |
197
+ | `qapu irrigation-type update` | Update an existing irrigation type - only the fields passed are changed (PUT /hermes/irrigation_types/{irrigation_type_id}). |
198
+
199
+ #### `setting` - rule thresholds, register, electric box
200
+
201
+ | Command | Description |
202
+ |---|---|
203
+ | `qapu setting get` | Get a device's editable settings - thresholds, register, electric box (GET /hermes/setting/{device_id}). |
204
+ | `qapu setting update` | Update a device's editable settings - only the fields passed are changed (PUT /hermes/setting/{device_id}). |
205
+
206
+ #### `stream` - ingested packet history
207
+
208
+ | Command | Description |
209
+ |---|---|
210
+ | `qapu stream get` | Get one stream row's detail - command name and variable count included (GET /hermes/stream/detail/{stream_id}). |
211
+ | `qapu stream list` | List a device's ingested packet stream history, most recent first (GET /hermes/stream/{device_id}). |
212
+
213
+ #### `synthesis` - derived-metric calculation rules
214
+
215
+ | Command | Description |
216
+ |---|---|
217
+ | `qapu synthesis add` | Create a new synthesis rule (POST /hermes/synthesis). |
218
+ | `qapu synthesis delete` | Delete an existing synthesis rule (DELETE /hermes/synthesis/{rule_id}). |
219
+ | `qapu synthesis get` | Get one synthesis rule's detail (GET /hermes/synthesis/{rule_id}). |
220
+ | `qapu synthesis list` | List derived-metric calculation rules (GET /hermes/synthesis). |
221
+ | `qapu synthesis update` | Update an existing synthesis rule - only the fields passed are changed (PUT /hermes/synthesis/{rule_id}). |
222
+
223
+ #### `user-role` - user role catalog (Admin/User/...)
224
+
225
+ | Command | Description |
226
+ |---|---|
227
+ | `qapu user-role add` | Create a new user role (POST /hermes/user_roles). |
228
+ | `qapu user-role delete` | Delete an existing user role (DELETE /hermes/user_roles/{role_id}). |
229
+ | `qapu user-role get` | Get one user role's detail (GET /hermes/user_roles/{role_id}). |
230
+ | `qapu user-role list` | List the user role catalog, e.g. Admin/User (GET /hermes/user_roles). |
231
+ | `qapu user-role update` | Update an existing user role - only the fields passed are changed (PUT /hermes/user_roles/{role_id}). |
232
+
233
+ #### `irrigation` - irrigation event history
234
+
235
+ | Command | Description |
236
+ |---|---|
237
+ | `qapu irrigation abstract` | Get a device's irrigation summary - last irrigation + 24h/today/30d/month totals (GET /hermes/irrigation/{device_id}/abstract). |
238
+ | `qapu irrigation list` | List a device's irrigation event history - start/end/duration (GET /hermes/irrigation/{device_id}). |
239
+
240
+ #### `project` - project catalog (Cinga, WeatherStat, ...)
241
+
242
+ | Command | Description |
243
+ |---|---|
244
+ | `qapu project add` | Create a new project (POST /hermes/projects). |
245
+ | `qapu project delete` | Delete an existing project (DELETE /hermes/projects/{project_id}). |
246
+ | `qapu project devices` | List every device belonging to one project, full detail (GET /hermes/projects/{project_id}/devices). |
247
+ | `qapu project get` | Get one project's detail (GET /hermes/projects/{project_id}). |
248
+ | `qapu project list` | List the project catalog (GET /hermes/projects). |
249
+ | `qapu project update` | Update an existing project - only the fields passed are changed (PUT /hermes/projects/{project_id}). |
250
+
251
+ #### `fleet` - bulk, multi-device queries
252
+
253
+ | Command | Description |
254
+ |---|---|
255
+ | `qapu fleet data` | Latest reading per variable, across every device in a group or project (GET /hermes/data/fleet). |
256
+
257
+ #### `device-command` - command template catalog (not actuation)
258
+
259
+ | Command | Description |
260
+ |---|---|
261
+ | `qapu device-command add` | Create a new device command template (POST /hermes/device_commands). |
262
+ | `qapu device-command delete` | Delete an existing device command template (DELETE /hermes/device_commands/{command_id}). |
263
+ | `qapu device-command get` | Get one device command template's detail, including its full payload Template (GET /hermes/device_commands/{id}). |
264
+ | `qapu device-command list` | List the device command template catalog (GET /hermes/device_commands). |
265
+ | `qapu device-command update` | Update an existing device command template - only the fields passed are changed (PUT /hermes/device_commands/{command_id}). |
266
+
267
+ ### Worked examples and deeper detail
268
+
39
269
  ```bash
40
270
  qapu --version # print the installed qapu-cli version and exit
41
271
  qapu health # GET /health - no auth, connectivity + CLI/server version + PyPI update check
@@ -118,6 +348,14 @@ Two distinct real installation faults, both diagnosable from `PF_R/S/T` alone (`
118
348
 
119
349
  Both are heuristics, not certainties - flags a phase for physical inspection, doesn't replace it. Detection: baseline = **median** of all three phases' `|PF|` (not "average of the other two" - the first version tried that and broke under a real multi-fault test, since one bad phase polluted the baseline used to judge the *other*, genuinely healthy phases; the median is robust to a single outlier). `deviation = |own |PF|| - baseline|` - `>= 0.15` (`CT_CHECK_DEVIATION_THRESHOLD`) means "FAZ SIRASI ŞÜPHELİ", else a negative sign means "TERS BAĞLI (Polarite)", else "Normal". The 0.15 threshold is a reasonable rule of thumb (a healthy 3-phase load's phases normally track within a few percent of each other), not derived from real fault-case field data - revisit if a real miswiring case doesn't get flagged correctly. Each phase's panel also shows `AE` (cross-referencing the existing rule's own signal) and "son veri: X dk/saat önce" (via the same `_relative_time()` helper used elsewhere). Live-tested against real prod data via deliberately-crafted `PF_R/S/T` packets sent to a disposable test device: healthy (all three ≈0.93-0.94) → all Normal; single reversed-polarity phase → only that phase flagged, others stay Normal; single wrong-phase-order phase → only that phase flagged; **two simultaneous faults** (one reversed + one phase-order, the case that broke the first "average of other two" version) → all three phases correctly classified independently. Device left in a healthy state afterward.
120
350
 
351
+ **`qapu pipeline` (added 2026-09-04)** - fleet-wide pipeline throughput for a time window, per direct request ("son x süre içerisinde ingeste kaç paket gelmiş data ne kadar işlemiş rule ne işlemiş gibi... docker servis özetleri"):
352
+ ```bash
353
+ qapu pipeline # last 60 minutes (default)
354
+ qapu pipeline --minutes 1440 # last 24 hours
355
+ qapu pipeline --json
356
+ ```
357
+ Not device-scoped - a fleet-wide summary across every service in the `ingest -> stream -> calibration -> raw-writer -> synthesis -> ... -> rule` pipeline. Deliberately reads from the real tables each stage actually writes to (`raw_data.stream_time`/`valid_pack` for `hardware`'s ingest, `streams.stream_time` for `data`'s calibration+synthesis completion, `device_timeline.create_time` for `rule`'s observable output, `blockchain.create_time` for mined blocks) rather than any service's own `/health` endpoint - those are point-in-time snapshots (uptime, CPU, last-message-age), not a windowed throughput count. New `common/qapu_common/domain/pipeline.py` (`Pipeline_Stats.get_stats(minutes)`, four plain `SELECT count(*) ... WHERE <time column> >= now() - interval` queries, no caching - these are meant to be live) + `GET /hermes/pipeline/stats` (`services/api/src/routers/hermes.py`, `minutes` query param, 1 to 10080/7 days). **`Rule_Events` deliberately does NOT count rule evaluations** - `rule` evaluates every single stream message 1:1, the same count `Data_Processed` already reports, so repeating it would be redundant; it counts `device_timeline` rows instead, rule's actual observable output (a trigger/reset transition), not every evaluation pass. The CLI prints a bordered summary table plus a soft backlog hint (yellow note, not an error) if `Data_Processed` looks meaningfully behind `Ingest_Valid` (`<80%`) - a sign of consumer lag worth checking, not itself proof of one. Live-tested against real prod DB: `--minutes 60` correctly returned all zeros (no test traffic in the preceding hour at that point in the session), `--minutes 1440` correctly returned real 24h counts, and a fresh real packet sent immediately before a `--minutes 5` check showed up as exactly `+1` across Ingest/Data_Processed/Blockchain_Mined (Rule_Events stayed `0`, correctly - that packet's only variable, `PCB_T`, didn't cross any rule threshold).
358
+
121
359
  `qapu trend` shows a per-variable history plus a simple linear-regression trend line (slope + direction). Three modes, picked by which options you pass:
122
360
  - **Raw readings** (`--last N`, default `N=20`): the measurement cache's rolling buffer - bounded to its own depth (~50 most recent packets), *not* a time window. Good for "what's it doing right now."
123
361
  - **Daily aggregates** (`--days N`): one row per calendar day (min/avg/max/count), from the same cache the `/measurement/{device_id}/history` endpoint reads - this is what actually covers multi-day/month windows, since the raw buffer doesn't go back that far. `--days` wins over `--last` if both are given (and `--start`/`--end` isn't).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qapu-cli"
3
- version = "0.7.1"
3
+ version = "0.7.2"
4
4
  description = "CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1256,6 +1256,53 @@ def device_energy(
1256
1256
  # Get One Variable's Trend on One Device - Either the Last N Raw Buffered
1257
1257
  # Readings, or Daily Min/Avg/Max Over the Last N Days (Mutually Exclusive -
1258
1258
  # --days Wins if Both are Given)
1259
+ @app.command("pipeline")
1260
+ def pipeline_stats(
1261
+ minutes: int = typer.Option(60, "--minutes", help="Window size in minutes (default 60, max 10080/7 days)."),
1262
+ as_json: bool = typer.Option(False, "--json", help="Print raw JSON instead of the summary table."),
1263
+ ):
1264
+ """Fleet-wide pipeline throughput for a time window - ingest/data/rule/blockchain packet+event counts (GET /hermes/pipeline/stats)."""
1265
+ result: dict[str, Any] = client.get("/hermes/pipeline/stats", params={"minutes": minutes})
1266
+
1267
+ if as_json:
1268
+ typer.echo(json.dumps(result, indent=2))
1269
+ return
1270
+
1271
+ if not result:
1272
+ typer.echo("İstatistikler alınamadı.")
1273
+ return
1274
+
1275
+ window = result.get("Window_Minutes", minutes)
1276
+ window_label = f"{window} dk" if window < 60 else (f"{window // 60} sa" if window % 60 == 0 else f"{window} dk")
1277
+
1278
+ console.print(f"[bold]Pipeline Özeti[/bold] - son {window_label}\n")
1279
+
1280
+ table = Table(show_header=True, header_style="bold")
1281
+ table.add_column("AŞAMA")
1282
+ table.add_column("SAYI", justify="right")
1283
+ table.add_column("DETAY")
1284
+
1285
+ ingest_total = result.get("Ingest_Total", 0)
1286
+ ingest_valid = result.get("Ingest_Valid", 0)
1287
+ ingest_invalid = result.get("Ingest_Invalid", 0)
1288
+ data_processed = result.get("Data_Processed", 0)
1289
+ rule_events = result.get("Rule_Events", 0)
1290
+ blocks_mined = result.get("Blockchain_Mined", 0)
1291
+
1292
+ table.add_row("Ingest (hardware)", str(ingest_total), f"{ingest_valid} geçerli, {ingest_invalid} geçersiz")
1293
+ table.add_row("Data İşlendi (data)", str(data_processed), "kalibrasyon + sentez tamamlanan paket")
1294
+ table.add_row("Kural Olayları (rule)", str(rule_events), "tetiklenen/sıfırlanan olay (device_timeline)")
1295
+ table.add_row("Blockchain Kazıldı", str(blocks_mined), "yeni blok")
1296
+
1297
+ console.print(table)
1298
+
1299
+ # Simple Backlog Hint - not an Alert, Just a Note if the Numbers Look
1300
+ # Off (data_processed Should Track ingest_valid Closely Since data
1301
+ # Consumes qapu.raw 1:1)
1302
+ if ingest_valid > 0 and data_processed < ingest_valid * 0.8:
1303
+ console.print(f"\n[yellow]Not: Data işlenen paket sayısı ({data_processed}), geçerli ingest sayısından ({ingest_valid}) belirgin şekilde düşük - olası birikme/gecikme, kontrol edilebilir.[/yellow]")
1304
+
1305
+
1259
1306
  @app.command("trend")
1260
1307
  def device_trend(
1261
1308
  device_id: str = typer.Argument(..., help="Device ID."),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qapu-cli
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm.
5
5
  Author: OVOO Technology
6
6
  Classifier: Programming Language :: Python :: 3
@@ -48,6 +48,236 @@ Either way installs a `qapu` command (see `pyproject.toml`'s `[project.scripts]`
48
48
 
49
49
  ## Commands
50
50
 
51
+ **Full command reference (100 commands, auto-generated from `main.py`'s docstrings on 2026-09-04 - regenerate the same way if this drifts, don't hand-maintain)**: every command below has `--help` for its full flag list; commands under a resource group (`device`, `variable`, `group`, ...) follow `qapu <group> <command> ...`. The rest of this section gives worked examples and deeper narrative for the commands with more going on (`data`/`trend`/`energy`/`voltage`/`current`/`power`/`ct-check`/`fleet`/`infrastructure`/etc.) - if a command below isn't mentioned again further down, its one-line description here plus `--help` is the whole story, there's nothing more to it.
52
+
53
+ #### Top-level (device-scoped or global)
54
+
55
+ | Command | Description |
56
+ |---|---|
57
+ | `qapu ct-check` | Diagnose CT (current transformer) wiring per phase - reversed polarity vs. wrong phase order - from live PF_R/S/T/AE_R/S/T (GET /hermes/data/{device_id}). |
58
+ | `qapu current` | Current synthesis parameters, grouped (RMS, imbalance, THD, crest factor, fundamental component) (GET /hermes/data/{device_id}). |
59
+ | `qapu data` | Readings per variable for a device - latest value, last N buffered readings (--last), daily min/avg/max (--days), or an explicit --start/--end range (GET /hermes/data/{device_id}). |
60
+ | `qapu energy` | One day's active/reactive energy breakdown per phase (GET /hermes/energy/{device_id}). |
61
+ | `qapu health` | Check CLI/server version, connectivity, and server status (GET /health, no auth required). |
62
+ | `qapu pipeline` | Fleet-wide pipeline throughput for a time window - ingest/data/rule/blockchain packet+event counts (GET /hermes/pipeline/stats). |
63
+ | `qapu power` | Power synthesis parameters, grouped (active/reactive/apparent, imbalance, power factor) (GET /hermes/data/{device_id}). |
64
+ | `qapu timeline` | Get one device's timeline events (GET /hermes/timeline/{device_id}). |
65
+ | `qapu trend` | Trend for one variable on one device: recent readings, daily min/avg/max, or an explicit --start/--end range (GET /hermes/trend/{device_id}/{variable_id}). |
66
+ | `qapu voltage` | Voltage synthesis parameters, grouped (RMS, imbalance, THD, fundamental component) (GET /hermes/data/{device_id}). |
67
+
68
+ #### `device` - device inventory
69
+
70
+ | Command | Description |
71
+ |---|---|
72
+ | `qapu device get` | Get one device's detail (GET /hermes/devices/{device_id}). |
73
+ | `qapu device list` | List every device Qapu knows about (GET /hermes/devices). |
74
+
75
+ #### `variable` - variable catalog
76
+
77
+ | Command | Description |
78
+ |---|---|
79
+ | `qapu variable get` | Get one variable's detail (GET /hermes/variables/{variable_id}). |
80
+ | `qapu variable list` | List the variable catalog (GET /hermes/variables). |
81
+
82
+ #### `group` - device groups
83
+
84
+ | Command | Description |
85
+ |---|---|
86
+ | `qapu group add` | Create a new device group (POST /hermes/groups). |
87
+ | `qapu group assign` | Assign a device to a group (POST /hermes/groups/{group_id}/devices/{device_id}). |
88
+ | `qapu group devices` | List the device IDs assigned to one group (GET /hermes/groups/{group_id}/devices). |
89
+ | `qapu group get` | Get one group's detail (GET /hermes/groups/{group_id}). |
90
+ | `qapu group list` | List device groups (GET /hermes/groups). |
91
+ | `qapu group unassign` | Remove a device's assignment from a group (DELETE /hermes/groups/{group_id}/devices/{device_id}). |
92
+ | `qapu group update` | Update an existing group - only the fields passed are changed (PUT /hermes/groups/{group_id}). |
93
+
94
+ #### `manufacturer` - manufacturer catalog
95
+
96
+ | Command | Description |
97
+ |---|---|
98
+ | `qapu manufacturer add` | Create a new manufacturer (POST /hermes/manufacturers). |
99
+ | `qapu manufacturer delete` | Delete an existing manufacturer (DELETE /hermes/manufacturers/{manufacturer_id}). |
100
+ | `qapu manufacturer get` | Get one manufacturer's detail (GET /hermes/manufacturers/{manufacturer_id}). |
101
+ | `qapu manufacturer list` | List the manufacturer catalog, grouped by category (GET /hermes/manufacturers). |
102
+ | `qapu manufacturer update` | Update an existing manufacturer - only the fields passed are changed (PUT /hermes/manufacturers/{manufacturer_id}). |
103
+
104
+ #### `model` - hardware model catalog
105
+
106
+ | Command | Description |
107
+ |---|---|
108
+ | `qapu model add` | Create a new hardware model, linked to its manufacturer (POST /hermes/models). |
109
+ | `qapu model delete` | Delete an existing hardware model (DELETE /hermes/models/{model_id}). |
110
+ | `qapu model get` | Get one hardware model's detail (GET /hermes/models/{model_id}). |
111
+ | `qapu model list` | List the hardware model catalog, grouped by the same thousands-as-category convention as manufacturers (GET /hermes/models). |
112
+ | `qapu model update` | Update an existing hardware model - only the fields passed are changed (PUT /hermes/models/{model_id}). |
113
+
114
+ #### `modem` - modem inventory
115
+
116
+ | Command | Description |
117
+ |---|---|
118
+ | `qapu modem get` | Get one modem's detail by IMEI (GET /hermes/modems/{imei}). |
119
+ | `qapu modem list` | List the modem inventory (GET /hermes/modems). |
120
+
121
+ #### `sim` - SIM inventory
122
+
123
+ | Command | Description |
124
+ |---|---|
125
+ | `qapu sim get` | Get one SIM's detail by ICCID (GET /hermes/sims/{iccid}). |
126
+ | `qapu sim list` | List the SIM inventory (GET /hermes/sims). |
127
+
128
+ #### `firmware` - firmware catalog
129
+
130
+ | Command | Description |
131
+ |---|---|
132
+ | `qapu firmware get` | Get one firmware version's detail (GET /hermes/firmware/{version}). |
133
+ | `qapu firmware list` | List the firmware catalog (GET /hermes/firmware). |
134
+
135
+ #### `status` - device/modem status catalog
136
+
137
+ | Command | Description |
138
+ |---|---|
139
+ | `qapu status add` | Create a new status (POST /hermes/statuses). |
140
+ | `qapu status delete` | Delete an existing status (DELETE /hermes/statuses/{status_id}). |
141
+ | `qapu status get` | Get one status's detail (GET /hermes/statuses/{status_id}). |
142
+ | `qapu status list` | List the device/modem status catalog, grouped by category (GET /hermes/statuses). |
143
+ | `qapu status update` | Update an existing status - only the fields passed are changed (PUT /hermes/statuses/{status_id}). |
144
+
145
+ #### `equipment-type` - box equipment type catalog
146
+
147
+ | Command | Description |
148
+ |---|---|
149
+ | `qapu equipment-type add` | Create a new equipment type - use before recording box equipment of a kind that doesn't exist in the catalog yet (POST /hermes/equipment_types). |
150
+ | `qapu equipment-type get` | Get one equipment type's detail (GET /hermes/equipment_types/{id}). |
151
+ | `qapu equipment-type list` | List the box equipment type catalog (GET /hermes/equipment_types). |
152
+
153
+ #### `pump-type` - pump type catalog
154
+
155
+ | Command | Description |
156
+ |---|---|
157
+ | `qapu pump-type add` | Create a new pump type - use before recording a pump of a kind that doesn't exist in the catalog yet (POST /hermes/pump_types). |
158
+ | `qapu pump-type delete` | Delete an existing pump type (DELETE /hermes/pump_types/{pump_type_id}). |
159
+ | `qapu pump-type get` | Get one pump type's detail (GET /hermes/pump_types/{id}). |
160
+ | `qapu pump-type list` | List the pump type catalog (GET /hermes/pump_types). |
161
+ | `qapu pump-type update` | Update an existing pump type - only the fields passed are changed (PUT /hermes/pump_types/{pump_type_id}). |
162
+
163
+ #### `infrastructure` - transformer/box/pump/equipment/land plot
164
+
165
+ | Command | Description |
166
+ |---|---|
167
+ | `qapu infrastructure add` | Create standalone infrastructure (transformer/electric box/equipment/pump), or add a land plot to a device's pump. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
168
+ | `qapu infrastructure assign` | Assign a device to control an existing pump, or monitor a transformer directly. Pick exactly one of --pump or --transformer. |
169
+ | `qapu infrastructure delete` | Delete one piece of box equipment (--equipment), or unlink/delete a device's whole infrastructure chain (DELETE /hermes/infrastructure/...). |
170
+ | `qapu infrastructure get` | Get one device's infrastructure - pump/box/transformer/equipment/land plots, or a direct transformer link (GET /hermes/infrastructure/{device_id}). |
171
+ | `qapu infrastructure update` | Update detail fields on a device's infrastructure. Pick exactly one of --transformer/--electric-box/--equipment/--pump/--land-plot. |
172
+
173
+ #### `blockchain` - mined block ledger
174
+
175
+ | Command | Description |
176
+ |---|---|
177
+ | `qapu blockchain get` | Get one device's block at a given index, full payload (GET /hermes/blockchain/{device_id}/{index}). |
178
+ | `qapu blockchain list` | List every mined block for a device, genesis to latest (GET /hermes/blockchain/{device_id}). |
179
+ | `qapu blockchain validate` | Validate a device's mined block chain - length, secure/tampered status, and time range (GET /hermes/blockchain/{device_id}/validate). |
180
+
181
+ #### `calibration` - Gain/Offset per variable
182
+
183
+ | Command | Description |
184
+ |---|---|
185
+ | `qapu calibration add` | Create a new calibration row for a device/variable (POST /hermes/calibration). |
186
+ | `qapu calibration delete` | Delete an existing calibration row (DELETE /hermes/calibration/{calibration_id}). |
187
+ | `qapu calibration get` | Get one calibration row's detail (GET /hermes/calibration/detail/{calibration_id}). |
188
+ | `qapu calibration list` | List a device's calibration rows - Gain/Offset per variable (GET /hermes/calibration/{device_id}). |
189
+ | `qapu calibration update` | Update an existing calibration row - only the fields passed are changed (PUT /hermes/calibration/{calibration_id}). |
190
+
191
+ #### `crop-type` - crop type catalog
192
+
193
+ | Command | Description |
194
+ |---|---|
195
+ | `qapu crop-type add` | Create a new crop type - use before recording a land plot growing a crop that doesn't exist in the catalog yet (POST /hermes/crop_types). |
196
+ | `qapu crop-type delete` | Delete an existing crop type (DELETE /hermes/crop_types/{crop_type_id}). |
197
+ | `qapu crop-type get` | Get one crop type's detail (GET /hermes/crop_types/{id}). |
198
+ | `qapu crop-type list` | List the crop type catalog (GET /hermes/crop_types). |
199
+ | `qapu crop-type update` | Update an existing crop type - only the fields passed are changed (PUT /hermes/crop_types/{crop_type_id}). |
200
+
201
+ #### `irrigation-type` - irrigation method catalog
202
+
203
+ | Command | Description |
204
+ |---|---|
205
+ | `qapu irrigation-type add` | Create a new irrigation type - use before recording a land plot using a method that doesn't exist in the catalog yet (POST /hermes/irrigation_types). |
206
+ | `qapu irrigation-type delete` | Delete an existing irrigation type (DELETE /hermes/irrigation_types/{irrigation_type_id}). |
207
+ | `qapu irrigation-type get` | Get one irrigation type's detail (GET /hermes/irrigation_types/{id}). |
208
+ | `qapu irrigation-type list` | List the irrigation type catalog (GET /hermes/irrigation_types). |
209
+ | `qapu irrigation-type update` | Update an existing irrigation type - only the fields passed are changed (PUT /hermes/irrigation_types/{irrigation_type_id}). |
210
+
211
+ #### `setting` - rule thresholds, register, electric box
212
+
213
+ | Command | Description |
214
+ |---|---|
215
+ | `qapu setting get` | Get a device's editable settings - thresholds, register, electric box (GET /hermes/setting/{device_id}). |
216
+ | `qapu setting update` | Update a device's editable settings - only the fields passed are changed (PUT /hermes/setting/{device_id}). |
217
+
218
+ #### `stream` - ingested packet history
219
+
220
+ | Command | Description |
221
+ |---|---|
222
+ | `qapu stream get` | Get one stream row's detail - command name and variable count included (GET /hermes/stream/detail/{stream_id}). |
223
+ | `qapu stream list` | List a device's ingested packet stream history, most recent first (GET /hermes/stream/{device_id}). |
224
+
225
+ #### `synthesis` - derived-metric calculation rules
226
+
227
+ | Command | Description |
228
+ |---|---|
229
+ | `qapu synthesis add` | Create a new synthesis rule (POST /hermes/synthesis). |
230
+ | `qapu synthesis delete` | Delete an existing synthesis rule (DELETE /hermes/synthesis/{rule_id}). |
231
+ | `qapu synthesis get` | Get one synthesis rule's detail (GET /hermes/synthesis/{rule_id}). |
232
+ | `qapu synthesis list` | List derived-metric calculation rules (GET /hermes/synthesis). |
233
+ | `qapu synthesis update` | Update an existing synthesis rule - only the fields passed are changed (PUT /hermes/synthesis/{rule_id}). |
234
+
235
+ #### `user-role` - user role catalog (Admin/User/...)
236
+
237
+ | Command | Description |
238
+ |---|---|
239
+ | `qapu user-role add` | Create a new user role (POST /hermes/user_roles). |
240
+ | `qapu user-role delete` | Delete an existing user role (DELETE /hermes/user_roles/{role_id}). |
241
+ | `qapu user-role get` | Get one user role's detail (GET /hermes/user_roles/{role_id}). |
242
+ | `qapu user-role list` | List the user role catalog, e.g. Admin/User (GET /hermes/user_roles). |
243
+ | `qapu user-role update` | Update an existing user role - only the fields passed are changed (PUT /hermes/user_roles/{role_id}). |
244
+
245
+ #### `irrigation` - irrigation event history
246
+
247
+ | Command | Description |
248
+ |---|---|
249
+ | `qapu irrigation abstract` | Get a device's irrigation summary - last irrigation + 24h/today/30d/month totals (GET /hermes/irrigation/{device_id}/abstract). |
250
+ | `qapu irrigation list` | List a device's irrigation event history - start/end/duration (GET /hermes/irrigation/{device_id}). |
251
+
252
+ #### `project` - project catalog (Cinga, WeatherStat, ...)
253
+
254
+ | Command | Description |
255
+ |---|---|
256
+ | `qapu project add` | Create a new project (POST /hermes/projects). |
257
+ | `qapu project delete` | Delete an existing project (DELETE /hermes/projects/{project_id}). |
258
+ | `qapu project devices` | List every device belonging to one project, full detail (GET /hermes/projects/{project_id}/devices). |
259
+ | `qapu project get` | Get one project's detail (GET /hermes/projects/{project_id}). |
260
+ | `qapu project list` | List the project catalog (GET /hermes/projects). |
261
+ | `qapu project update` | Update an existing project - only the fields passed are changed (PUT /hermes/projects/{project_id}). |
262
+
263
+ #### `fleet` - bulk, multi-device queries
264
+
265
+ | Command | Description |
266
+ |---|---|
267
+ | `qapu fleet data` | Latest reading per variable, across every device in a group or project (GET /hermes/data/fleet). |
268
+
269
+ #### `device-command` - command template catalog (not actuation)
270
+
271
+ | Command | Description |
272
+ |---|---|
273
+ | `qapu device-command add` | Create a new device command template (POST /hermes/device_commands). |
274
+ | `qapu device-command delete` | Delete an existing device command template (DELETE /hermes/device_commands/{command_id}). |
275
+ | `qapu device-command get` | Get one device command template's detail, including its full payload Template (GET /hermes/device_commands/{id}). |
276
+ | `qapu device-command list` | List the device command template catalog (GET /hermes/device_commands). |
277
+ | `qapu device-command update` | Update an existing device command template - only the fields passed are changed (PUT /hermes/device_commands/{command_id}). |
278
+
279
+ ### Worked examples and deeper detail
280
+
51
281
  ```bash
52
282
  qapu --version # print the installed qapu-cli version and exit
53
283
  qapu health # GET /health - no auth, connectivity + CLI/server version + PyPI update check
@@ -130,6 +360,14 @@ Two distinct real installation faults, both diagnosable from `PF_R/S/T` alone (`
130
360
 
131
361
  Both are heuristics, not certainties - flags a phase for physical inspection, doesn't replace it. Detection: baseline = **median** of all three phases' `|PF|` (not "average of the other two" - the first version tried that and broke under a real multi-fault test, since one bad phase polluted the baseline used to judge the *other*, genuinely healthy phases; the median is robust to a single outlier). `deviation = |own |PF|| - baseline|` - `>= 0.15` (`CT_CHECK_DEVIATION_THRESHOLD`) means "FAZ SIRASI ŞÜPHELİ", else a negative sign means "TERS BAĞLI (Polarite)", else "Normal". The 0.15 threshold is a reasonable rule of thumb (a healthy 3-phase load's phases normally track within a few percent of each other), not derived from real fault-case field data - revisit if a real miswiring case doesn't get flagged correctly. Each phase's panel also shows `AE` (cross-referencing the existing rule's own signal) and "son veri: X dk/saat önce" (via the same `_relative_time()` helper used elsewhere). Live-tested against real prod data via deliberately-crafted `PF_R/S/T` packets sent to a disposable test device: healthy (all three ≈0.93-0.94) → all Normal; single reversed-polarity phase → only that phase flagged, others stay Normal; single wrong-phase-order phase → only that phase flagged; **two simultaneous faults** (one reversed + one phase-order, the case that broke the first "average of other two" version) → all three phases correctly classified independently. Device left in a healthy state afterward.
132
362
 
363
+ **`qapu pipeline` (added 2026-09-04)** - fleet-wide pipeline throughput for a time window, per direct request ("son x süre içerisinde ingeste kaç paket gelmiş data ne kadar işlemiş rule ne işlemiş gibi... docker servis özetleri"):
364
+ ```bash
365
+ qapu pipeline # last 60 minutes (default)
366
+ qapu pipeline --minutes 1440 # last 24 hours
367
+ qapu pipeline --json
368
+ ```
369
+ Not device-scoped - a fleet-wide summary across every service in the `ingest -> stream -> calibration -> raw-writer -> synthesis -> ... -> rule` pipeline. Deliberately reads from the real tables each stage actually writes to (`raw_data.stream_time`/`valid_pack` for `hardware`'s ingest, `streams.stream_time` for `data`'s calibration+synthesis completion, `device_timeline.create_time` for `rule`'s observable output, `blockchain.create_time` for mined blocks) rather than any service's own `/health` endpoint - those are point-in-time snapshots (uptime, CPU, last-message-age), not a windowed throughput count. New `common/qapu_common/domain/pipeline.py` (`Pipeline_Stats.get_stats(minutes)`, four plain `SELECT count(*) ... WHERE <time column> >= now() - interval` queries, no caching - these are meant to be live) + `GET /hermes/pipeline/stats` (`services/api/src/routers/hermes.py`, `minutes` query param, 1 to 10080/7 days). **`Rule_Events` deliberately does NOT count rule evaluations** - `rule` evaluates every single stream message 1:1, the same count `Data_Processed` already reports, so repeating it would be redundant; it counts `device_timeline` rows instead, rule's actual observable output (a trigger/reset transition), not every evaluation pass. The CLI prints a bordered summary table plus a soft backlog hint (yellow note, not an error) if `Data_Processed` looks meaningfully behind `Ingest_Valid` (`<80%`) - a sign of consumer lag worth checking, not itself proof of one. Live-tested against real prod DB: `--minutes 60` correctly returned all zeros (no test traffic in the preceding hour at that point in the session), `--minutes 1440` correctly returned real 24h counts, and a fresh real packet sent immediately before a `--minutes 5` check showed up as exactly `+1` across Ingest/Data_Processed/Blockchain_Mined (Rule_Events stayed `0`, correctly - that packet's only variable, `PCB_T`, didn't cross any rule threshold).
370
+
133
371
  `qapu trend` shows a per-variable history plus a simple linear-regression trend line (slope + direction). Three modes, picked by which options you pass:
134
372
  - **Raw readings** (`--last N`, default `N=20`): the measurement cache's rolling buffer - bounded to its own depth (~50 most recent packets), *not* a time window. Good for "what's it doing right now."
135
373
  - **Daily aggregates** (`--days N`): one row per calendar day (min/avg/max/count), from the same cache the `/measurement/{device_id}/history` endpoint reads - this is what actually covers multi-day/month windows, since the raw buffer doesn't go back that far. `--days` wins over `--last` if both are given (and `--start`/`--end` isn't).
File without changes
File without changes
File without changes