rhombus-node-mcp 0.1.28 → 0.1.30
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/dist/api/events-tool-api.js +104 -22
- package/dist/createServer.js +1 -1
- package/dist/tools/events-tool.js +34 -5
- package/dist/tools/lpr-tool.js +2 -0
- package/dist/types/access-control-tool-types.js +1 -1
- package/dist/types/events-tools-types.js +54 -5
- package/dist/types/lpr-tool-types.js +3 -1
- package/package.json +1 -1
|
@@ -4,9 +4,20 @@ import { postApi } from "../network/network.js";
|
|
|
4
4
|
import { formatTimestamp } from "../util.js";
|
|
5
5
|
import { tempFunc, TempUnit } from "../utils/temp.js";
|
|
6
6
|
// Type definitions
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/** One entry from the camera VOD footage seekpoint index (many activity types). */
|
|
8
|
+
export const CameraFootageEvent = z.object({
|
|
9
|
+
activity: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe("Activity type on the recording timeline (e.g. MOTION_HUMAN, MOTION_CAR, LICENSEPLATE_IDENTIFIED—exact set depends on the camera and analytics)."),
|
|
12
|
+
timestamp: z.number().describe("Unix timestamp in milliseconds."),
|
|
13
|
+
id: z.number().optional().describe("Seekpoint id when the API provides one."),
|
|
14
|
+
licensePlate: z
|
|
15
|
+
.string()
|
|
16
|
+
.nullable()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Plate text on this seekpoint when present. For org LPR saved vehicles, labels, and plate search APIs, use lpr-tool."),
|
|
19
|
+
vehicleName: z.string().nullable().optional().describe("Vehicle display name on this seekpoint when present."),
|
|
20
|
+
faceNames: z.string().nullable().optional().describe("Face names on this seekpoint when present."),
|
|
10
21
|
});
|
|
11
22
|
const ACCESS_CONTROL_EVENT_BATCH_SIZE = 1000;
|
|
12
23
|
const ACCESS_CONTROL_EVENT_TYPE_FILTER = ["CredentialReceivedEvent"];
|
|
@@ -75,6 +86,71 @@ async function getAccessControlEventsForDoor(doorUuid, startTime, endTime, timeZ
|
|
|
75
86
|
}
|
|
76
87
|
return allEvents;
|
|
77
88
|
}
|
|
89
|
+
export async function getBrivoAccessControlEvents(startTime, endTime, timeZone, requestModifiers, sessionId) {
|
|
90
|
+
// Step 1: fetch Brivo integration config to get configured doors and their location UUIDs
|
|
91
|
+
const integrationResponse = await postApi({
|
|
92
|
+
route: "/integrations/accessControl/getBrivoIntegrationV2",
|
|
93
|
+
body: {},
|
|
94
|
+
modifiers: requestModifiers,
|
|
95
|
+
sessionId,
|
|
96
|
+
});
|
|
97
|
+
const brivoSettings = integrationResponse.orgIntegrationV2;
|
|
98
|
+
const integrationEnabled = brivoSettings?.enabled ?? false;
|
|
99
|
+
const doorInfoMap = brivoSettings?.doorInfoMap ?? {};
|
|
100
|
+
const brivoDoors = Object.entries(doorInfoMap)
|
|
101
|
+
.filter(([, info]) => info != null)
|
|
102
|
+
.map(([brivoDoornId, info]) => ({
|
|
103
|
+
brivoDoornId,
|
|
104
|
+
doorName: info.doorName ?? undefined,
|
|
105
|
+
locationUuid: info.locationUuid ?? undefined,
|
|
106
|
+
}));
|
|
107
|
+
if (brivoDoors.length === 0) {
|
|
108
|
+
return {
|
|
109
|
+
integrationEnabled,
|
|
110
|
+
brivoDoorsConfigured: 0,
|
|
111
|
+
brivoDoors: [],
|
|
112
|
+
events: [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Step 2: collect unique location UUIDs from configured Brivo doors
|
|
116
|
+
const locationUuids = [...new Set(brivoDoors.map(d => d.locationUuid).filter((id) => !!id))];
|
|
117
|
+
// Step 3: query CredentialReceivedEvents for each location
|
|
118
|
+
const MAX_LIMIT = 1000;
|
|
119
|
+
const allEvents = [];
|
|
120
|
+
await Promise.all(locationUuids.map(async (locationUuid) => {
|
|
121
|
+
const body = {
|
|
122
|
+
locationUuid,
|
|
123
|
+
typeFilter: ["CredentialReceivedEvent"],
|
|
124
|
+
...(startTime ? { createdAfterMs: startTime } : {}),
|
|
125
|
+
...(endTime ? { createdBeforeMs: endTime } : {}),
|
|
126
|
+
limit: MAX_LIMIT,
|
|
127
|
+
};
|
|
128
|
+
const response = await postApi({
|
|
129
|
+
route: "/component/findComponentEventsByLocation",
|
|
130
|
+
body,
|
|
131
|
+
modifiers: requestModifiers,
|
|
132
|
+
sessionId,
|
|
133
|
+
});
|
|
134
|
+
const mapped = (response.componentEvents || []).map(event => mapAccessControlEvent(event, timeZone));
|
|
135
|
+
allEvents.push(...mapped);
|
|
136
|
+
}));
|
|
137
|
+
allEvents.sort((a, b) => (b.timestampMs || 0) - (a.timestampMs || 0));
|
|
138
|
+
return {
|
|
139
|
+
integrationEnabled,
|
|
140
|
+
brivoDoorsConfigured: brivoDoors.length,
|
|
141
|
+
brivoDoors,
|
|
142
|
+
events: allEvents.map(e => ({
|
|
143
|
+
authenticationResult: e.authenticationResult ?? undefined,
|
|
144
|
+
authorizationResult: e.authorizationResult ?? undefined,
|
|
145
|
+
doorUuid: e.doorUuid ?? undefined,
|
|
146
|
+
locationUuid: e.locationUuid ?? undefined,
|
|
147
|
+
user: e.user ?? undefined,
|
|
148
|
+
credSource: e.credSource ?? undefined,
|
|
149
|
+
timestampMs: e.timestampMs ?? undefined,
|
|
150
|
+
datetime: e.datetime,
|
|
151
|
+
})),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
78
154
|
export async function getFaceEvents(_locationUuid, timeZone, requestModifiers, sessionId) {
|
|
79
155
|
const nowMs = Date.now();
|
|
80
156
|
const rangeStartMs = nowMs - THREE_HOURS_MS;
|
|
@@ -121,7 +197,7 @@ export async function getAccessControlEvents(doorUuids, startTime, endTime, time
|
|
|
121
197
|
console.error(`componentEvents: ${JSON.stringify(accessControlEvents)}`);
|
|
122
198
|
return accessControlEvents;
|
|
123
199
|
}
|
|
124
|
-
export async function
|
|
200
|
+
export async function getCameraFootageSeekpointEvents(cameraUuid, duration, startTime, requestModifiers, sessionId) {
|
|
125
201
|
const body = {
|
|
126
202
|
cameraUuid,
|
|
127
203
|
duration,
|
|
@@ -132,25 +208,31 @@ export async function getHumanMotionEvents(cameraUuid, duration, startTime, requ
|
|
|
132
208
|
body,
|
|
133
209
|
modifiers: requestModifiers,
|
|
134
210
|
sessionId,
|
|
135
|
-
}).then(response => {
|
|
136
|
-
const seekPoints = response.footageSeekPoints || [];
|
|
137
|
-
const uniqueHumanEvents = seekPoints
|
|
138
|
-
.reduceRight((acc, point) => {
|
|
139
|
-
if (point.a === "MOTION_HUMAN" &&
|
|
140
|
-
typeof point.ts === "number" &&
|
|
141
|
-
typeof point.id === "number" &&
|
|
142
|
-
!acc.some(existing => existing.id === point.id)) {
|
|
143
|
-
acc.unshift({ timestamp: point.ts, id: point.id });
|
|
144
|
-
}
|
|
145
|
-
return acc;
|
|
146
|
-
}, [])
|
|
147
|
-
.map(event => ({
|
|
148
|
-
timestamp: event.timestamp,
|
|
149
|
-
id: event.id,
|
|
150
|
-
}));
|
|
151
|
-
return { cameraUuid, uniqueHumanEvents };
|
|
152
211
|
});
|
|
153
|
-
|
|
212
|
+
const seekPoints = response.footageSeekPoints ?? [];
|
|
213
|
+
const seen = new Set();
|
|
214
|
+
const cameraFootageEvents = [];
|
|
215
|
+
for (const point of seekPoints) {
|
|
216
|
+
if (typeof point.ts !== "number" || point.a == null) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const idPart = point.id != null ? String(point.id) : "noid";
|
|
220
|
+
const dedupeKey = `${idPart}_${point.ts}_${point.a}`;
|
|
221
|
+
if (seen.has(dedupeKey)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
seen.add(dedupeKey);
|
|
225
|
+
cameraFootageEvents.push({
|
|
226
|
+
activity: String(point.a),
|
|
227
|
+
timestamp: point.ts,
|
|
228
|
+
...(point.id != null ? { id: point.id } : {}),
|
|
229
|
+
...(point.lp !== undefined ? { licensePlate: point.lp } : {}),
|
|
230
|
+
...(point.vn !== undefined ? { vehicleName: point.vn } : {}),
|
|
231
|
+
...(point.fn !== undefined ? { faceNames: point.fn } : {}),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
cameraFootageEvents.sort((a, b) => b.timestamp - a.timestamp);
|
|
235
|
+
return { cameraUuid, cameraFootageEvents };
|
|
154
236
|
}
|
|
155
237
|
const EVENT_COUNT_MAX_PER_RESPONSE = 2000;
|
|
156
238
|
export async function getEventsForEnvironmentalGateway(deviceUuid, startTime, endTime, timeZone, tempUnit, requestModifiers, sessionId) {
|
package/dist/createServer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAccessControlEvents, getEventsForEnvironmentalGateway, getClimateEventsForSensor, getComponentEventsByLocation,
|
|
1
|
+
import { getAccessControlEvents, getBrivoAccessControlEvents, getEventsForEnvironmentalGateway, getClimateEventsForSensor, getComponentEventsByLocation, getCameraFootageSeekpointEvents, getButtonPressEvents, getOccupancyEvents, getProximityEvents, getDoorbellEvents, } from "../api/events-tool-api.js";
|
|
2
2
|
import { EventsToolRequestType, OUTPUT_SCHEMA, TOOL_ARGS, } from "../types/events-tools-types.js";
|
|
3
3
|
import { createToolStructuredContent } from "../util.js";
|
|
4
4
|
import { getLogger } from "../logger.js";
|
|
@@ -9,7 +9,29 @@ const TOOL_NAME = "events-tool";
|
|
|
9
9
|
const TOOL_DESCRIPTION = `
|
|
10
10
|
**Scope:** This tool returns **raw, event-level data** (individual events with timestamps). Use **report-tool** when you need aggregated counts, time-series summaries, or analytics over intervals.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**Vehicles vs lpr-tool:** **eventType "camera"** returns **footage seekpoints** from that camera's recording timeline—**every activity type** the API returns for the window (human motion, vehicle motion, and others depending on the camera and analytics). Some rows may include plate or vehicle metadata on the seekpoint. **lpr-tool** is still the right choice for **org LPR workflows**: saved vehicles, vehicle labels, fuzzy plate search, and vehicle event APIs—not a replacement for "everything this camera logged on its timeline."
|
|
13
|
+
|
|
14
|
+
This tool has multiple modes, set by "eventType": access-control, brivo-access-control, environmental-gateway, climate-sensor, component-events, camera. Use it when the user asks for specific events (unlocks, badge ins, credentials, arrivals, environmental readings, climate data, camera timeline activity, or other component events). It can return large result sets; keep time ranges narrow. For ranges spanning more than ~24 hours, prefer report-tool for aggregates. For maximum flexibility across event types at a location, use eventType "component-events".
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
When eventType is "brivo-access-control":
|
|
19
|
+
|
|
20
|
+
Retrieves badge/credential events from Brivo-integrated doors. Automatically fetches the Brivo integration configuration to determine which locations have Brivo doors mapped. No door UUIDs are required.
|
|
21
|
+
|
|
22
|
+
Use this when the user asks specifically about Brivo events, Brivo badge ins, Brivo access control, or events from Brivo doors.
|
|
23
|
+
|
|
24
|
+
Arguments:
|
|
25
|
+
* **startTime (string):** Start of the time range (ISO 8601).
|
|
26
|
+
* **endTime (string):** End of the time range (ISO 8601).
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
* **integrationEnabled:** Whether the Brivo integration is currently enabled.
|
|
30
|
+
* **brivoDoorsConfigured:** Number of Brivo doors configured in the integration.
|
|
31
|
+
* **brivoDoors:** List of Brivo doors with their IDs, names, and associated Rhombus location UUIDs.
|
|
32
|
+
* **events:** Credential received events from all locations that have Brivo doors configured, sorted newest first.
|
|
33
|
+
|
|
34
|
+
Note: Events are fetched at the location level, so results may include events from all access-controlled doors at locations where Brivo is configured.
|
|
13
35
|
|
|
14
36
|
---
|
|
15
37
|
|
|
@@ -80,7 +102,7 @@ Valid event types include:
|
|
|
80
102
|
|
|
81
103
|
When eventType is "camera":
|
|
82
104
|
|
|
83
|
-
Retrieves human motion
|
|
105
|
+
Retrieves **footage seekpoints** for one camera: **all activity types** returned for the search window (not limited to human motion). Each item includes an **activity** string plus **timestamp**; plate/vehicle/face fields appear when the API provides them. Use **lpr-tool** for org LPR saved vehicles, labels, and dedicated plate search.
|
|
84
106
|
|
|
85
107
|
Arguments:
|
|
86
108
|
* **cameraUuid (string):** UUID of the camera.
|
|
@@ -92,6 +114,13 @@ const TOOL_HANDLER = async (args, extra) => {
|
|
|
92
114
|
const { eventType, accessControlledDoorUuids, deviceUuid, sensorUuid, locationUuid, componentEventTypes, startTime, endTime, limit, timeZone, tempUnit, cameraUuid, duration, buttonSensorUuid, occupancySensorUuid, proximityTagUuids, doorbellCameraUuid, } = args;
|
|
93
115
|
logger.debug(`eventType: ${eventType}`);
|
|
94
116
|
switch (eventType) {
|
|
117
|
+
case EventsToolRequestType.BRIVO_ACCESS_CONTROL: {
|
|
118
|
+
const result = await getBrivoAccessControlEvents(startTime ? new Date(startTime).getTime() : undefined, endTime ? new Date(endTime).getTime() : undefined, timeZone, extra._meta?.requestModifiers, extra.sessionId);
|
|
119
|
+
return createToolStructuredContent({
|
|
120
|
+
eventType: "brivo-access-control",
|
|
121
|
+
brivoAccessControlEvents: result,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
95
124
|
case "access-control": {
|
|
96
125
|
if (!accessControlledDoorUuids || accessControlledDoorUuids.length === 0) {
|
|
97
126
|
return createToolStructuredContent({
|
|
@@ -148,8 +177,8 @@ const TOOL_HANDLER = async (args, extra) => {
|
|
|
148
177
|
});
|
|
149
178
|
}
|
|
150
179
|
else {
|
|
151
|
-
const events = await
|
|
152
|
-
return createToolStructuredContent({ eventType: "camera", cameraEvents: events.
|
|
180
|
+
const events = await getCameraFootageSeekpointEvents(cameraUuid, duration ?? 3600, startTime ? new Date(startTime).getTime() : Date.now() - 3600000, extra._meta?.requestModifiers, extra.sessionId);
|
|
181
|
+
return createToolStructuredContent({ eventType: "camera", cameraEvents: events.cameraFootageEvents });
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
case EventsToolRequestType.BUTTON_PRESS: {
|
package/dist/tools/lpr-tool.js
CHANGED
|
@@ -5,6 +5,8 @@ const TOOL_NAME = "lpr-tool";
|
|
|
5
5
|
const TOOL_DESCRIPTION = `
|
|
6
6
|
This tool interacts with the Rhombus LPR system to retrieve information about license plate recognition events and registered license plates.
|
|
7
7
|
|
|
8
|
+
**Vs events-tool (camera):** **events-tool** with eventType **camera** returns that camera’s **VOD footage seekpoints** (many activity types on the timeline, including vehicle-related activity when present). **lpr-tool** is for the **LPR product surface**: plate events, **saved vehicles**, **labels**, and plate **search** APIs across the org—use it when the user needs registry, labeling, or org-wide LPR queries, not only “what showed up on this camera’s timeline.”
|
|
9
|
+
|
|
8
10
|
The system's cameras may have LPR enabled, and when it is enabled, it will detect "license plate recognition" events when it sees a license plate
|
|
9
11
|
come into view. However, it is possible that the recognized license is only a partial match, so keep that in mind when using this tool.
|
|
10
12
|
Users will be able to save license plates into the system, and then additionally label them with a name.
|
|
@@ -13,7 +13,7 @@ export var AccessControlRequestType;
|
|
|
13
13
|
AccessControlRequestType["GET_REMOTE_UNLOCK_USERS"] = "get-remote-unlock-users";
|
|
14
14
|
})(AccessControlRequestType || (AccessControlRequestType = {}));
|
|
15
15
|
export const TOOL_ARGS = {
|
|
16
|
-
requestType: z.
|
|
16
|
+
requestType: z.nativeEnum(AccessControlRequestType).describe("The type of access control request to make."),
|
|
17
17
|
doorUuid: z
|
|
18
18
|
.string()
|
|
19
19
|
.nullable()
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ISOTimestampFormatDescription } from "../utils/timestampInput.js";
|
|
3
3
|
import { ComponentEventEnumType } from "./schema.js";
|
|
4
|
-
import {
|
|
4
|
+
import { CameraFootageEvent } from "../api/events-tool-api.js";
|
|
5
5
|
import { TempUnit } from "../utils/temp.js";
|
|
6
6
|
export var EventsToolRequestType;
|
|
7
7
|
(function (EventsToolRequestType) {
|
|
8
8
|
EventsToolRequestType["ACCESS_CONTROL"] = "access-control";
|
|
9
|
+
EventsToolRequestType["BRIVO_ACCESS_CONTROL"] = "brivo-access-control";
|
|
9
10
|
EventsToolRequestType["ENVIRONMENTAL_GATEWAY"] = "environmental-gateway";
|
|
10
11
|
EventsToolRequestType["CLIMATE_SENSOR"] = "climate-sensor";
|
|
11
12
|
EventsToolRequestType["COMPONENT_EVENTS"] = "component-events";
|
|
@@ -20,10 +21,11 @@ export const TOOL_ARGS = {
|
|
|
20
21
|
.nativeEnum(EventsToolRequestType)
|
|
21
22
|
.describe("The type of events to retrieve. " +
|
|
22
23
|
"access-control: Access control events like unlocks, badge ins, credentials, arrivals. " +
|
|
24
|
+
"brivo-access-control: Badge/credential events from Brivo-integrated doors. Does not require door UUIDs — automatically looks up which doors are configured via the Brivo integration. " +
|
|
23
25
|
"environmental-gateway: Environmental gateway events with sensor readings and derived values. " +
|
|
24
26
|
"climate-sensor: Climate sensor events with temperature, humidity, air quality readings. " +
|
|
25
27
|
"component-events: All types of component events for a location (most flexible option). " +
|
|
26
|
-
"camera:
|
|
28
|
+
"camera: Footage seekpoints for one camera—all timeline activity types that camera recorded (human motion, vehicle motion, etc., depending on device/analytics). For org LPR saved vehicles, labels, and plate search APIs, use lpr-tool. " +
|
|
27
29
|
"button-press: Button press events from button sensors. " +
|
|
28
30
|
"occupancy: Occupancy sensor events with people count. " +
|
|
29
31
|
"proximity: Proximity tag events with RSSI readings. " +
|
|
@@ -84,7 +86,7 @@ export const TOOL_ARGS = {
|
|
|
84
86
|
.int()
|
|
85
87
|
.positive()
|
|
86
88
|
.nullable()
|
|
87
|
-
.describe("Duration in seconds to search
|
|
89
|
+
.describe("Duration in seconds to search footage seekpoints. Required when eventType is 'camera'. Default is 3600 (1 hour)."),
|
|
88
90
|
buttonSensorUuid: z
|
|
89
91
|
.string()
|
|
90
92
|
.nullable()
|
|
@@ -143,6 +145,7 @@ export const OUTPUT_SCHEMA = z.object({
|
|
|
143
145
|
eventType: z
|
|
144
146
|
.enum([
|
|
145
147
|
"access-control",
|
|
148
|
+
"brivo-access-control",
|
|
146
149
|
"environmental-gateway",
|
|
147
150
|
"climate-sensor",
|
|
148
151
|
"component-events",
|
|
@@ -153,6 +156,52 @@ export const OUTPUT_SCHEMA = z.object({
|
|
|
153
156
|
"doorbell",
|
|
154
157
|
])
|
|
155
158
|
.optional(),
|
|
159
|
+
brivoAccessControlEvents: z.optional(z
|
|
160
|
+
.object({
|
|
161
|
+
integrationEnabled: z.boolean().describe("Whether the Brivo integration is enabled"),
|
|
162
|
+
brivoDoorsConfigured: z
|
|
163
|
+
.number()
|
|
164
|
+
.describe("Number of Brivo doors configured in the integration"),
|
|
165
|
+
brivoDoors: z
|
|
166
|
+
.array(z.object({
|
|
167
|
+
brivoDoornId: z.string().describe("Brivo's door ID"),
|
|
168
|
+
doorName: z.string().optional().describe("Brivo door name"),
|
|
169
|
+
locationUuid: z.string().optional().describe("Rhombus location UUID for this door"),
|
|
170
|
+
}))
|
|
171
|
+
.describe("List of Brivo doors configured in the integration"),
|
|
172
|
+
events: z
|
|
173
|
+
.array(z.object({
|
|
174
|
+
authenticationResult: z
|
|
175
|
+
.string()
|
|
176
|
+
.optional()
|
|
177
|
+
.describe("The result of the authentication process"),
|
|
178
|
+
authorizationResult: z
|
|
179
|
+
.string()
|
|
180
|
+
.optional()
|
|
181
|
+
.describe("The result of the authorization process"),
|
|
182
|
+
doorUuid: z
|
|
183
|
+
.string()
|
|
184
|
+
.optional()
|
|
185
|
+
.describe("The Rhombus access controlled door UUID"),
|
|
186
|
+
locationUuid: z
|
|
187
|
+
.string()
|
|
188
|
+
.optional()
|
|
189
|
+
.describe("The Rhombus location UUID where the event occurred"),
|
|
190
|
+
user: z.string().optional().describe("Username of the person who triggered the event"),
|
|
191
|
+
credSource: z
|
|
192
|
+
.string()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe("The source of the credential (e.g. WIEGAND, NFC, BLE_WAVE, REMOTE)"),
|
|
195
|
+
timestampMs: z
|
|
196
|
+
.number()
|
|
197
|
+
.optional()
|
|
198
|
+
.describe("Timestamp in milliseconds when the event occurred"),
|
|
199
|
+
datetime: z.string().optional().describe("Formatted datetime string of the event"),
|
|
200
|
+
}))
|
|
201
|
+
.describe("Credential received events from locations that have Brivo doors configured, sorted by timestamp (newest first)"),
|
|
202
|
+
})
|
|
203
|
+
.nullable()
|
|
204
|
+
.describe("Brivo access control events. Fetches credential events from all locations that have Brivo doors configured in the integration.")),
|
|
156
205
|
accessControlEvents: z.optional(z
|
|
157
206
|
.array(z.object({
|
|
158
207
|
authenticationResult: z
|
|
@@ -281,9 +330,9 @@ export const OUTPUT_SCHEMA = z.object({
|
|
|
281
330
|
.nullable()
|
|
282
331
|
.describe("Component events data for all types of access control events at a location, sorted by timestamp (newest first)")),
|
|
283
332
|
cameraEvents: z
|
|
284
|
-
.array(
|
|
333
|
+
.array(CameraFootageEvent)
|
|
285
334
|
.optional()
|
|
286
|
-
.describe(`
|
|
335
|
+
.describe(`Footage timeline seekpoints for the camera (all activity types returned in the window). Use with eventType "${EventsToolRequestType.CAMERA}".`),
|
|
287
336
|
buttonPressEvents: z
|
|
288
337
|
.array(z.object({
|
|
289
338
|
timestampMs: z.number().optional(),
|
|
@@ -45,7 +45,9 @@ export const VehicleEventsArgs = z.object({
|
|
|
45
45
|
ISOTimestampFormatDescription),
|
|
46
46
|
});
|
|
47
47
|
export const TOOL_ARGS = {
|
|
48
|
-
requestType: z
|
|
48
|
+
requestType: z
|
|
49
|
+
.nativeEnum(LprToolRequestType)
|
|
50
|
+
.describe("Org LPR operation (vehicle events, saved vehicles, labels, plate search, save vehicle). Per-camera VOD timeline seekpoints use events-tool (eventType camera)."),
|
|
49
51
|
vehicleEventsArgs: VehicleEventsArgs.nullable().describe("Only necessary for requestType 'get-vehicle-events'"),
|
|
50
52
|
timeZone: z
|
|
51
53
|
.string()
|