een-api-toolkit 0.3.97 → 0.3.103
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.
- package/CHANGELOG.md +117 -55
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/docs/AI-CONTEXT.md +1 -1
- package/docs/ai-reference/AI-AUTH.md +1 -1
- package/docs/ai-reference/AI-AUTOMATIONS.md +1 -1
- package/docs/ai-reference/AI-DEVICES.md +1 -1
- package/docs/ai-reference/AI-EVENT-DATA-SCHEMAS.md +2 -1
- package/docs/ai-reference/AI-EVENTS.md +1 -1
- package/docs/ai-reference/AI-GROUPING.md +1 -1
- package/docs/ai-reference/AI-JOBS.md +1 -1
- package/docs/ai-reference/AI-MEDIA.md +1 -1
- package/docs/ai-reference/AI-PTZ.md +1 -1
- package/docs/ai-reference/AI-SETUP.md +1 -1
- package/docs/ai-reference/AI-USERS.md +1 -1
- package/examples/vue-ptz/src/components/PositionInput.vue +236 -58
- package/package.json +1 -1
package/docs/AI-CONTEXT.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Event Type to Data Schemas Mapping - EEN API Toolkit
|
|
2
2
|
|
|
3
|
-
> **Version:** 0.3.
|
|
3
|
+
> **Version:** 0.3.103
|
|
4
4
|
>
|
|
5
5
|
> Complete reference for event type to data schema mappings.
|
|
6
6
|
> Load this document when building dynamic event queries with the `include` parameter.
|
|
@@ -152,6 +152,7 @@ const schemas = EVENT_TYPE_DATA_SCHEMAS['een.personDetectionEvent.v1']
|
|
|
152
152
|
| `een.objectRemovalEvent.v1` | monitoredArea, objectDetection, fullFrameImageUrl, croppedFrameImageUrl, displayOverlay.boundingBox, fullFrameImageUrlWithOverlay |
|
|
153
153
|
| `een.personTailgateEvent.v1` | objectDetection, fullFrameImageUrl, croppedFrameImageUrl, displayOverlay.boundingBox, fullFrameImageUrlWithOverlay |
|
|
154
154
|
| `een.edgeReportedDeviceStatusEvent.v1` | deviceCommonStatusUpdate, deviceErrorStatusUpdate |
|
|
155
|
+
| `een.accessActivationEvent.v1` | credentialAccessActivation, creatorDetails, userAccessActivation |
|
|
155
156
|
|
|
156
157
|
### Camera Analytics Events
|
|
157
158
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, watch } from 'vue'
|
|
3
3
|
import { movePtz } from 'een-api-toolkit'
|
|
4
|
-
import type { PtzPositionResponse } from 'een-api-toolkit'
|
|
4
|
+
import type { PtzPositionResponse, PtzDirection, PtzStepSize, PtzMoveType, PtzMove } from 'een-api-toolkit'
|
|
5
5
|
import { useApiLog } from '../composables/useApiLog'
|
|
6
6
|
|
|
7
7
|
const props = defineProps<{
|
|
@@ -14,45 +14,97 @@ const emit = defineEmits<{
|
|
|
14
14
|
}>()
|
|
15
15
|
|
|
16
16
|
const { log: apiLog } = useApiLog()
|
|
17
|
+
|
|
18
|
+
// Move type selection
|
|
19
|
+
const moveType = ref<PtzMoveType>('position')
|
|
20
|
+
|
|
21
|
+
// Position fields
|
|
17
22
|
const x = ref<string>('0')
|
|
18
23
|
const y = ref<string>('0')
|
|
19
24
|
const z = ref<string>('0')
|
|
25
|
+
|
|
26
|
+
// Direction fields
|
|
27
|
+
const directions = ref<PtzDirection[]>([])
|
|
28
|
+
const stepSize = ref<PtzStepSize>('medium')
|
|
29
|
+
const allDirections: PtzDirection[] = ['up', 'down', 'left', 'right', 'in', 'out']
|
|
30
|
+
|
|
31
|
+
// CenterOn fields
|
|
32
|
+
const relativeX = ref<string>('0.5')
|
|
33
|
+
const relativeY = ref<string>('0.5')
|
|
34
|
+
|
|
20
35
|
const applying = ref(false)
|
|
21
36
|
const error = ref<string | null>(null)
|
|
22
37
|
|
|
23
|
-
watch(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
watch(moveType, () => {
|
|
39
|
+
error.value = null
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
function importPosition() {
|
|
43
|
+
if (props.currentPosition) {
|
|
44
|
+
x.value = props.currentPosition.x?.toFixed(3) ?? '0'
|
|
45
|
+
y.value = props.currentPosition.y?.toFixed(3) ?? '0'
|
|
46
|
+
z.value = props.currentPosition.z?.toFixed(3) ?? '0'
|
|
28
47
|
}
|
|
29
|
-
}
|
|
48
|
+
}
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
if (
|
|
50
|
+
function buildMove(): PtzMove | null {
|
|
51
|
+
if (moveType.value === 'position') {
|
|
52
|
+
const xVal = parseFloat(x.value)
|
|
53
|
+
const yVal = parseFloat(y.value)
|
|
54
|
+
const zVal = parseFloat(z.value)
|
|
55
|
+
|
|
56
|
+
if (isNaN(xVal) || isNaN(yVal) || isNaN(zVal)) {
|
|
57
|
+
error.value = 'Invalid numeric values'
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Position coordinates are camera-specific absolute values (not normalised to 0-1)
|
|
62
|
+
return { moveType: 'position', x: xVal, y: yVal, z: zVal }
|
|
63
|
+
} else if (moveType.value === 'direction') {
|
|
64
|
+
if (directions.value.length === 0) {
|
|
65
|
+
error.value = 'Select at least one direction'
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
33
68
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
69
|
+
return { moveType: 'direction', direction: [...directions.value], stepSize: stepSize.value }
|
|
70
|
+
} else {
|
|
71
|
+
const rxVal = parseFloat(relativeX.value)
|
|
72
|
+
const ryVal = parseFloat(relativeY.value)
|
|
73
|
+
|
|
74
|
+
if (isNaN(rxVal) || isNaN(ryVal)) {
|
|
75
|
+
error.value = 'Invalid numeric values'
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
37
78
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
79
|
+
if (rxVal < 0 || rxVal > 1 || ryVal < 0 || ryVal > 1) {
|
|
80
|
+
error.value = 'Values must be between 0 and 1'
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { moveType: 'centerOn', relativeX: rxVal, relativeY: ryVal }
|
|
41
85
|
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function apply() {
|
|
89
|
+
if (!props.cameraId || applying.value) return
|
|
42
90
|
|
|
43
|
-
applying.value = true
|
|
44
91
|
error.value = null
|
|
45
92
|
|
|
46
|
-
const move =
|
|
47
|
-
|
|
48
|
-
apiLog('movePtz', { cameraId: props.cameraId, move }, result.error ?? result.data, !!result.error)
|
|
93
|
+
const move = buildMove()
|
|
94
|
+
if (!move) return
|
|
49
95
|
|
|
50
|
-
applying.value =
|
|
96
|
+
applying.value = true
|
|
97
|
+
try {
|
|
98
|
+
const result = await movePtz(props.cameraId, move)
|
|
99
|
+
apiLog('movePtz', { cameraId: props.cameraId, move }, result.error ?? result.data, !!result.error)
|
|
51
100
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
101
|
+
if (result.error) {
|
|
102
|
+
error.value = result.error.message
|
|
103
|
+
} else {
|
|
104
|
+
emit('move-complete')
|
|
105
|
+
}
|
|
106
|
+
} finally {
|
|
107
|
+
applying.value = false
|
|
56
108
|
}
|
|
57
109
|
}
|
|
58
110
|
</script>
|
|
@@ -60,39 +112,114 @@ async function apply() {
|
|
|
60
112
|
<template>
|
|
61
113
|
<div class="position-input" data-testid="position-input">
|
|
62
114
|
<div class="input-row">
|
|
63
|
-
<label>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
data-testid="input-x"
|
|
70
|
-
@keyup.enter="apply"
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
<div class="input-row">
|
|
74
|
-
<label>Y</label>
|
|
75
|
-
<input
|
|
76
|
-
v-model="y"
|
|
77
|
-
type="number"
|
|
78
|
-
step="0.01"
|
|
79
|
-
:disabled="!cameraId || applying"
|
|
80
|
-
data-testid="input-y"
|
|
81
|
-
@keyup.enter="apply"
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<div class="input-row">
|
|
85
|
-
<label>Z</label>
|
|
86
|
-
<input
|
|
87
|
-
v-model="z"
|
|
88
|
-
type="number"
|
|
89
|
-
step="0.1"
|
|
90
|
-
min="0"
|
|
91
|
-
:disabled="!cameraId || applying"
|
|
92
|
-
data-testid="input-z"
|
|
93
|
-
@keyup.enter="apply"
|
|
94
|
-
/>
|
|
115
|
+
<label>Move</label>
|
|
116
|
+
<select v-model="moveType" :disabled="!cameraId || applying" data-testid="move-type-select">
|
|
117
|
+
<option value="position">Position</option>
|
|
118
|
+
<option value="direction">Direction</option>
|
|
119
|
+
<option value="centerOn">Center On</option>
|
|
120
|
+
</select>
|
|
95
121
|
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Position fields -->
|
|
124
|
+
<template v-if="moveType === 'position'">
|
|
125
|
+
<div class="input-row">
|
|
126
|
+
<label>X</label>
|
|
127
|
+
<input
|
|
128
|
+
v-model="x"
|
|
129
|
+
type="number"
|
|
130
|
+
step="0.01"
|
|
131
|
+
:disabled="!cameraId || applying"
|
|
132
|
+
data-testid="input-x"
|
|
133
|
+
@keyup.enter="apply"
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="input-row">
|
|
137
|
+
<label>Y</label>
|
|
138
|
+
<input
|
|
139
|
+
v-model="y"
|
|
140
|
+
type="number"
|
|
141
|
+
step="0.01"
|
|
142
|
+
:disabled="!cameraId || applying"
|
|
143
|
+
data-testid="input-y"
|
|
144
|
+
@keyup.enter="apply"
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="input-row">
|
|
148
|
+
<label>Z</label>
|
|
149
|
+
<input
|
|
150
|
+
v-model="z"
|
|
151
|
+
type="number"
|
|
152
|
+
step="0.1"
|
|
153
|
+
min="0"
|
|
154
|
+
:disabled="!cameraId || applying"
|
|
155
|
+
data-testid="input-z"
|
|
156
|
+
@keyup.enter="apply"
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
<button
|
|
160
|
+
class="import-btn"
|
|
161
|
+
:disabled="!cameraId || !currentPosition || applying"
|
|
162
|
+
@click="importPosition"
|
|
163
|
+
data-testid="import-position"
|
|
164
|
+
>
|
|
165
|
+
Import Current Position
|
|
166
|
+
</button>
|
|
167
|
+
</template>
|
|
168
|
+
|
|
169
|
+
<!-- Direction fields -->
|
|
170
|
+
<template v-else-if="moveType === 'direction'">
|
|
171
|
+
<div class="direction-checkboxes">
|
|
172
|
+
<label v-for="dir in allDirections" :key="dir" class="checkbox-label">
|
|
173
|
+
<input
|
|
174
|
+
type="checkbox"
|
|
175
|
+
:value="dir"
|
|
176
|
+
v-model="directions"
|
|
177
|
+
:disabled="!cameraId || applying"
|
|
178
|
+
:data-testid="'dir-' + dir"
|
|
179
|
+
/>
|
|
180
|
+
{{ dir }}
|
|
181
|
+
</label>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="input-row">
|
|
184
|
+
<label>Step</label>
|
|
185
|
+
<select v-model="stepSize" :disabled="!cameraId || applying" data-testid="step-size-select">
|
|
186
|
+
<option value="small">Small</option>
|
|
187
|
+
<option value="medium">Medium</option>
|
|
188
|
+
<option value="large">Large</option>
|
|
189
|
+
</select>
|
|
190
|
+
</div>
|
|
191
|
+
</template>
|
|
192
|
+
|
|
193
|
+
<!-- CenterOn fields -->
|
|
194
|
+
<template v-else>
|
|
195
|
+
<div class="input-row">
|
|
196
|
+
<label>rX</label>
|
|
197
|
+
<input
|
|
198
|
+
v-model="relativeX"
|
|
199
|
+
type="number"
|
|
200
|
+
step="0.01"
|
|
201
|
+
min="0"
|
|
202
|
+
max="1"
|
|
203
|
+
:disabled="!cameraId || applying"
|
|
204
|
+
data-testid="input-relative-x"
|
|
205
|
+
@keyup.enter="apply"
|
|
206
|
+
/>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="input-row">
|
|
209
|
+
<label>rY</label>
|
|
210
|
+
<input
|
|
211
|
+
v-model="relativeY"
|
|
212
|
+
type="number"
|
|
213
|
+
step="0.01"
|
|
214
|
+
min="0"
|
|
215
|
+
max="1"
|
|
216
|
+
:disabled="!cameraId || applying"
|
|
217
|
+
data-testid="input-relative-y"
|
|
218
|
+
@keyup.enter="apply"
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
</template>
|
|
222
|
+
|
|
96
223
|
<button
|
|
97
224
|
class="apply-btn"
|
|
98
225
|
:disabled="!cameraId || applying"
|
|
@@ -127,7 +254,7 @@ async function apply() {
|
|
|
127
254
|
font-size: 13px;
|
|
128
255
|
font-weight: 600;
|
|
129
256
|
color: #555;
|
|
130
|
-
min-width:
|
|
257
|
+
min-width: 32px;
|
|
131
258
|
text-align: right;
|
|
132
259
|
}
|
|
133
260
|
|
|
@@ -140,10 +267,61 @@ async function apply() {
|
|
|
140
267
|
font-family: monospace;
|
|
141
268
|
}
|
|
142
269
|
|
|
143
|
-
.input-row
|
|
270
|
+
.input-row select {
|
|
271
|
+
flex: 1;
|
|
272
|
+
padding: 5px 8px;
|
|
273
|
+
border: 1px solid #ddd;
|
|
274
|
+
border-radius: 4px;
|
|
275
|
+
font-size: 13px;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.input-row input:disabled,
|
|
279
|
+
.input-row select:disabled {
|
|
144
280
|
opacity: 0.5;
|
|
145
281
|
}
|
|
146
282
|
|
|
283
|
+
.direction-checkboxes {
|
|
284
|
+
display: grid;
|
|
285
|
+
grid-template-columns: 1fr 1fr;
|
|
286
|
+
gap: 4px 12px;
|
|
287
|
+
margin-bottom: 8px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.checkbox-label {
|
|
291
|
+
display: flex;
|
|
292
|
+
align-items: center;
|
|
293
|
+
gap: 6px;
|
|
294
|
+
font-size: 13px;
|
|
295
|
+
color: #555;
|
|
296
|
+
cursor: pointer;
|
|
297
|
+
text-transform: capitalize;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.checkbox-label input[type="checkbox"] {
|
|
301
|
+
margin: 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.import-btn {
|
|
305
|
+
width: 100%;
|
|
306
|
+
padding: 6px;
|
|
307
|
+
font-size: 11px;
|
|
308
|
+
background: #6c757d;
|
|
309
|
+
color: white;
|
|
310
|
+
border: none;
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
cursor: pointer;
|
|
313
|
+
margin-bottom: 4px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.import-btn:hover:not(:disabled) {
|
|
317
|
+
background: #5a6268;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.import-btn:disabled {
|
|
321
|
+
opacity: 0.4;
|
|
322
|
+
cursor: not-allowed;
|
|
323
|
+
}
|
|
324
|
+
|
|
147
325
|
.apply-btn {
|
|
148
326
|
width: 100%;
|
|
149
327
|
padding: 8px;
|