rhombus-node-mcp
Version:
MCP server for Rhombus API
375 lines (374 loc) • 18.2 kB
JavaScript
import { z } from "zod";
import { ISOTimestampFormatDescription } from "../utils/timestampInput.js";
import { ComponentEventEnumType } from "./schema.js";
import { CameraFootageEvent } from "../api/events-tool-api.js";
import { TempUnit } from "../utils/temp.js";
export var EventsToolRequestType;
(function (EventsToolRequestType) {
EventsToolRequestType["ACCESS_CONTROL"] = "access-control";
EventsToolRequestType["BRIVO_ACCESS_CONTROL"] = "brivo-access-control";
EventsToolRequestType["ENVIRONMENTAL_GATEWAY"] = "environmental-gateway";
EventsToolRequestType["CLIMATE_SENSOR"] = "climate-sensor";
EventsToolRequestType["COMPONENT_EVENTS"] = "component-events";
EventsToolRequestType["CAMERA"] = "camera";
EventsToolRequestType["BUTTON_PRESS"] = "button-press";
EventsToolRequestType["OCCUPANCY"] = "occupancy";
EventsToolRequestType["PROXIMITY"] = "proximity";
EventsToolRequestType["DOORBELL"] = "doorbell";
})(EventsToolRequestType || (EventsToolRequestType = {}));
export const TOOL_ARGS = {
eventType: z
.nativeEnum(EventsToolRequestType)
.describe("The type of events to retrieve. " +
"access-control: Access control events like unlocks, badge ins, credentials, arrivals. " +
"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. " +
"environmental-gateway: Environmental gateway events with sensor readings and derived values. " +
"climate-sensor: Climate sensor events with temperature, humidity, air quality readings. " +
"component-events: All types of component events for a location (most flexible option). " +
"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. " +
"button-press: Button press events from button sensors. " +
"occupancy: Occupancy sensor events with people count. " +
"proximity: Proximity tag events with RSSI readings. " +
"doorbell: Doorbell camera events."),
startTime: z
.string()
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
.describe("A timestamp representing when to start the search for access control events." +
ISOTimestampFormatDescription),
endTime: z
.string()
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
.describe("A timestamp representing when to end the search for access control events." +
ISOTimestampFormatDescription),
accessControlledDoorUuids: z
.array(z.string())
.nullable()
.describe("The UUIDs (array) of the access controlled doors. Required when eventType is 'access-control'."),
deviceUuid: z
.string()
.nullable()
.describe("The UUID of the environmental gateway device. Required when eventType is 'environmental-gateway' Can be obtained from the get-entity-tool for ENVIRONMENTAL_GATEWAY."),
sensorUuid: z
.string()
.nullable()
.describe("The UUID of the climate sensor. Required when eventType is 'climate-sensor'. Can be obtained from the get-entity-tool for SENSOR."),
limit: z
.number()
.int()
.positive()
.nullable()
.describe("Maximum number of climate events to return. Only applicable when eventType is 'climate-sensor'. Default is 1000. Pass null for other event types."),
locationUuid: z
.string()
.nullable()
.describe("The UUID of the location. Required when eventType is 'component-events'."),
componentEventTypes: z
.array(z.nativeEnum(ComponentEventEnumType))
.nullable()
.describe("Array of component event types to filter by. Only applicable when eventType is 'component-events'. " +
"If empty or null, returns all event types. Valid values: " +
"DoorbellEvent, DoorReaderStateChangeEvent, DoorRelayStateChangeEvent, DoorPositionIndicatorStateChangeEvent, " +
"RequestToExitStateChangeEvent, CredentialReceivedEvent, ButtonEvent, GenericInputStateChangeEvent, " +
"GenericRelayStateChangeEvent, AccessControlUnitTamperEvent, AccessControlUnitLocationLockdownStateEvent, " +
"DoorLocationLockdownStateEvent, PanicButtonEvent, AccessControlUnitBatteryStateChangeEvent, " +
"WaveToUnlockIntentExpiredEvent, DoorStateChangeEvent, DoorAuthFirstInStateEvent, DoorScheduleFirstInStateEvent, " +
"AccessControlUnitDoorFirstInStateEvent, AperioDoorExtensionStateEvent, AperioGatewayStateEvent, " +
"AperioGatewayConnectionStateChangeEvent, AperioDtcEvent, AperioTamperStateEvent."),
timeZone: z
.string()
.describe("The timezone of the requested locations or devices. This is necessary for the tool to produce accurate formatted timestamps."),
cameraUuid: z
.string()
.nullable()
.describe("The unique identifier for the camera. Required when eventType is 'camera'. Can be obtained from the get-entity-tool for CAMERA."),
duration: z
.number()
.int()
.positive()
.nullable()
.describe("Duration in seconds to search footage seekpoints. Required when eventType is 'camera'. Default is 3600 (1 hour)."),
buttonSensorUuid: z
.string()
.nullable()
.describe("The UUID of the button sensor. Required when eventType is 'button-press'."),
occupancySensorUuid: z
.string()
.nullable()
.describe("The UUID of the occupancy sensor. Required when eventType is 'occupancy'."),
proximityTagUuids: z
.array(z.string())
.nullable()
.describe("Array of proximity tag UUIDs. Required when eventType is 'proximity'."),
doorbellCameraUuid: z
.string()
.nullable()
.describe("The UUID of the doorbell camera. Required when eventType is 'doorbell'."),
tempUnit: z
.nativeEnum(TempUnit)
.nullable()
.describe("The unit of temperature to return. Default is Celsius."),
};
const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
const StrippedEnvironmentalEvent = z.object({
timestampString: z.string().optional().describe("Human-readable formatted timestamp"),
temp: z.number().optional().describe("Temperature from CO2 sensor in Celsius"),
probeTemp: z.number().optional().describe("Temperature from probe sensor in Celsius"),
humidity: z.number().optional().describe("Relative humidity percentage"),
pm25: z.number().optional().describe("PM2.5 particulate matter reading"),
co2: z.number().optional().describe("CO2 concentration in PPM"),
vapeDetected: z.boolean().optional().describe("Whether vape was detected"),
});
const ClimateSensorEvent = z.object({
timestampString: z.string().optional().describe("Human-readable formatted timestamp"),
timestampMs: z.number().optional().describe("Timestamp in milliseconds"),
temp: z.number().optional().describe("Temperature reading in Celsius"),
probeTemp: z.number().optional().describe("Temperature from probe sensor"),
// probeTempC: z.number().optional().describe("Temperature from probe sensor in Celsius"),
humidity: z.number().optional().describe("Relative humidity percentage"),
pm25: z.number().optional().describe("PM2.5 particulate matter reading"),
co2: z.number().optional().describe("CO2 concentration in PPM"),
tvoc: z.number().optional().describe("Total Volatile Organic Compounds"),
iaq: z.number().optional().describe("Indoor Air Quality index"),
ethanol: z.number().optional().describe("Ethanol concentration"),
heatIndexDegF: z.number().optional().describe("Heat index in Fahrenheit"),
heatIndexRangeWarning: z.string().optional().describe("Heat index warning level"),
vapeSmokeDetected: z.boolean().optional().describe("Whether vape or smoke was detected"),
vapeSmokePercent: z.number().optional().describe("Vape/smoke confidence percentage"),
thcDetected: z.boolean().optional().describe("Whether THC was detected"),
thcPercent: z.number().optional().describe("THC confidence percentage"),
tampered: z.boolean().optional().describe("Whether the sensor was tampered with"),
batteryPercentage: z.number().optional().describe("Battery level percentage"),
locationUuid: z.string().optional().describe("Location UUID"),
orgUuid: z.string().optional().describe("Organization UUID"),
});
export const OUTPUT_SCHEMA = z.object({
eventType: z
.enum([
"access-control",
"brivo-access-control",
"environmental-gateway",
"climate-sensor",
"component-events",
"camera",
"button-press",
"occupancy",
"proximity",
"doorbell",
])
.optional(),
brivoAccessControlEvents: z.optional(z
.object({
integrationEnabled: z.boolean().describe("Whether the Brivo integration is enabled"),
brivoDoorsConfigured: z
.number()
.describe("Number of Brivo doors configured in the integration"),
brivoDoors: z
.array(z.object({
brivoDoornId: z.string().describe("Brivo's door ID"),
doorName: z.string().optional().describe("Brivo door name"),
locationUuid: z.string().optional().describe("Rhombus location UUID for this door"),
}))
.describe("List of Brivo doors configured in the integration"),
events: z
.array(z.object({
authenticationResult: z
.string()
.optional()
.describe("The result of the authentication process"),
authorizationResult: z
.string()
.optional()
.describe("The result of the authorization process"),
doorUuid: z
.string()
.optional()
.describe("The Rhombus access controlled door UUID"),
locationUuid: z
.string()
.optional()
.describe("The Rhombus location UUID where the event occurred"),
user: z.string().optional().describe("Username of the person who triggered the event"),
credSource: z
.string()
.optional()
.describe("The source of the credential (e.g. WIEGAND, NFC, BLE_WAVE, REMOTE)"),
timestampMs: z
.number()
.optional()
.describe("Timestamp in milliseconds when the event occurred"),
datetime: z.string().optional().describe("Formatted datetime string of the event"),
}))
.describe("Credential received events from locations that have Brivo doors configured, sorted by timestamp (newest first)"),
})
.nullable()
.describe("Brivo access control events. Fetches credential events from all locations that have Brivo doors configured in the integration.")),
accessControlEvents: z.optional(z
.array(z.object({
authenticationResult: z
.string()
.optional()
.describe("The result of the authentication process"),
authorizationResult: z
.string()
.optional()
.describe("The result of the authorization process"),
doorUuid: z
.string()
.optional()
.describe("The unique identifier for the access controlled door"),
locationUuid: z
.string()
.optional()
.describe("The unique identifier for the location where the event occurred"),
user: z
.string()
.optional()
.describe("The username of the person who triggered the event"),
credSource: z
.string()
.optional()
.describe("The source of the credential. Is what generated the event. " +
"BLE_WAVE is a user badging in by physically waving their hand over the reader. " +
"NFC is a user badging in by tapping their badge or their phone on the reader. " +
"REMOTE is unlocking the door remotely through the Rhombus app."),
timestampMs: z
.number()
.optional()
.describe("Timestamp in milliseconds when the event occurred"),
datetime: z.string().optional().describe("Datetime string of when the event occurred"),
}))
.nullable()
.describe("Access control events data including badge ins, credentials, arrivals, etc., sorted by timestamp (newest first).")),
environmentalGatewayEvents: z.optional(z
.object({
events: z
.array(StrippedEnvironmentalEvent)
.optional()
.describe("An array where each object represents a single environmental event containing sensor readings and derived values"),
lastEvaluatedKey: z
.string()
.optional()
.describe("A key for pagination if more results are available"),
})
.nullable()
.describe("Environmental gateway events data including sensor readings and derived values")),
climateSensorEvents: z.optional(z
.array(ClimateSensorEvent)
.nullable()
.describe("Climate sensor events data including temperature, humidity, air quality, and other readings")),
componentEvents: z.optional(z
.array(z.object({
eventType: z
.string()
.optional()
.describe("The type of component event (e.g., DoorbellEvent, CredentialReceivedEvent, etc.)"),
componentUuid: z
.string()
.optional()
.describe("The unique identifier for the component that generated the event"),
locationUuid: z
.string()
.optional()
.describe("The unique identifier for the location where the event occurred"),
orgUuid: z.string().optional().describe("The unique identifier for the organization"),
correlationId: z
.string()
.optional()
.describe("A correlation ID for tracking related events"),
ownerDeviceUuid: z
.string()
.optional()
.describe("The unique identifier for the device that owns this component"),
datetime: z
.string()
.optional()
.describe("Human-readable datetime string of when the event occurred"),
timestampMs: z
.number()
.optional()
.describe("Timestamp in milliseconds when the event occurred"),
uuid: z.string().optional().describe("The unique identifier for this specific event"),
// Event-specific fields
authenticationResult: z
.string()
.optional()
.describe("The result of the authentication process (for credential events)"),
authorizationResult: z
.string()
.optional()
.describe("The result of the authorization process (for credential events)"),
user: z
.string()
.optional()
.describe("The username of the person who triggered the event (for credential events)"),
credSource: z
.string()
.optional()
.describe("The source of the credential (for credential events)"),
doorUuid: z
.string()
.optional()
.describe("The unique identifier for the door (for door-related events)"),
doorbellCameraUuid: z
.string()
.optional()
.describe("The unique identifier for the doorbell camera (for doorbell events)"),
previousState: z
.string()
.optional()
.describe("The previous state before the change (for state change events)"),
newState: z
.string()
.optional()
.describe("The new state after the change (for state change events)"),
reason: z.string().optional().describe("The reason for the state change or event"),
buttonState: z
.string()
.optional()
.describe("The state of the button (for button events)"),
}))
.nullable()
.describe("Component events data for all types of access control events at a location, sorted by timestamp (newest first)")),
cameraEvents: z
.array(CameraFootageEvent)
.optional()
.describe(`Footage timeline seekpoints for the camera (all activity types returned in the window). Use with eventType "${EventsToolRequestType.CAMERA}".`),
buttonPressEvents: z
.array(z.object({
timestampMs: z.number().optional(),
datetime: z.string().optional(),
sensorUuid: z.string().optional(),
buttonState: z.string().optional(),
}))
.optional()
.describe("Button press events"),
occupancyEvents: z
.array(z.object({
timestampMs: z.number().optional(),
datetime: z.string().optional(),
sensorUuid: z.string().optional(),
count: z.number().optional(),
}))
.optional()
.describe("Occupancy sensor events"),
proximityEvents: z
.array(z.object({
timestampMs: z.number().optional(),
datetime: z.string().optional(),
tagUuid: z.string().optional(),
rssi: z.number().optional(),
}))
.optional()
.describe("Proximity tag events"),
doorbellEvents: z
.array(z.object({
timestampMs: z.number().optional(),
datetime: z.string().optional(),
doorbellCameraUuid: z.string().optional(),
eventType: z.string().optional(),
}))
.optional()
.describe("Doorbell camera events"),
needUserInput: z.boolean().optional(),
commandForUser: z.string().optional(),
});