dt-common-device 3.1.5 → 4.0.0
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/alerts/Alert.service.d.ts +7 -3
- package/dist/alerts/Alert.service.js +10 -4
- package/dist/device/local/services/Device.service.d.ts +8 -6
- package/dist/device/local/services/Device.service.js +49 -27
- package/dist/events/BaseEventHandler.d.ts +2 -1
- package/dist/events/BaseEventHandler.js +3 -2
- package/dist/events/BaseEventTransformer.d.ts +2 -2
- package/dist/events/BaseEventTransformer.js +2 -2
- package/dist/events/DeviceEventHandler.d.ts +1 -6
- package/dist/events/DeviceEventHandler.js +14 -75
- package/dist/events/DeviceEventTransformerFactory.js +2 -2
- package/dist/events/EventHandler.d.ts +7 -6
- package/dist/events/EventHandler.js +17 -62
- package/dist/events/EventProcessingService.d.ts +1 -1
- package/dist/events/EventProcessingService.js +5 -5
- package/dist/events/interfaces/DeviceEvent.d.ts +8 -4
- package/dist/events/interfaces/IEventTransformer.d.ts +2 -2
- package/dist/issues/Issue.service.d.ts +5 -1
- package/dist/issues/Issue.service.js +7 -1
- package/dist/queue/utils/queueUtils.js +1 -1
- package/dist/utils/redis.utils.d.ts +59 -0
- package/dist/utils/redis.utils.js +75 -20
- package/package.json +1 -1
|
@@ -32,17 +32,21 @@ export declare class AlertService {
|
|
|
32
32
|
*/
|
|
33
33
|
raiseHubAlert(hubId: string, propertyId: string, title: string, description: string, category?: AlertCategory | AlertCategory[], severity?: AlertSeverity, createdBy?: string): Promise<IAlertDocument>;
|
|
34
34
|
/**
|
|
35
|
-
* Raise alert for device going offline
|
|
35
|
+
* Raise alert for device going offline (OPERATIONAL only)
|
|
36
36
|
*/
|
|
37
37
|
raiseDeviceOfflineAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument>;
|
|
38
38
|
/**
|
|
39
|
-
* Raise alert for device coming online
|
|
39
|
+
* Raise alert for device coming online (OPERATIONAL only)
|
|
40
40
|
*/
|
|
41
41
|
raiseDeviceOnlineAlert(device: IDevice, source: Source, reason?: string): Promise<IAlertDocument>;
|
|
42
42
|
/**
|
|
43
|
-
* Raise alert for device battery level below threshold
|
|
43
|
+
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
44
44
|
*/
|
|
45
45
|
raiseDeviceBatteryAlert(device: IDevice, batteryLevel: number, threshold: number, source: Source): Promise<IAlertDocument>;
|
|
46
|
+
/**
|
|
47
|
+
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
|
|
48
|
+
*/
|
|
49
|
+
raiseDeviceIssueAlert(device: IDevice, issueType: string, source: Source, reason?: string): Promise<IAlertDocument>;
|
|
46
50
|
/**
|
|
47
51
|
* Create a new alert with business logic validation
|
|
48
52
|
* Accepts either a CreateAlertData object or an AlertBuilder instance
|
|
@@ -147,22 +147,28 @@ let AlertService = (() => {
|
|
|
147
147
|
return await this.createAlert(alertBuilder);
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
150
|
-
* Raise alert for device going offline
|
|
150
|
+
* Raise alert for device going offline (OPERATIONAL only)
|
|
151
151
|
*/
|
|
152
152
|
async raiseDeviceOfflineAlert(device, source, reason) {
|
|
153
153
|
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Offline", `Device ${device.name} (${device.deviceId}) has gone offline. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
* Raise alert for device coming online
|
|
156
|
+
* Raise alert for device coming online (OPERATIONAL only)
|
|
157
157
|
*/
|
|
158
158
|
async raiseDeviceOnlineAlert(device, source, reason) {
|
|
159
159
|
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Online", `Device ${device.name} (${device.deviceId}) is now online. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.INFO, source);
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
162
|
-
* Raise alert for device battery level below threshold
|
|
162
|
+
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
163
163
|
*/
|
|
164
164
|
async raiseDeviceBatteryAlert(device, batteryLevel, threshold, source) {
|
|
165
|
-
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Battery Low", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`, [alert_types_1.AlertCategory.ENERGY], alert_types_1.AlertSeverity.MEDIUM, source);
|
|
165
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Battery Low", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS, alert_types_1.AlertCategory.ENERGY], alert_types_1.AlertSeverity.MEDIUM, source);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
|
|
169
|
+
*/
|
|
170
|
+
async raiseDeviceIssueAlert(device, issueType, source, reason) {
|
|
171
|
+
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, `Device Issue - ${issueType}`, `Device ${device.name} (${device.deviceId}) has an issue: ${issueType}. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
|
|
166
172
|
}
|
|
167
173
|
/**
|
|
168
174
|
* Create a new alert with business logic validation
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IDevice, IStatus } from "../interfaces";
|
|
2
2
|
import { Source } from "../../../constants/Service";
|
|
3
|
+
import { AuditProperties } from "../../../audit/AuditProperties";
|
|
3
4
|
export declare class LocalDeviceService {
|
|
4
5
|
private readonly eventHandler;
|
|
5
6
|
private readonly deviceRepository;
|
|
@@ -12,21 +13,22 @@ export declare class LocalDeviceService {
|
|
|
12
13
|
getDevices(deviceIds: string[], withHubDetails?: boolean): Promise<IDevice[]>;
|
|
13
14
|
getPropertyDevices(propertyId: string, selectDeviceId?: boolean, type?: string, withHubDetails?: boolean): Promise<IDevice[]>;
|
|
14
15
|
getPropertyDeviceIds(propertyId: string, selectDeviceId: boolean | undefined, type: string): Promise<any>;
|
|
15
|
-
updateDevice(deviceId: string, body: any): Promise<any>;
|
|
16
|
-
deleteDevice(deviceId: string): Promise<any>;
|
|
16
|
+
updateDevice(deviceId: string, body: any, auditBody: AuditProperties): Promise<any>;
|
|
17
|
+
deleteDevice(deviceId: string, auditBody: AuditProperties): Promise<any>;
|
|
17
18
|
getState(deviceId: string): Promise<any>;
|
|
18
|
-
setState(deviceId: string, newState: any): Promise<void>;
|
|
19
|
+
setState(deviceId: string, newState: any, auditProperties: AuditProperties): Promise<void>;
|
|
19
20
|
getStatus(deviceId: string): Promise<Record<string, any>>;
|
|
20
|
-
setStatus(deviceId: string, newStatus: IStatus, source: Source, reason?: string): Promise<void>;
|
|
21
|
+
setStatus(deviceId: string, newStatus: IStatus, source: Source, auditBody: AuditProperties, reason?: string): Promise<void>;
|
|
21
22
|
private handleOfflineStatus;
|
|
22
23
|
private handleOnlineStatus;
|
|
23
24
|
private getDeviceBaseline;
|
|
24
25
|
getBatteryLevel(deviceId: string): Promise<Record<string, any>>;
|
|
25
|
-
setBatteryLevel(deviceId: string, batteryLevel: number, source: Source): Promise<void>;
|
|
26
|
+
setBatteryLevel(deviceId: string, batteryLevel: number, source: Source, auditBody: AuditProperties): Promise<void>;
|
|
26
27
|
private shouldUpdateBatteryLevel;
|
|
27
28
|
private getPropertyBatteryThreshold;
|
|
29
|
+
private checkForDeviceMalfunctions;
|
|
28
30
|
getMetaData(deviceId: string): Promise<any>;
|
|
29
|
-
setMetaData(deviceId: string, metaData: Record<string, any
|
|
31
|
+
setMetaData(deviceId: string, metaData: Record<string, any>, auditBody: AuditProperties): Promise<any>;
|
|
30
32
|
getDevicesByZone(zoneId: string): Promise<import("../interfaces").IDtDevice[]>;
|
|
31
33
|
getDevicesByAccessGroup(accessGroupId: string): Promise<import("../interfaces").IDtDevice[]>;
|
|
32
34
|
querySelect(query: any, fields: string[]): Promise<any>;
|
|
@@ -93,19 +93,19 @@ let LocalDeviceService = (() => {
|
|
|
93
93
|
}
|
|
94
94
|
return await this.deviceRepository.getPropertyDeviceIds(propertyId, selectDeviceId, type);
|
|
95
95
|
}
|
|
96
|
-
async updateDevice(deviceId, body) {
|
|
96
|
+
async updateDevice(deviceId, body, auditBody) {
|
|
97
97
|
if (!deviceId) {
|
|
98
98
|
throw new Error("Device ID is required");
|
|
99
99
|
}
|
|
100
100
|
await this.deviceRepository.updateDevice(deviceId, body);
|
|
101
|
-
return await this.eventHandler.onDeviceUpdate(deviceId, body);
|
|
101
|
+
return await this.eventHandler.onDeviceUpdate(deviceId, body, auditBody);
|
|
102
102
|
}
|
|
103
|
-
async deleteDevice(deviceId) {
|
|
103
|
+
async deleteDevice(deviceId, auditBody) {
|
|
104
104
|
if (!deviceId) {
|
|
105
105
|
throw new Error("Device ID is required");
|
|
106
106
|
}
|
|
107
107
|
await this.deviceRepository.deleteDevice(deviceId);
|
|
108
|
-
return await this.eventHandler.onDeviceDelete(deviceId);
|
|
108
|
+
return await this.eventHandler.onDeviceDelete(deviceId, auditBody);
|
|
109
109
|
}
|
|
110
110
|
async getState(deviceId) {
|
|
111
111
|
if (!deviceId) {
|
|
@@ -113,7 +113,7 @@ let LocalDeviceService = (() => {
|
|
|
113
113
|
}
|
|
114
114
|
return await this.deviceRepository.getState(deviceId);
|
|
115
115
|
}
|
|
116
|
-
async setState(deviceId, newState) {
|
|
116
|
+
async setState(deviceId, newState, auditProperties) {
|
|
117
117
|
if (!deviceId || !newState) {
|
|
118
118
|
throw new Error("Device ID and new state are required");
|
|
119
119
|
}
|
|
@@ -122,7 +122,7 @@ let LocalDeviceService = (() => {
|
|
|
122
122
|
const changedKeys = Object.keys(newState).filter((key) => !(0, lodash_1.isEqual)(oldState[key], newState[key]));
|
|
123
123
|
if (changedKeys.length > 0) {
|
|
124
124
|
await this.deviceRepository.setState(deviceId, newState);
|
|
125
|
-
return await this.eventHandler.onStateChange(deviceId, newState);
|
|
125
|
+
return await this.eventHandler.onStateChange(deviceId, newState, auditProperties);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
async getStatus(deviceId) {
|
|
@@ -131,7 +131,7 @@ let LocalDeviceService = (() => {
|
|
|
131
131
|
}
|
|
132
132
|
return await this.deviceRepository.getStatus(deviceId);
|
|
133
133
|
}
|
|
134
|
-
async setStatus(deviceId, newStatus, source, reason) {
|
|
134
|
+
async setStatus(deviceId, newStatus, source, auditBody, reason) {
|
|
135
135
|
if (!deviceId || !newStatus) {
|
|
136
136
|
throw new Error("Device ID and new status are required");
|
|
137
137
|
}
|
|
@@ -143,19 +143,19 @@ let LocalDeviceService = (() => {
|
|
|
143
143
|
const isNewStatusOffline = newStatus.liveStatus === "OFFLINE";
|
|
144
144
|
if (isNewStatusOffline) {
|
|
145
145
|
// New Status = OFFLINE
|
|
146
|
-
await this.handleOfflineStatus(
|
|
146
|
+
await this.handleOfflineStatus(device, oldStatus, newStatus, source, auditBody, reason, currentTime);
|
|
147
147
|
}
|
|
148
148
|
else if (isNewStatusOnline) {
|
|
149
149
|
// New Status = ONLINE
|
|
150
|
-
await this.handleOnlineStatus(
|
|
150
|
+
await this.handleOnlineStatus(device, oldStatus, newStatus, source, auditBody, reason, currentTime);
|
|
151
151
|
}
|
|
152
152
|
else {
|
|
153
153
|
// For any other status, just update normally
|
|
154
154
|
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
155
|
-
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
155
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus, auditBody);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
async handleOfflineStatus(
|
|
158
|
+
async handleOfflineStatus(device, oldStatus, newStatus, source, auditBody, reason, currentTime) {
|
|
159
159
|
const isExistingStatusOnline = oldStatus?.online === true;
|
|
160
160
|
const isExistingStatusOffline = oldStatus?.online === false;
|
|
161
161
|
if (isExistingStatusOnline) {
|
|
@@ -168,15 +168,15 @@ let LocalDeviceService = (() => {
|
|
|
168
168
|
message: reason || "Device went offline",
|
|
169
169
|
default: {},
|
|
170
170
|
};
|
|
171
|
-
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
172
|
-
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
171
|
+
await this.deviceRepository.setStatus(device.deviceId, newStatus);
|
|
172
|
+
await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody);
|
|
173
173
|
}
|
|
174
174
|
else if (isExistingStatusOffline) {
|
|
175
175
|
// Existing status is Offline
|
|
176
176
|
const timeLapsed = oldStatus?.lastUpdated
|
|
177
177
|
? Date.now() - new Date(oldStatus.lastUpdated).getTime()
|
|
178
178
|
: 0;
|
|
179
|
-
const baselineTime = await this.getDeviceBaseline(deviceId);
|
|
179
|
+
const baselineTime = await this.getDeviceBaseline(device.deviceId);
|
|
180
180
|
if (timeLapsed > baselineTime) {
|
|
181
181
|
// When the time lapsed is higher than the baseline time
|
|
182
182
|
newStatus.online = false;
|
|
@@ -187,16 +187,16 @@ let LocalDeviceService = (() => {
|
|
|
187
187
|
message: reason || "Device has been offline for longer than baseline",
|
|
188
188
|
default: {},
|
|
189
189
|
};
|
|
190
|
-
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
191
|
-
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
192
|
-
// Raise alert
|
|
190
|
+
await this.deviceRepository.setStatus(device.deviceId, newStatus);
|
|
191
|
+
await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody);
|
|
192
|
+
// Raise alert (OPERATIONAL only)
|
|
193
193
|
await this.alertService.raiseDeviceOfflineAlert(device, source, reason);
|
|
194
|
-
// Raise issue when the device goes offline if longer than the baseline
|
|
194
|
+
// Raise issue when the device goes offline if longer than the baseline (OPERATIONAL only)
|
|
195
195
|
await this.issueService.createDeviceOfflineIssue(device, source, reason);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
-
async handleOnlineStatus(
|
|
199
|
+
async handleOnlineStatus(device, oldStatus, newStatus, source, auditBody, reason, currentTime) {
|
|
200
200
|
const isExistingStatusOnline = oldStatus?.online === true;
|
|
201
201
|
const isExistingStatusOffline = oldStatus?.online === false;
|
|
202
202
|
if (isExistingStatusOnline) {
|
|
@@ -211,8 +211,8 @@ let LocalDeviceService = (() => {
|
|
|
211
211
|
newStatus.liveStatus = "ONLINE";
|
|
212
212
|
newStatus.lastUpdated = currentTime;
|
|
213
213
|
newStatus.error = {}; // Clear the error
|
|
214
|
-
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
215
|
-
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
214
|
+
await this.deviceRepository.setStatus(device.deviceId, newStatus);
|
|
215
|
+
await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody);
|
|
216
216
|
//TODO: ALERT NEEDED?
|
|
217
217
|
// Raise alert
|
|
218
218
|
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
@@ -224,8 +224,8 @@ let LocalDeviceService = (() => {
|
|
|
224
224
|
newStatus.liveStatus = "ONLINE";
|
|
225
225
|
newStatus.lastUpdated = currentTime;
|
|
226
226
|
newStatus.error = undefined; // Clear the error
|
|
227
|
-
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
228
|
-
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
227
|
+
await this.deviceRepository.setStatus(device.deviceId, newStatus);
|
|
228
|
+
await this.eventHandler.onStatusChange(device.deviceId, newStatus, auditBody);
|
|
229
229
|
//TODO: ALERT NEEDED?
|
|
230
230
|
// Raise alert
|
|
231
231
|
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
@@ -244,7 +244,7 @@ let LocalDeviceService = (() => {
|
|
|
244
244
|
}
|
|
245
245
|
return await this.deviceRepository.getBatteryLevel(deviceId);
|
|
246
246
|
}
|
|
247
|
-
async setBatteryLevel(deviceId, batteryLevel, source) {
|
|
247
|
+
async setBatteryLevel(deviceId, batteryLevel, source, auditBody) {
|
|
248
248
|
if (!deviceId || batteryLevel === undefined || batteryLevel === null) {
|
|
249
249
|
throw new Error("Device ID and battery level are required");
|
|
250
250
|
}
|
|
@@ -260,7 +260,7 @@ let LocalDeviceService = (() => {
|
|
|
260
260
|
if (shouldUpdate) {
|
|
261
261
|
// Save the battery level in the device
|
|
262
262
|
await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
|
|
263
|
-
await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel);
|
|
263
|
+
await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel, auditBody);
|
|
264
264
|
// Get property threshold
|
|
265
265
|
const propertyThreshold = await this.getPropertyBatteryThreshold(device.propertyId);
|
|
266
266
|
// Check if battery level is below threshold
|
|
@@ -290,17 +290,39 @@ let LocalDeviceService = (() => {
|
|
|
290
290
|
// In a real implementation, this would fetch from property configuration or settings
|
|
291
291
|
return 20; // 20% default threshold
|
|
292
292
|
}
|
|
293
|
+
async checkForDeviceMalfunctions(device, source, reason) {
|
|
294
|
+
// TODO: Implement device malfunction detection logic
|
|
295
|
+
// This should check for:
|
|
296
|
+
// - Lock jammed
|
|
297
|
+
// - Device not accepting codes
|
|
298
|
+
// - Other malfunction indicators
|
|
299
|
+
// For now, we'll check if the reason indicates a malfunction
|
|
300
|
+
const malfunctionIndicators = [
|
|
301
|
+
"jammed",
|
|
302
|
+
"not accepting codes",
|
|
303
|
+
"malfunction",
|
|
304
|
+
"error",
|
|
305
|
+
"failure",
|
|
306
|
+
];
|
|
307
|
+
const hasMalfunction = malfunctionIndicators.some((indicator) => reason?.toLowerCase().includes(indicator));
|
|
308
|
+
if (hasMalfunction) {
|
|
309
|
+
// Raise alert for device malfunction (READINESS + OPERATIONAL)
|
|
310
|
+
await this.alertService.raiseDeviceIssueAlert(device, "Device Malfunction Detected", source, reason);
|
|
311
|
+
// Raise issue for device malfunction (READINESS + OPERATIONAL)
|
|
312
|
+
await this.issueService.createDeviceMalfunctionIssue(device, "Device Malfunction", source, reason);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
293
315
|
async getMetaData(deviceId) {
|
|
294
316
|
if (!deviceId) {
|
|
295
317
|
throw new Error("Device ID is required");
|
|
296
318
|
}
|
|
297
319
|
return await this.deviceRepository.getMetaData(deviceId);
|
|
298
320
|
}
|
|
299
|
-
async setMetaData(deviceId, metaData) {
|
|
321
|
+
async setMetaData(deviceId, metaData, auditBody) {
|
|
300
322
|
if (!deviceId || !metaData) {
|
|
301
323
|
throw new Error("Device ID and meta data are required");
|
|
302
324
|
}
|
|
303
|
-
await this.eventHandler.onDeviceMetaChange(deviceId, metaData);
|
|
325
|
+
await this.eventHandler.onDeviceMetaChange(deviceId, metaData, auditBody);
|
|
304
326
|
return await this.deviceRepository.setMetaData(deviceId, metaData);
|
|
305
327
|
}
|
|
306
328
|
async getDevicesByZone(zoneId) {
|
|
@@ -2,6 +2,7 @@ import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
3
|
import { ILogger } from "../config/config.types";
|
|
4
4
|
import { LocalDeviceService } from "../device/local/services/Device.service";
|
|
5
|
+
import { AuditProperties } from "../audit/AuditProperties";
|
|
5
6
|
export declare abstract class BaseEventHandler implements IEventHandler {
|
|
6
7
|
protected readonly supportedEventTypes: string[];
|
|
7
8
|
protected readonly priority: number;
|
|
@@ -19,7 +20,7 @@ export declare abstract class BaseEventHandler implements IEventHandler {
|
|
|
19
20
|
* Handle multiple events - default implementation processes them sequentially
|
|
20
21
|
*/
|
|
21
22
|
handleEvents(events: DeviceEvent[]): Promise<void>;
|
|
22
|
-
onStateChange(deviceId: string, state: Record<string, any>, event: DeviceEvent): Promise<void>;
|
|
23
|
+
onStateChange(deviceId: string, state: Record<string, any>, event: DeviceEvent, auditProperties: AuditProperties): Promise<void>;
|
|
23
24
|
/**
|
|
24
25
|
* Check if this handler can process the given event type
|
|
25
26
|
*/
|
|
@@ -65,9 +65,10 @@ class BaseEventHandler {
|
|
|
65
65
|
this.logger.error(`${this.constructor.name}: handleEvents Error`, error);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
// TODO: Check AuditBody for this function
|
|
69
|
+
async onStateChange(deviceId, state, event, auditProperties) {
|
|
69
70
|
try {
|
|
70
|
-
await this.localDeviceService.setState(deviceId, state);
|
|
71
|
+
await this.localDeviceService.setState(deviceId, state, auditProperties);
|
|
71
72
|
await this.afterEvent(event);
|
|
72
73
|
}
|
|
73
74
|
catch (error) {
|
|
@@ -10,7 +10,7 @@ export declare abstract class BaseEventTransformer implements IEventTransformer
|
|
|
10
10
|
/**
|
|
11
11
|
* Transform parsed data into DeviceEvent format - to be implemented by device-specific transformers
|
|
12
12
|
*/
|
|
13
|
-
abstract transform(parsedData: any): DeviceEvent | DeviceEvent[]
|
|
13
|
+
abstract transform(parsedData: any): Promise<DeviceEvent | DeviceEvent[]>;
|
|
14
14
|
/**
|
|
15
15
|
* Validate transformed event - default implementation, can be overridden
|
|
16
16
|
*/
|
|
@@ -22,5 +22,5 @@ export declare abstract class BaseEventTransformer implements IEventTransformer
|
|
|
22
22
|
/**
|
|
23
23
|
* Execute the full transformation pipeline
|
|
24
24
|
*/
|
|
25
|
-
executeTransformation(): DeviceEvent[]
|
|
25
|
+
executeTransformation(): Promise<DeviceEvent[]>;
|
|
26
26
|
}
|
|
@@ -46,13 +46,13 @@ class BaseEventTransformer {
|
|
|
46
46
|
/**
|
|
47
47
|
* Execute the full transformation pipeline
|
|
48
48
|
*/
|
|
49
|
-
executeTransformation() {
|
|
49
|
+
async executeTransformation() {
|
|
50
50
|
try {
|
|
51
51
|
this.logger.info(`Starting transformation for device type: ${this.deviceType}`);
|
|
52
52
|
// Step 1: Parse the raw data
|
|
53
53
|
const parsedData = this.parseData(this.rawData);
|
|
54
54
|
// Step 2: Transform to DeviceEvent format
|
|
55
|
-
const transformedResult = this.transform(parsedData);
|
|
55
|
+
const transformedResult = await this.transform(parsedData);
|
|
56
56
|
// Step 3: Convert to array format
|
|
57
57
|
// TODO: Check if any service sends multiple events
|
|
58
58
|
const events = Array.isArray(transformedResult)
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { IDevice } from "../device/local/interfaces";
|
|
2
2
|
import { BaseEventHandler } from "./BaseEventHandler";
|
|
3
|
-
import { DeviceEvent
|
|
3
|
+
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
4
4
|
export declare class DeviceEventHandler extends BaseEventHandler {
|
|
5
5
|
private readonly localHubService;
|
|
6
6
|
constructor();
|
|
7
7
|
onEvent(event: DeviceEvent): Promise<void>;
|
|
8
8
|
updateDeviceEventData(deviceData: IDevice, event: DeviceEvent): Promise<void>;
|
|
9
9
|
extractHubDetails(device: IDevice): Promise<any[]>;
|
|
10
|
-
constructDeviceEventEntity(eventData: any, device: IDevice, hubDetails: any[], options?: EventConstructionOptions): DeviceEventEntity;
|
|
11
|
-
dumpToEventOperation(data: any, device: IDevice): Promise<void>;
|
|
12
|
-
updateTablesBasedOnEventType(eventData: any, device: IDevice): Promise<void>;
|
|
13
|
-
updateDeviceStatus(data: any, device: IDevice): Promise<void>;
|
|
14
|
-
updateDeviceBattery(data: any, device: IDevice): Promise<void>;
|
|
15
10
|
}
|
|
@@ -92,6 +92,8 @@ let DeviceEventHandler = (() => {
|
|
|
92
92
|
Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CRITICAL,
|
|
93
93
|
Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.LOW,
|
|
94
94
|
Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CHANGED,
|
|
95
|
+
Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.UPDATED,
|
|
96
|
+
Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.UNKNOWN,
|
|
95
97
|
], 100);
|
|
96
98
|
// Use dependency injection instead of creating new instance
|
|
97
99
|
this.localHubService = typedi_1.default.get(services_1.LocalHubService);
|
|
@@ -106,13 +108,9 @@ let DeviceEventHandler = (() => {
|
|
|
106
108
|
throw new Error("[DT | CDL]:[DeviceEventHandler]: deviceId does not exist");
|
|
107
109
|
}
|
|
108
110
|
await this.updateDeviceEventData(device, event);
|
|
109
|
-
// Update relevant tables based on event type
|
|
110
|
-
await this.updateTablesBasedOnEventType(event, device);
|
|
111
|
-
// Save event logs
|
|
112
|
-
await this.dumpToEventOperation(event, device);
|
|
113
111
|
}
|
|
114
112
|
catch (error) {
|
|
115
|
-
this.logger.error(
|
|
113
|
+
this.logger.error(`[DT | CDL]:[DeviceEventHandler]: Error processing event: ${event.eventName} ERROR: ${error}`);
|
|
116
114
|
throw error;
|
|
117
115
|
}
|
|
118
116
|
}
|
|
@@ -134,10 +132,20 @@ let DeviceEventHandler = (() => {
|
|
|
134
132
|
default: {},
|
|
135
133
|
},
|
|
136
134
|
},
|
|
135
|
+
}, {
|
|
136
|
+
deviceId: deviceData.deviceId,
|
|
137
|
+
deviceName: deviceData.name,
|
|
138
|
+
propertyId: deviceData.propertyId,
|
|
139
|
+
resource: "device",
|
|
137
140
|
});
|
|
138
141
|
break;
|
|
139
142
|
case Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CHANGED:
|
|
140
|
-
await this.localDeviceService.setBatteryLevel(deviceData.deviceId, event?.data?.batteryLevel ?? 0, constants_1.Source.CLOUD_EVENT
|
|
143
|
+
await this.localDeviceService.setBatteryLevel(deviceData.deviceId, event?.data?.batteryLevel ?? 0, constants_1.Source.CLOUD_EVENT, {
|
|
144
|
+
deviceId: deviceData.deviceId,
|
|
145
|
+
deviceName: deviceData.name,
|
|
146
|
+
propertyId: deviceData.propertyId,
|
|
147
|
+
resource: "device",
|
|
148
|
+
});
|
|
141
149
|
break;
|
|
142
150
|
}
|
|
143
151
|
}
|
|
@@ -159,75 +167,6 @@ let DeviceEventHandler = (() => {
|
|
|
159
167
|
}
|
|
160
168
|
return hubDetails;
|
|
161
169
|
}
|
|
162
|
-
constructDeviceEventEntity(eventData, device, hubDetails, options = {}) {
|
|
163
|
-
return {
|
|
164
|
-
event: {
|
|
165
|
-
eventId: options.eventId || eventData?.eventId || "",
|
|
166
|
-
eventName: options.eventName || eventData?.eventName || "",
|
|
167
|
-
status: options.status || eventData?.status || "",
|
|
168
|
-
mode: options.mode || eventData?.data?.mode,
|
|
169
|
-
userName: options.userName || eventData?.userName || "",
|
|
170
|
-
userId: options.userId || eventData?.userId || "",
|
|
171
|
-
userType: options.userType || eventData?.userType || "",
|
|
172
|
-
raw_event: options.rawEvent || eventData?.rawData || {},
|
|
173
|
-
batteryLevel: options.batteryLevel || eventData?.data?.batteryLevel || "",
|
|
174
|
-
reason: options.reason || eventData?.data?.reason || "",
|
|
175
|
-
eventDescription: options.eventDescription || eventData?.event || "",
|
|
176
|
-
},
|
|
177
|
-
device: {
|
|
178
|
-
id: eventData?.deviceId || "",
|
|
179
|
-
name: device?.name || "",
|
|
180
|
-
type: device?.deviceType?.type || "",
|
|
181
|
-
brand: device?.specifications?.manufacturer || "",
|
|
182
|
-
model: device?.specifications?.model || "",
|
|
183
|
-
},
|
|
184
|
-
hub: hubDetails,
|
|
185
|
-
property: {
|
|
186
|
-
id: eventData?.property?.id || "",
|
|
187
|
-
name: eventData?.property?.name || "",
|
|
188
|
-
location: eventData?.property?.apartment || "",
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
async dumpToEventOperation(data, device) {
|
|
193
|
-
try {
|
|
194
|
-
const hubDetails = await this.extractHubDetails(device);
|
|
195
|
-
const eventData = this.constructDeviceEventEntity(data, device, hubDetails, {
|
|
196
|
-
status: data.eventName === "lock.unlock" ? "UNLOCKED" : "LOCKED",
|
|
197
|
-
rawEvent: data.rawData,
|
|
198
|
-
});
|
|
199
|
-
this.logger.info("[DT | CDL]:[DeviceEventHandler]: Event data dumped to event operation", { eventData });
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
this.logger.error("[DT | CDL]:[DeviceEventHandler]: Error dumping to event operation", error);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
async updateTablesBasedOnEventType(eventData, device) {
|
|
206
|
-
switch (eventData.eventName) {
|
|
207
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.STATUS.ONLINE:
|
|
208
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.STATUS.OFFLINE:
|
|
209
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.STATUS.CHANGED:
|
|
210
|
-
this.updateDeviceStatus(eventData, device);
|
|
211
|
-
break;
|
|
212
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CHANGED:
|
|
213
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.CRITICAL:
|
|
214
|
-
case Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.LOW:
|
|
215
|
-
this.updateDeviceBattery(eventData, device);
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
async updateDeviceStatus(data, device) {
|
|
220
|
-
this.logger.info("[DT | CDL]:[DeviceEventHandler]: Updating device status", {
|
|
221
|
-
data,
|
|
222
|
-
device,
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
async updateDeviceBattery(data, device) {
|
|
226
|
-
this.logger.info("[DT | CDL]:[DeviceEventHandler]: Updating device battery", {
|
|
227
|
-
data,
|
|
228
|
-
device,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
170
|
};
|
|
232
171
|
__setFunctionName(_classThis, "DeviceEventHandler");
|
|
233
172
|
(() => {
|
|
@@ -72,10 +72,10 @@ let DeviceEventTransformerFactory = (() => {
|
|
|
72
72
|
// Default validation - always return true
|
|
73
73
|
return true;
|
|
74
74
|
}
|
|
75
|
-
executeTransformation() {
|
|
75
|
+
async executeTransformation() {
|
|
76
76
|
try {
|
|
77
77
|
const parsedData = this.parseData(this.rawData);
|
|
78
|
-
const transformedResult = this.transform(parsedData);
|
|
78
|
+
const transformedResult = await this.transform(parsedData);
|
|
79
79
|
const events = Array.isArray(transformedResult) ? transformedResult : [transformedResult];
|
|
80
80
|
return events.filter((event) => this.validate(event));
|
|
81
81
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { AuditProperties } from "../audit/AuditProperties";
|
|
1
2
|
export declare class EventHandler {
|
|
2
3
|
private readonly source;
|
|
3
4
|
constructor();
|
|
4
5
|
onDeviceCreate(body: any): Promise<void>;
|
|
5
|
-
onDeviceUpdate(deviceId: string, body: any): Promise<void>;
|
|
6
|
-
onDeviceDelete(deviceId: string): Promise<void>;
|
|
7
|
-
onStateChange(deviceId: string, state: any): Promise<void>;
|
|
8
|
-
onStatusChange(deviceId: string, status: any): Promise<void>;
|
|
9
|
-
onBatteryLevelChange(deviceId: string, batteryLevel: number): Promise<void>;
|
|
10
|
-
onDeviceMetaChange(deviceId: string, metaData: Record<string, any
|
|
6
|
+
onDeviceUpdate(deviceId: string, body: any, auditBody: AuditProperties): Promise<void>;
|
|
7
|
+
onDeviceDelete(deviceId: string, auditBody: AuditProperties): Promise<void>;
|
|
8
|
+
onStateChange(deviceId: string, state: any, auditProperties: AuditProperties): Promise<void>;
|
|
9
|
+
onStatusChange(deviceId: string, status: any, auditProperties: AuditProperties): Promise<void>;
|
|
10
|
+
onBatteryLevelChange(deviceId: string, batteryLevel: number, auditProperties: AuditProperties): Promise<void>;
|
|
11
|
+
onDeviceMetaChange(deviceId: string, metaData: Record<string, any>, auditProperties: AuditProperties): Promise<void>;
|
|
11
12
|
}
|
|
@@ -39,10 +39,11 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
39
39
|
};
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
41
|
exports.EventHandler = void 0;
|
|
42
|
-
const dt_pub_sub_1 = require("dt-pub-sub");
|
|
43
42
|
const dt_audit_library_1 = require("dt-audit-library");
|
|
44
43
|
const Event_1 = require("../constants/Event");
|
|
45
44
|
const typedi_1 = require("typedi");
|
|
45
|
+
const AuditUtils_1 = require("../audit/AuditUtils");
|
|
46
|
+
// TODO: For all the Event handlers, we need to publish the respective events for External Consumption
|
|
46
47
|
let EventHandler = (() => {
|
|
47
48
|
let _classDecorators = [(0, typedi_1.Service)()];
|
|
48
49
|
let _classDescriptor;
|
|
@@ -53,101 +54,55 @@ let EventHandler = (() => {
|
|
|
53
54
|
this.source = "dt-common-device";
|
|
54
55
|
}
|
|
55
56
|
async onDeviceCreate(body) {
|
|
56
|
-
// TODO: For Future Consumption
|
|
57
|
-
// await eventDispatcher.publishEvent(
|
|
58
|
-
// DT_EVENT_TYPES.DEVICE.CREATE.SUCCESS,
|
|
59
|
-
// body,
|
|
60
|
-
// this.source
|
|
61
|
-
// );
|
|
62
57
|
const payload = {
|
|
63
58
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.CREATE.SUCCESS,
|
|
64
|
-
properties:
|
|
65
|
-
...body,
|
|
66
|
-
},
|
|
59
|
+
properties: (0, AuditUtils_1.buildAuditProperties)(body),
|
|
67
60
|
};
|
|
68
61
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
69
62
|
}
|
|
70
|
-
async onDeviceUpdate(deviceId, body) {
|
|
71
|
-
await dt_pub_sub_1.eventDispatcher.publishEvent(Event_1.DT_EVENT_TYPES.DEVICE.UPDATE.SUCCESS, { deviceId, body }, this.source);
|
|
63
|
+
async onDeviceUpdate(deviceId, body, auditBody) {
|
|
72
64
|
const payload = {
|
|
73
65
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.UPDATE.SUCCESS,
|
|
74
|
-
properties: {
|
|
75
|
-
...body,
|
|
76
|
-
},
|
|
66
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({ ...auditBody, deviceId, ...body }),
|
|
77
67
|
};
|
|
78
68
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
79
69
|
}
|
|
80
|
-
async onDeviceDelete(deviceId) {
|
|
81
|
-
await dt_pub_sub_1.eventDispatcher.publishEvent(Event_1.DT_EVENT_TYPES.DEVICE.DELETE.SUCCESS, { deviceId }, this.source);
|
|
70
|
+
async onDeviceDelete(deviceId, auditBody) {
|
|
82
71
|
const payload = {
|
|
83
72
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.DELETE.SUCCESS,
|
|
84
|
-
properties: {
|
|
85
|
-
deviceId,
|
|
86
|
-
},
|
|
73
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({ ...auditBody, deviceId }),
|
|
87
74
|
};
|
|
88
75
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
89
76
|
}
|
|
90
|
-
async onStateChange(deviceId, state) {
|
|
91
|
-
// TODO: For Future Consumption
|
|
92
|
-
/* await eventDispatcher.publishEvent(
|
|
93
|
-
DT_EVENT_TYPES.DEVICE.STATE.SET,
|
|
94
|
-
{ deviceId, state },
|
|
95
|
-
this.source
|
|
96
|
-
); */
|
|
77
|
+
async onStateChange(deviceId, state, auditProperties) {
|
|
97
78
|
const payload = {
|
|
98
79
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.STATE.SET,
|
|
99
|
-
properties: {
|
|
100
|
-
deviceId,
|
|
101
|
-
state,
|
|
102
|
-
},
|
|
80
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({ ...auditProperties, deviceId, ...state }),
|
|
103
81
|
};
|
|
104
82
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
105
83
|
}
|
|
106
|
-
async onStatusChange(deviceId, status) {
|
|
107
|
-
// TODO: For Future Consumption
|
|
108
|
-
/* await eventDispatcher.publishEvent(
|
|
109
|
-
DT_EVENT_TYPES.DEVICE.STATUS.SET,
|
|
110
|
-
{ deviceId, status },
|
|
111
|
-
this.source
|
|
112
|
-
); */
|
|
84
|
+
async onStatusChange(deviceId, status, auditProperties) {
|
|
113
85
|
const payload = {
|
|
114
86
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.STATUS.SET,
|
|
115
|
-
properties: {
|
|
116
|
-
deviceId,
|
|
117
|
-
status,
|
|
118
|
-
},
|
|
87
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({ ...auditProperties, deviceId, ...status }),
|
|
119
88
|
};
|
|
120
89
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
121
90
|
}
|
|
122
|
-
async onBatteryLevelChange(deviceId, batteryLevel) {
|
|
123
|
-
// TODO: For Future Consumption
|
|
124
|
-
/* await eventDispatcher.publishEvent(
|
|
125
|
-
DT_EVENT_TYPES.DEVICE.BATTERY.SET,
|
|
126
|
-
{ deviceId, batteryLevel },
|
|
127
|
-
this.source
|
|
128
|
-
); */
|
|
91
|
+
async onBatteryLevelChange(deviceId, batteryLevel, auditProperties) {
|
|
129
92
|
const payload = {
|
|
130
93
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.BATTERY.SET,
|
|
131
|
-
properties: {
|
|
94
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({
|
|
95
|
+
...auditProperties,
|
|
132
96
|
deviceId,
|
|
133
97
|
batteryLevel,
|
|
134
|
-
},
|
|
98
|
+
}),
|
|
135
99
|
};
|
|
136
100
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
137
101
|
}
|
|
138
|
-
async onDeviceMetaChange(deviceId, metaData) {
|
|
139
|
-
// TODO: For Future Consumption
|
|
140
|
-
/* await eventDispatcher.publishEvent(
|
|
141
|
-
DT_EVENT_TYPES.DEVICE.META_DATA.SET,
|
|
142
|
-
{ deviceId, metaData },
|
|
143
|
-
this.source
|
|
144
|
-
); */
|
|
102
|
+
async onDeviceMetaChange(deviceId, metaData, auditProperties) {
|
|
145
103
|
const payload = {
|
|
146
104
|
eventType: Event_1.DT_EVENT_TYPES.DEVICE.META_DATA.SET,
|
|
147
|
-
properties: {
|
|
148
|
-
deviceId,
|
|
149
|
-
metaData,
|
|
150
|
-
},
|
|
105
|
+
properties: (0, AuditUtils_1.buildAuditProperties)({ ...auditProperties, deviceId, metaData }),
|
|
151
106
|
};
|
|
152
107
|
await (0, dt_audit_library_1.publishAudit)(payload);
|
|
153
108
|
}
|
|
@@ -23,7 +23,7 @@ export declare class EventProcessingService {
|
|
|
23
23
|
/**
|
|
24
24
|
* Transform device event using EventTransformerFactory
|
|
25
25
|
*/
|
|
26
|
-
transformDeviceEventWithTransformer(connectionProvider: string, rawData: any): DeviceEvent | null
|
|
26
|
+
transformDeviceEventWithTransformer(connectionProvider: string, rawData: any): Promise<DeviceEvent | null>;
|
|
27
27
|
/**
|
|
28
28
|
* Transform raw event data to DeviceEvent format using EventTransformer
|
|
29
29
|
*/
|
|
@@ -95,7 +95,7 @@ let EventProcessingService = (() => {
|
|
|
95
95
|
/**
|
|
96
96
|
* Transform device event using EventTransformerFactory
|
|
97
97
|
*/
|
|
98
|
-
transformDeviceEventWithTransformer(connectionProvider, rawData) {
|
|
98
|
+
async transformDeviceEventWithTransformer(connectionProvider, rawData) {
|
|
99
99
|
try {
|
|
100
100
|
// Create transformer for the connection provider
|
|
101
101
|
const transformer = this.deviceEventTransformerFactory.createTransformer(connectionProvider, rawData);
|
|
@@ -104,7 +104,7 @@ let EventProcessingService = (() => {
|
|
|
104
104
|
return null;
|
|
105
105
|
}
|
|
106
106
|
// Execute the transformation pipeline
|
|
107
|
-
const transformedEvents = transformer.executeTransformation();
|
|
107
|
+
const transformedEvents = await transformer.executeTransformation();
|
|
108
108
|
if (transformedEvents.length === 0) {
|
|
109
109
|
this.logger.warn(`No events transformed for connection provider: ${connectionProvider}`);
|
|
110
110
|
return null;
|
|
@@ -120,10 +120,10 @@ let EventProcessingService = (() => {
|
|
|
120
120
|
/**
|
|
121
121
|
* Transform raw event data to DeviceEvent format using EventTransformer
|
|
122
122
|
*/
|
|
123
|
-
transformToDeviceEvent(connectionProvider, rawData) {
|
|
123
|
+
async transformToDeviceEvent(connectionProvider, rawData) {
|
|
124
124
|
try {
|
|
125
125
|
// Use the transformer-based approach
|
|
126
|
-
const deviceEvent = this.transformDeviceEventWithTransformer(connectionProvider, rawData);
|
|
126
|
+
const deviceEvent = await this.transformDeviceEventWithTransformer(connectionProvider, rawData);
|
|
127
127
|
if (!deviceEvent) {
|
|
128
128
|
this.logger.warn("Failed to transform event data using transformer", {
|
|
129
129
|
connectionProvider,
|
|
@@ -154,7 +154,7 @@ let EventProcessingService = (() => {
|
|
|
154
154
|
eventName: rawData.eventName ?? rawData.type,
|
|
155
155
|
});
|
|
156
156
|
// Transform raw data to DeviceEvent using EventTransformer
|
|
157
|
-
const deviceEvent = this.transformToDeviceEvent(connectionProvider, rawData);
|
|
157
|
+
const deviceEvent = await this.transformToDeviceEvent(connectionProvider, rawData);
|
|
158
158
|
if (!deviceEvent) {
|
|
159
159
|
this.logger.warn("Failed to transform event data", {
|
|
160
160
|
connectionProvider,
|
|
@@ -3,10 +3,10 @@ export interface DeviceEvent {
|
|
|
3
3
|
deviceId: string;
|
|
4
4
|
eventName: string;
|
|
5
5
|
data: DeviceEventData;
|
|
6
|
-
timestamp
|
|
7
|
-
connectionProvider
|
|
8
|
-
originalEventName
|
|
9
|
-
rawEvent
|
|
6
|
+
timestamp: string;
|
|
7
|
+
connectionProvider: string;
|
|
8
|
+
originalEventName: string;
|
|
9
|
+
rawEvent: any;
|
|
10
10
|
}
|
|
11
11
|
export interface EventConstructionOptions {
|
|
12
12
|
eventId?: string;
|
|
@@ -30,6 +30,10 @@ export interface DeviceEventEntity {
|
|
|
30
30
|
export interface DeviceEventData {
|
|
31
31
|
mode?: string;
|
|
32
32
|
batteryLevel?: number;
|
|
33
|
+
deviceName?: string;
|
|
34
|
+
propertyId?: string;
|
|
35
|
+
propertyName?: string;
|
|
36
|
+
[key: string]: any;
|
|
33
37
|
}
|
|
34
38
|
export interface TTLockEventData extends DeviceEventData {
|
|
35
39
|
label: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DeviceEvent } from "./DeviceEvent";
|
|
2
2
|
export interface IEventTransformer {
|
|
3
3
|
parseData(rawData: any): any;
|
|
4
|
-
transform(parsedData: any): DeviceEvent | DeviceEvent[]
|
|
4
|
+
transform(parsedData: any): Promise<DeviceEvent | DeviceEvent[]>;
|
|
5
5
|
validate(transformedEvent: DeviceEvent): boolean;
|
|
6
|
-
executeTransformation(): DeviceEvent[]
|
|
6
|
+
executeTransformation(): Promise<DeviceEvent[]>;
|
|
7
7
|
}
|
|
@@ -40,9 +40,13 @@ export declare class IssueService {
|
|
|
40
40
|
*/
|
|
41
41
|
createDeviceOfflineIssue(device: IDevice, source: Source, reason?: string): Promise<IIssueDocument>;
|
|
42
42
|
/**
|
|
43
|
-
* Create issue for device battery level below threshold
|
|
43
|
+
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
44
44
|
*/
|
|
45
45
|
createDeviceBatteryIssue(device: IDevice, batteryLevel: number, threshold: number, source: Source): Promise<IIssueDocument>;
|
|
46
|
+
/**
|
|
47
|
+
* Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
|
|
48
|
+
*/
|
|
49
|
+
createDeviceMalfunctionIssue(device: IDevice, issueType: string, source: Source, reason?: string): Promise<IIssueDocument>;
|
|
46
50
|
/**
|
|
47
51
|
* Create a maintenance issue using IssueBuilder
|
|
48
52
|
*/
|
|
@@ -189,11 +189,17 @@ let IssueService = (() => {
|
|
|
189
189
|
return await this.createDeviceIssue(device.deviceId, device.propertyId, "Device Offline - Requires Attention", `Device ${device.name} (${device.deviceId}) has been offline for longer than the baseline time. ${reason ? `Reason: ${reason}` : ""} This requires immediate attention to restore device functionality.`, source, issue_types_1.IssuesCategory.OPERATIONS, issue_types_1.IssuePriority.HIGH);
|
|
190
190
|
}
|
|
191
191
|
/**
|
|
192
|
-
* Create issue for device battery level below threshold
|
|
192
|
+
* Create issue for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
|
|
193
193
|
*/
|
|
194
194
|
async createDeviceBatteryIssue(device, batteryLevel, threshold, source) {
|
|
195
195
|
return await this.createDeviceIssue(device.deviceId, device.propertyId, "Device Battery Low - Requires Attention", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%. This requires immediate attention to replace or charge the device battery.`, source, issue_types_1.IssuesCategory.ENERGY, issue_types_1.IssuePriority.MEDIUM);
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Create issue for device malfunction (jammed or not accepting codes) (READINESS + OPERATIONAL)
|
|
199
|
+
*/
|
|
200
|
+
async createDeviceMalfunctionIssue(device, issueType, source, reason) {
|
|
201
|
+
return await this.createDeviceIssue(device.deviceId, device.propertyId, `Device Malfunction - ${issueType} - Requires Attention`, `Device ${device.name} (${device.deviceId}) has a malfunction: ${issueType}. ${reason ? `Reason: ${reason}` : ""} This requires immediate attention to resolve the device malfunction.`, source, issue_types_1.IssuesCategory.OPERATIONS, issue_types_1.IssuePriority.HIGH);
|
|
202
|
+
}
|
|
197
203
|
/**
|
|
198
204
|
* Create a maintenance issue using IssueBuilder
|
|
199
205
|
*/
|
|
@@ -1,8 +1,67 @@
|
|
|
1
1
|
export declare class RedisUtils {
|
|
2
2
|
private readonly client;
|
|
3
|
+
/**
|
|
4
|
+
* Get a value from Redis
|
|
5
|
+
* @param key - The key to get
|
|
6
|
+
* @param field - The field to get
|
|
7
|
+
* @returns The value
|
|
8
|
+
*/
|
|
3
9
|
hget(key: string, field: string): Promise<any>;
|
|
10
|
+
/**
|
|
11
|
+
* Set a value in Redis with a TTL
|
|
12
|
+
* @param key - The key to set
|
|
13
|
+
* @param field - The field to set
|
|
14
|
+
* @param value - The value to set (JSON stringified)
|
|
15
|
+
* @param ttl - The TTL in seconds
|
|
16
|
+
* @returns The number of fields set
|
|
17
|
+
*/
|
|
18
|
+
hsetWithTTL(key: string, field: string, value: string, ttl: number): Promise<number>;
|
|
19
|
+
/**
|
|
20
|
+
* Set a value in Redis
|
|
21
|
+
* @param key - The key to set
|
|
22
|
+
* @param field - The field to set
|
|
23
|
+
* @param value - The value to set (JSON stringified)
|
|
24
|
+
* @returns The number of fields set
|
|
25
|
+
*/
|
|
4
26
|
hset(key: string, field: string, value: string): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Delete a field from a hash
|
|
29
|
+
* @param key - The key to delete from
|
|
30
|
+
* @param fields - The fields to delete
|
|
31
|
+
* @returns The number of fields deleted
|
|
32
|
+
*/
|
|
5
33
|
hdel(key: string, ...fields: string[]): Promise<number>;
|
|
34
|
+
/**
|
|
35
|
+
* Set a value in Redis with a TTL
|
|
36
|
+
* @param key - The key to set
|
|
37
|
+
* @param value - The value to set (JSON stringified)
|
|
38
|
+
* @param ttl - The TTL in seconds
|
|
39
|
+
* @returns The value
|
|
40
|
+
*/
|
|
41
|
+
set(key: string, value: string, ttl: number): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Get a value from Redis
|
|
44
|
+
* @param key - The key to get
|
|
45
|
+
* @returns The value
|
|
46
|
+
*/
|
|
47
|
+
get(key: string): Promise<string | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Delete a key from Redis
|
|
50
|
+
* @param key - The key to delete
|
|
51
|
+
* @returns The number of keys deleted
|
|
52
|
+
*/
|
|
53
|
+
del(key: string): Promise<number>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a key exists
|
|
56
|
+
* @param key - The key to check
|
|
57
|
+
* @returns 1 if the key exists, 0 otherwise
|
|
58
|
+
*/
|
|
6
59
|
exists(key: string): Promise<number>;
|
|
60
|
+
/**
|
|
61
|
+
* Set an expiration time for a key
|
|
62
|
+
* @param key - The key to set the expiration for
|
|
63
|
+
* @param seconds - The number of seconds until the key expires
|
|
64
|
+
* @returns 1 if the expiration was set, 0 if the key does not exist
|
|
65
|
+
*/
|
|
7
66
|
expire(key: string, seconds: number): Promise<any>;
|
|
8
67
|
}
|
|
@@ -50,6 +50,12 @@ let RedisUtils = (() => {
|
|
|
50
50
|
constructor() {
|
|
51
51
|
this.client = (0, redis_1.getRedisClient)(); // singleton Redis client instance
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Get a value from Redis
|
|
55
|
+
* @param key - The key to get
|
|
56
|
+
* @param field - The field to get
|
|
57
|
+
* @returns The value
|
|
58
|
+
*/
|
|
53
59
|
async hget(key, field) {
|
|
54
60
|
try {
|
|
55
61
|
const value = await this.client.hget(key, field);
|
|
@@ -63,6 +69,32 @@ let RedisUtils = (() => {
|
|
|
63
69
|
throw error;
|
|
64
70
|
}
|
|
65
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Set a value in Redis with a TTL
|
|
74
|
+
* @param key - The key to set
|
|
75
|
+
* @param field - The field to set
|
|
76
|
+
* @param value - The value to set (JSON stringified)
|
|
77
|
+
* @param ttl - The TTL in seconds
|
|
78
|
+
* @returns The number of fields set
|
|
79
|
+
*/
|
|
80
|
+
async hsetWithTTL(key, field, value, ttl) {
|
|
81
|
+
try {
|
|
82
|
+
await this.hset(key, field, value);
|
|
83
|
+
await this.expire(key, ttl);
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error(`Error setting value for key ${key}:`, error);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set a value in Redis
|
|
93
|
+
* @param key - The key to set
|
|
94
|
+
* @param field - The field to set
|
|
95
|
+
* @param value - The value to set (JSON stringified)
|
|
96
|
+
* @returns The number of fields set
|
|
97
|
+
*/
|
|
66
98
|
async hset(key, field, value) {
|
|
67
99
|
try {
|
|
68
100
|
return await this.client.hset(key, field, value);
|
|
@@ -72,29 +104,46 @@ let RedisUtils = (() => {
|
|
|
72
104
|
throw error;
|
|
73
105
|
}
|
|
74
106
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Delete a field from a hash
|
|
109
|
+
* @param key - The key to delete from
|
|
110
|
+
* @param fields - The fields to delete
|
|
111
|
+
* @returns The number of fields deleted
|
|
112
|
+
*/
|
|
78
113
|
async hdel(key, ...fields) {
|
|
79
114
|
return await this.client.hdel(key, ...fields);
|
|
80
115
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Set a value in Redis with a TTL
|
|
118
|
+
* @param key - The key to set
|
|
119
|
+
* @param value - The value to set (JSON stringified)
|
|
120
|
+
* @param ttl - The TTL in seconds
|
|
121
|
+
* @returns The value
|
|
122
|
+
*/
|
|
123
|
+
async set(key, value, ttl) {
|
|
124
|
+
return await this.client.set(key, value, "EX", ttl);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get a value from Redis
|
|
128
|
+
* @param key - The key to get
|
|
129
|
+
* @returns The value
|
|
130
|
+
*/
|
|
131
|
+
async get(key) {
|
|
132
|
+
return await this.client.get(key);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Delete a key from Redis
|
|
136
|
+
* @param key - The key to delete
|
|
137
|
+
* @returns The number of keys deleted
|
|
138
|
+
*/
|
|
139
|
+
async del(key) {
|
|
140
|
+
return await this.client.del(key);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Check if a key exists
|
|
144
|
+
* @param key - The key to check
|
|
145
|
+
* @returns 1 if the key exists, 0 otherwise
|
|
146
|
+
*/
|
|
98
147
|
async exists(key) {
|
|
99
148
|
try {
|
|
100
149
|
return await this.client.exists(key);
|
|
@@ -104,6 +153,12 @@ let RedisUtils = (() => {
|
|
|
104
153
|
throw error;
|
|
105
154
|
}
|
|
106
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Set an expiration time for a key
|
|
158
|
+
* @param key - The key to set the expiration for
|
|
159
|
+
* @param seconds - The number of seconds until the key expires
|
|
160
|
+
* @returns 1 if the expiration was set, 0 if the key does not exist
|
|
161
|
+
*/
|
|
107
162
|
async expire(key, seconds) {
|
|
108
163
|
try {
|
|
109
164
|
return await this.client.expire(key, seconds);
|