dt-common-device 3.1.6 → 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.
@@ -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>): Promise<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(deviceId, device, oldStatus, newStatus, source, reason, currentTime);
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(deviceId, device, oldStatus, newStatus, source, reason, currentTime);
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(deviceId, device, oldStatus, newStatus, source, reason, currentTime) {
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(deviceId, device, oldStatus, newStatus, source, reason, currentTime) {
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
- async onStateChange(deviceId, state, event) {
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, DeviceEventEntity, EventConstructionOptions } from "./interfaces/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("[DT | CDL]:[DeviceEventHandler]: Error processing event", 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>): Promise<void>;
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?: string;
7
- connectionProvider?: string;
8
- originalEventName?: string;
9
- rawEvent?: any;
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
  */
@@ -91,7 +91,7 @@ class QueueUtils {
91
91
  method: method.toLowerCase(),
92
92
  url: url,
93
93
  headers: options.headers || {},
94
- timeout: 30000,
94
+ timeout: 60000,
95
95
  ...(options.body && { data: options.body }),
96
96
  ...(options.params && { params: options.params }),
97
97
  });
@@ -31,6 +31,26 @@ export declare class RedisUtils {
31
31
  * @returns The number of fields deleted
32
32
  */
33
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>;
34
54
  /**
35
55
  * Check if a key exists
36
56
  * @param key - The key to check
@@ -113,6 +113,32 @@ let RedisUtils = (() => {
113
113
  async hdel(key, ...fields) {
114
114
  return await this.client.hdel(key, ...fields);
115
115
  }
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
+ }
116
142
  /**
117
143
  * Check if a key exists
118
144
  * @param key - The key to check
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "3.1.6",
3
+ "version": "4.0.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [