dt-common-device 3.0.2 → 3.0.4
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/README.md +7 -2
- package/dist/alerts/Alert.model.js +8 -2
- package/dist/alerts/Alert.repository.d.ts +3 -3
- package/dist/alerts/Alert.repository.js +28 -5
- package/dist/alerts/Alert.service.d.ts +18 -4
- package/dist/alerts/Alert.service.js +34 -3
- package/dist/alerts/AlertBuilder.d.ts +1 -1
- package/dist/alerts/AlertBuilder.js +1 -1
- package/dist/alerts/AlertService.example.js +5 -3
- package/dist/alerts/alert.types.d.ts +3 -3
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.js +3 -3
- package/dist/connection/Connection.repository.js +1 -1
- package/dist/constants/ConnectionProviders.d.ts +11 -0
- package/dist/constants/ConnectionProviders.js +14 -0
- package/dist/constants/Event.d.ts +14 -0
- package/dist/constants/Event.js +14 -0
- package/dist/constants/Service.d.ts +15 -0
- package/dist/constants/Service.js +19 -0
- package/dist/constants/index.d.ts +3 -0
- package/dist/constants/index.js +19 -0
- package/dist/db/redis.js +1 -0
- package/dist/device/cloud/entities/CloudDevice.d.ts +2 -2
- package/dist/device/cloud/entities/CloudDeviceService.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.js +1 -1
- package/dist/device/local/interfaces/IDevice.d.ts +3 -2
- package/dist/device/local/repository/Device.repository.js +3 -3
- package/dist/device/local/repository/Hub.repository.js +3 -3
- package/dist/device/local/repository/Schedule.repository.js +2 -2
- package/dist/device/local/services/Device.service.d.ts +11 -2
- package/dist/device/local/services/Device.service.js +145 -25
- package/dist/events/BaseEventHandler.d.ts +2 -2
- package/dist/events/BaseEventHandler.js +2 -2
- package/dist/events/BaseEventTransformer.d.ts +1 -1
- package/dist/events/BaseEventTransformer.js +1 -1
- package/dist/events/DeviceEventHandler.d.ts +1 -1
- package/dist/events/DeviceEventHandler.js +4 -3
- package/dist/events/EventHandler.js +1 -1
- package/dist/events/EventHandlerOrchestrator.js +1 -1
- package/dist/events/EventProcessingService.js +1 -1
- package/dist/events/InternalEventSubscription.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/issues/Issue.service.d.ts +11 -1
- package/dist/issues/Issue.service.js +16 -3
- package/dist/issues/IssueService.example.js +4 -2
- package/package.json +1 -1
- package/src/alerts/Alert.model.ts +8 -2
- package/src/alerts/Alert.repository.ts +28 -6
- package/src/alerts/Alert.service.ts +91 -7
- package/src/alerts/AlertBuilder.ts +2 -2
- package/src/alerts/AlertService.example.ts +5 -3
- package/src/alerts/alert.types.ts +3 -3
- package/src/config/config.ts +3 -3
- package/src/connection/Connection.repository.ts +1 -1
- package/src/constants/ConnectionProviders.ts +11 -0
- package/src/constants/Event.ts +14 -0
- package/src/constants/Service.ts +17 -0
- package/src/constants/index.ts +3 -0
- package/src/db/redis.ts +1 -0
- package/src/device/cloud/entities/CloudDevice.ts +2 -2
- package/src/device/cloud/entities/CloudDeviceService.ts +1 -1
- package/src/device/cloud/entities/DeviceFactory.ts +2 -2
- package/src/device/local/interfaces/IDevice.ts +3 -2
- package/src/device/local/repository/Device.repository.ts +3 -3
- package/src/device/local/repository/Hub.repository.ts +3 -3
- package/src/device/local/repository/Schedule.repository.ts +2 -2
- package/src/device/local/services/Device.service.ts +231 -29
- package/src/events/BaseEventHandler.ts +3 -3
- package/src/events/BaseEventTransformer.ts +2 -2
- package/src/events/DeviceEventHandler.ts +6 -4
- package/src/events/EventHandler.ts +1 -1
- package/src/events/EventHandlerOrchestrator.ts +2 -2
- package/src/events/EventProcessingService.ts +2 -2
- package/src/events/InternalEventSubscription.ts +2 -2
- package/src/index.ts +3 -0
- package/src/issues/Issue.service.ts +67 -7
- package/src/issues/IssueService.example.ts +4 -2
- package/tsconfig.json +0 -4
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import { IDevice, IStatus } from "../interfaces";
|
|
2
|
-
import { EventHandler } from "
|
|
2
|
+
import { EventHandler } from "../../../events/EventHandler";
|
|
3
3
|
import { isEqual } from "lodash";
|
|
4
4
|
import { DeviceRepository } from "../repository/Device.repository";
|
|
5
5
|
import Container from "typedi";
|
|
6
|
+
import { AlertService } from "../../../alerts/Alert.service";
|
|
7
|
+
import { IssueService } from "../../../issues/Issue.service";
|
|
8
|
+
import { Source } from "../../../constants/Service";
|
|
9
|
+
import { getConfig } from "../../../config/config";
|
|
6
10
|
|
|
7
11
|
export class LocalDeviceService {
|
|
8
12
|
private readonly eventHandler: EventHandler;
|
|
9
13
|
private readonly deviceRepository: DeviceRepository;
|
|
14
|
+
private readonly alertService: AlertService;
|
|
15
|
+
private readonly issueService: IssueService;
|
|
16
|
+
private readonly logger;
|
|
17
|
+
|
|
10
18
|
constructor() {
|
|
11
19
|
this.eventHandler = new EventHandler();
|
|
12
20
|
this.deviceRepository = Container.get(DeviceRepository);
|
|
21
|
+
this.alertService = Container.get(AlertService);
|
|
22
|
+
this.issueService = Container.get(IssueService);
|
|
23
|
+
this.logger = getConfig().LOGGER;
|
|
13
24
|
}
|
|
14
25
|
|
|
15
26
|
async createDevice(body: IDevice): Promise<IDevice> {
|
|
@@ -117,31 +128,168 @@ export class LocalDeviceService {
|
|
|
117
128
|
return await this.deviceRepository.getStatus(deviceId);
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
async setStatus(
|
|
131
|
+
async setStatus(
|
|
132
|
+
deviceId: string,
|
|
133
|
+
newStatus: IStatus,
|
|
134
|
+
source: Source,
|
|
135
|
+
reason?: string
|
|
136
|
+
) {
|
|
121
137
|
if (!deviceId || !newStatus) {
|
|
122
138
|
throw new Error("Device ID and new status are required");
|
|
123
139
|
}
|
|
124
140
|
|
|
125
|
-
const
|
|
126
|
-
const
|
|
141
|
+
const device = await this.getDevice(deviceId);
|
|
142
|
+
const oldStatus = device.status;
|
|
143
|
+
const currentTime = new Date().toISOString();
|
|
144
|
+
|
|
145
|
+
// Determine if the new status is ONLINE or OFFLINE
|
|
146
|
+
const isNewStatusOnline = newStatus.liveStatus === "ONLINE";
|
|
147
|
+
const isNewStatusOffline = newStatus.liveStatus === "OFFLINE";
|
|
148
|
+
|
|
149
|
+
if (isNewStatusOffline) {
|
|
150
|
+
// New Status = OFFLINE
|
|
151
|
+
await this.handleOfflineStatus(
|
|
152
|
+
deviceId,
|
|
153
|
+
device,
|
|
154
|
+
oldStatus,
|
|
155
|
+
newStatus,
|
|
156
|
+
source,
|
|
157
|
+
reason,
|
|
158
|
+
currentTime
|
|
159
|
+
);
|
|
160
|
+
} else if (isNewStatusOnline) {
|
|
161
|
+
// New Status = ONLINE
|
|
162
|
+
await this.handleOnlineStatus(
|
|
163
|
+
deviceId,
|
|
164
|
+
device,
|
|
165
|
+
oldStatus,
|
|
166
|
+
newStatus,
|
|
167
|
+
source,
|
|
168
|
+
reason,
|
|
169
|
+
currentTime
|
|
170
|
+
);
|
|
171
|
+
} else {
|
|
172
|
+
// For any other status, just update normally
|
|
173
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
174
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private async handleOfflineStatus(
|
|
179
|
+
deviceId: string,
|
|
180
|
+
device: IDevice,
|
|
181
|
+
oldStatus: any,
|
|
182
|
+
newStatus: IStatus,
|
|
183
|
+
source: Source,
|
|
184
|
+
reason?: string,
|
|
185
|
+
currentTime?: string
|
|
186
|
+
) {
|
|
187
|
+
const isExistingStatusOnline = oldStatus?.online === true;
|
|
188
|
+
const isExistingStatusOffline = oldStatus?.online === false;
|
|
189
|
+
|
|
190
|
+
if (isExistingStatusOnline) {
|
|
191
|
+
// Existing status is Online
|
|
192
|
+
newStatus.online = true;
|
|
193
|
+
newStatus.liveStatus = "OFFLINE";
|
|
194
|
+
newStatus.lastUpdated = currentTime;
|
|
195
|
+
newStatus.error = {
|
|
196
|
+
type: "offline",
|
|
197
|
+
message: reason || "Device went offline",
|
|
198
|
+
default: {},
|
|
199
|
+
};
|
|
127
200
|
|
|
128
|
-
if (isStatusChanged) {
|
|
129
201
|
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
130
202
|
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
203
|
+
} else if (isExistingStatusOffline) {
|
|
204
|
+
// Existing status is Offline
|
|
205
|
+
const timeLapsed = oldStatus?.lastUpdated
|
|
206
|
+
? Date.now() - new Date(oldStatus.lastUpdated).getTime()
|
|
207
|
+
: 0;
|
|
208
|
+
|
|
209
|
+
const baselineTime = await this.getDeviceBaseline(deviceId);
|
|
210
|
+
|
|
211
|
+
if (timeLapsed > baselineTime) {
|
|
212
|
+
// When the time lapsed is higher than the baseline time
|
|
213
|
+
newStatus.online = false;
|
|
214
|
+
newStatus.liveStatus = "OFFLINE";
|
|
215
|
+
newStatus.lastUpdated = currentTime;
|
|
216
|
+
newStatus.error = {
|
|
217
|
+
type: "offline",
|
|
218
|
+
message: reason || "Device has been offline for longer than baseline",
|
|
219
|
+
default: {},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
223
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
224
|
+
|
|
225
|
+
// Raise alert
|
|
226
|
+
await this.alertService.raiseDeviceOfflineAlert(device, source, reason);
|
|
227
|
+
|
|
228
|
+
// Raise issue when the device goes offline if longer than the baseline
|
|
229
|
+
await this.issueService.createDeviceOfflineIssue(
|
|
230
|
+
device,
|
|
231
|
+
source,
|
|
232
|
+
reason
|
|
233
|
+
);
|
|
234
|
+
}
|
|
131
235
|
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private async handleOnlineStatus(
|
|
239
|
+
deviceId: string,
|
|
240
|
+
device: IDevice,
|
|
241
|
+
oldStatus: any,
|
|
242
|
+
newStatus: IStatus,
|
|
243
|
+
source: Source,
|
|
244
|
+
reason?: string,
|
|
245
|
+
currentTime?: string
|
|
246
|
+
) {
|
|
247
|
+
const isExistingStatusOnline = oldStatus?.online === true;
|
|
248
|
+
const isExistingStatusOffline = oldStatus?.online === false;
|
|
132
249
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
Date.now() - new Date(oldStatus.lastUpdated).getTime();
|
|
138
|
-
if (timeDifference > 86400000) {
|
|
139
|
-
//return await this.alertService.raiseOperationsAlert();
|
|
250
|
+
if (isExistingStatusOnline) {
|
|
251
|
+
// Existing status is Online
|
|
252
|
+
if (oldStatus?.liveStatus === "ONLINE") {
|
|
253
|
+
// liveStatus = Online → Do nothing
|
|
140
254
|
return;
|
|
255
|
+
} else if (oldStatus?.liveStatus === "OFFLINE") {
|
|
256
|
+
// liveStatus = Offline → Follow the step #2 (same as existing status is Offline)
|
|
257
|
+
newStatus.online = true;
|
|
258
|
+
newStatus.liveStatus = "ONLINE";
|
|
259
|
+
newStatus.lastUpdated = currentTime;
|
|
260
|
+
newStatus.error = {}; // Clear the error
|
|
261
|
+
|
|
262
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
263
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
264
|
+
|
|
265
|
+
//TODO: ALERT NEEDED?
|
|
266
|
+
// Raise alert
|
|
267
|
+
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
141
268
|
}
|
|
269
|
+
} else if (isExistingStatusOffline) {
|
|
270
|
+
// Existing status is Offline
|
|
271
|
+
newStatus.online = true;
|
|
272
|
+
newStatus.liveStatus = "ONLINE";
|
|
273
|
+
newStatus.lastUpdated = currentTime;
|
|
274
|
+
newStatus.error = undefined; // Clear the error
|
|
275
|
+
|
|
276
|
+
await this.deviceRepository.setStatus(deviceId, newStatus);
|
|
277
|
+
await this.eventHandler.onStatusChange(deviceId, newStatus);
|
|
278
|
+
|
|
279
|
+
//TODO: ALERT NEEDED?
|
|
280
|
+
// Raise alert
|
|
281
|
+
await this.alertService.raiseDeviceOnlineAlert(device, source, reason);
|
|
142
282
|
}
|
|
143
283
|
}
|
|
144
284
|
|
|
285
|
+
private async getDeviceBaseline(deviceId: string): Promise<number> {
|
|
286
|
+
// TODO: Implement device baseline retrieval
|
|
287
|
+
// This should return the baseline time in milliseconds for the specific device
|
|
288
|
+
// For now, returning a default value of 5 minutes (300000ms)
|
|
289
|
+
// In a real implementation, this would fetch from device configuration or settings
|
|
290
|
+
return 3600000; // 1 hour in milliseconds
|
|
291
|
+
}
|
|
292
|
+
|
|
145
293
|
async getBatteryLevel(deviceId: string) {
|
|
146
294
|
if (!deviceId) {
|
|
147
295
|
throw new Error("Device ID is required");
|
|
@@ -149,29 +297,83 @@ export class LocalDeviceService {
|
|
|
149
297
|
return await this.deviceRepository.getBatteryLevel(deviceId);
|
|
150
298
|
}
|
|
151
299
|
|
|
152
|
-
async setBatteryLevel(
|
|
300
|
+
async setBatteryLevel(
|
|
301
|
+
deviceId: string,
|
|
302
|
+
batteryLevel: number,
|
|
303
|
+
source: Source
|
|
304
|
+
) {
|
|
305
|
+
if (!deviceId || batteryLevel === undefined || batteryLevel === null) {
|
|
306
|
+
throw new Error("Device ID and battery level are required");
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Get device information
|
|
310
|
+
const device = await this.getDevice(deviceId);
|
|
311
|
+
|
|
153
312
|
// Fetch the old battery level state
|
|
154
|
-
const oldBatteryLevel =
|
|
313
|
+
const oldBatteryLevel = device.state?.batteryPercentage;
|
|
155
314
|
|
|
315
|
+
// Check if battery level has changed
|
|
156
316
|
const isDifferent = !isEqual(oldBatteryLevel?.value, batteryLevel);
|
|
157
317
|
|
|
158
318
|
if (isDifferent) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
319
|
+
// Check if current time is greater than or equal to last updated time (8-hour logic)
|
|
320
|
+
const shouldUpdate = this.shouldUpdateBatteryLevel(
|
|
321
|
+
oldBatteryLevel?.lastUpdated
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
if (shouldUpdate) {
|
|
325
|
+
// Save the battery level in the device
|
|
326
|
+
await this.deviceRepository.setBatteryLevel(deviceId, batteryLevel);
|
|
327
|
+
await this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel);
|
|
328
|
+
|
|
329
|
+
// Get property threshold
|
|
330
|
+
const propertyThreshold = await this.getPropertyBatteryThreshold(
|
|
331
|
+
device.propertyId
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// Check if battery level is below threshold
|
|
335
|
+
if (batteryLevel < propertyThreshold) {
|
|
336
|
+
// Raise alert
|
|
337
|
+
await this.alertService.raiseDeviceBatteryAlert(
|
|
338
|
+
device,
|
|
339
|
+
batteryLevel,
|
|
340
|
+
propertyThreshold,
|
|
341
|
+
source
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// Raise issue when the level is below threshold
|
|
345
|
+
await this.issueService.createDeviceBatteryIssue(
|
|
346
|
+
device,
|
|
347
|
+
batteryLevel,
|
|
348
|
+
propertyThreshold,
|
|
349
|
+
source
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private shouldUpdateBatteryLevel(lastUpdated?: string): boolean {
|
|
357
|
+
if (!lastUpdated) {
|
|
358
|
+
return true; // No previous update, so we should update
|
|
174
359
|
}
|
|
360
|
+
|
|
361
|
+
const lastUpdateTime = new Date(lastUpdated).getTime();
|
|
362
|
+
const currentTime = Date.now();
|
|
363
|
+
const eightHoursInMs = 8 * 60 * 60 * 1000; // 8 hours in milliseconds
|
|
364
|
+
|
|
365
|
+
// Return true if current time is greater than or equal to last updated time + 8 hours
|
|
366
|
+
return currentTime >= lastUpdateTime + eightHoursInMs;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private async getPropertyBatteryThreshold(
|
|
370
|
+
propertyId: string
|
|
371
|
+
): Promise<number> {
|
|
372
|
+
// TODO: Implement property battery threshold retrieval
|
|
373
|
+
// This should return the battery threshold for the specific property
|
|
374
|
+
// For now, returning a default value of 20%
|
|
375
|
+
// In a real implementation, this would fetch from property configuration or settings
|
|
376
|
+
return 20; // 20% default threshold
|
|
175
377
|
}
|
|
176
378
|
|
|
177
379
|
async getMetaData(deviceId: string) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
|
-
import { getConfig } from "
|
|
4
|
-
import { ILogger } from "
|
|
5
|
-
import { LocalDeviceService } from "
|
|
3
|
+
import { getConfig } from "../config/config";
|
|
4
|
+
import { ILogger } from "../config/config.types";
|
|
5
|
+
import { LocalDeviceService } from "../device/local/services/Device.service";
|
|
6
6
|
|
|
7
7
|
export abstract class BaseEventHandler implements IEventHandler {
|
|
8
8
|
protected readonly supportedEventTypes: string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getConfig } from "
|
|
2
|
-
import { ILogger } from "
|
|
1
|
+
import { getConfig } from "../config/config";
|
|
2
|
+
import { ILogger } from "../config/config.types";
|
|
3
3
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
4
4
|
import { IEventTransformer } from "./interfaces/IEventTransformer";
|
|
5
5
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Source } from "../constants";
|
|
2
|
+
import { DT_EVENT_TYPES } from "../constants/Event";
|
|
3
|
+
import { IDevice } from "../device/local/interfaces";
|
|
4
|
+
import { LocalHubService } from "../device/local/services";
|
|
4
5
|
import { BaseEventHandler } from "./BaseEventHandler";
|
|
5
6
|
import {
|
|
6
7
|
DeviceEvent,
|
|
@@ -82,7 +83,8 @@ export class DeviceEventHandler extends BaseEventHandler {
|
|
|
82
83
|
case DT_EVENT_TYPES.DEVICE.BATTERY.CHANGED:
|
|
83
84
|
await this.localDeviceService.setBatteryLevel(
|
|
84
85
|
deviceData.deviceId,
|
|
85
|
-
event?.data?.batteryLevel ?? 0
|
|
86
|
+
event?.data?.batteryLevel ?? 0,
|
|
87
|
+
Source.CLOUD_EVENT
|
|
86
88
|
);
|
|
87
89
|
break;
|
|
88
90
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { eventDispatcher } from "dt-pub-sub";
|
|
2
2
|
import { publishAudit } from "dt-audit-library";
|
|
3
|
-
import { DT_EVENT_TYPES } from "
|
|
3
|
+
import { DT_EVENT_TYPES } from "../constants/Event";
|
|
4
4
|
|
|
5
5
|
export class EventHandler {
|
|
6
6
|
private readonly source: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
3
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
4
|
-
import { ILogger } from "
|
|
5
|
-
import { getConfig } from "
|
|
4
|
+
import { ILogger } from "../config/config.types";
|
|
5
|
+
import { getConfig } from "../config/config";
|
|
6
6
|
|
|
7
7
|
@Service()
|
|
8
8
|
export class EventHandlerOrchestrator {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
2
|
import { DeviceEventHandler } from "./DeviceEventHandler";
|
|
3
|
-
import { ILogger } from "
|
|
4
|
-
import { getConfig } from "
|
|
3
|
+
import { ILogger } from "../config/config.types";
|
|
4
|
+
import { getConfig } from "../config/config";
|
|
5
5
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
6
6
|
import { IEventTransformer } from "./interfaces/IEventTransformer";
|
|
7
7
|
import { EventHandlerOrchestrator } from "./EventHandlerOrchestrator";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eventDispatcher } from "dt-pub-sub";
|
|
2
|
-
import { getConfig } from "
|
|
2
|
+
import { getConfig } from "../config/config";
|
|
3
3
|
import {
|
|
4
4
|
IInternalEvent,
|
|
5
5
|
HeartbeatEventData,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ReservationEventData,
|
|
8
8
|
ServiceEventData,
|
|
9
9
|
} from "./interfaces/IInternalEvent";
|
|
10
|
-
import { ILogger } from "
|
|
10
|
+
import { ILogger } from "../config/config.types";
|
|
11
11
|
|
|
12
12
|
// Event types enum for better type safety
|
|
13
13
|
export enum InternalEventType {
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
EntityType,
|
|
12
12
|
} from "./issue.types";
|
|
13
13
|
import { IssueBuilder } from "./IssueBuilder";
|
|
14
|
+
import { Source } from "../constants/Service";
|
|
15
|
+
import { IDevice } from "../device/local/interfaces";
|
|
14
16
|
|
|
15
17
|
@Service()
|
|
16
18
|
export class IssueService {
|
|
@@ -132,7 +134,7 @@ export class IssueService {
|
|
|
132
134
|
propertyId: string,
|
|
133
135
|
title: string,
|
|
134
136
|
description: string,
|
|
135
|
-
|
|
137
|
+
source: Source,
|
|
136
138
|
category?: IssuesCategory,
|
|
137
139
|
priority?: IssuePriority,
|
|
138
140
|
assignedTo?: string,
|
|
@@ -141,7 +143,7 @@ export class IssueService {
|
|
|
141
143
|
const issueBuilder = IssueBuilder.createDeviceIssue(deviceId, propertyId)
|
|
142
144
|
.setTitle(title)
|
|
143
145
|
.setDescription(description)
|
|
144
|
-
.setCreatedBy(
|
|
146
|
+
.setCreatedBy(source);
|
|
145
147
|
|
|
146
148
|
if (category) issueBuilder.setCategory(category);
|
|
147
149
|
if (priority) issueBuilder.setPriority(priority);
|
|
@@ -205,6 +207,49 @@ export class IssueService {
|
|
|
205
207
|
return await this.createIssue(issueBuilder);
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Create issue for device going offline longer than baseline
|
|
212
|
+
*/
|
|
213
|
+
async createDeviceOfflineIssue(
|
|
214
|
+
device: IDevice,
|
|
215
|
+
source: Source,
|
|
216
|
+
reason?: string
|
|
217
|
+
): Promise<IIssueDocument> {
|
|
218
|
+
return await this.createDeviceIssue(
|
|
219
|
+
device.deviceId,
|
|
220
|
+
device.propertyId,
|
|
221
|
+
"Device Offline - Requires Attention",
|
|
222
|
+
`Device ${device.name} (${
|
|
223
|
+
device.deviceId
|
|
224
|
+
}) has been offline for longer than the baseline time. ${
|
|
225
|
+
reason ? `Reason: ${reason}` : ""
|
|
226
|
+
} This requires immediate attention to restore device functionality.`,
|
|
227
|
+
source,
|
|
228
|
+
IssuesCategory.OPERATIONS,
|
|
229
|
+
IssuePriority.HIGH
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Create issue for device battery level below threshold
|
|
235
|
+
*/
|
|
236
|
+
async createDeviceBatteryIssue(
|
|
237
|
+
device: IDevice,
|
|
238
|
+
batteryLevel: number,
|
|
239
|
+
threshold: number,
|
|
240
|
+
source: Source
|
|
241
|
+
): Promise<IIssueDocument> {
|
|
242
|
+
return await this.createDeviceIssue(
|
|
243
|
+
device.deviceId,
|
|
244
|
+
device.propertyId,
|
|
245
|
+
"Device Battery Low - Requires Attention",
|
|
246
|
+
`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.`,
|
|
247
|
+
source,
|
|
248
|
+
IssuesCategory.ENERGY,
|
|
249
|
+
IssuePriority.MEDIUM
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
208
253
|
/**
|
|
209
254
|
* Create a maintenance issue using IssueBuilder
|
|
210
255
|
*/
|
|
@@ -218,7 +263,11 @@ export class IssueService {
|
|
|
218
263
|
assignedTo?: string,
|
|
219
264
|
dueDate?: Date
|
|
220
265
|
): Promise<IIssueDocument> {
|
|
221
|
-
const issueBuilder = IssueBuilder.createMaintenanceIssue(
|
|
266
|
+
const issueBuilder = IssueBuilder.createMaintenanceIssue(
|
|
267
|
+
propertyId,
|
|
268
|
+
entityId,
|
|
269
|
+
entityType
|
|
270
|
+
)
|
|
222
271
|
.setTitle(title)
|
|
223
272
|
.setDescription(description)
|
|
224
273
|
.setCreatedBy(createdBy);
|
|
@@ -242,7 +291,11 @@ export class IssueService {
|
|
|
242
291
|
assignedTo?: string,
|
|
243
292
|
dueDate?: Date
|
|
244
293
|
): Promise<IIssueDocument> {
|
|
245
|
-
const issueBuilder = IssueBuilder.createUrgentIssue(
|
|
294
|
+
const issueBuilder = IssueBuilder.createUrgentIssue(
|
|
295
|
+
propertyId,
|
|
296
|
+
entityId,
|
|
297
|
+
entityType
|
|
298
|
+
)
|
|
246
299
|
.setTitle(title)
|
|
247
300
|
.setDescription(description)
|
|
248
301
|
.setCreatedBy(createdBy);
|
|
@@ -257,7 +310,9 @@ export class IssueService {
|
|
|
257
310
|
* Create a new issue with business logic validation
|
|
258
311
|
* Accepts either a CreateIssueData object or an IssueBuilder instance
|
|
259
312
|
*/
|
|
260
|
-
async createIssue(
|
|
313
|
+
async createIssue(
|
|
314
|
+
issueData: CreateIssueData | IssueBuilder
|
|
315
|
+
): Promise<IIssueDocument> {
|
|
261
316
|
let processedIssueData: CreateIssueData;
|
|
262
317
|
|
|
263
318
|
// Handle IssueBuilder instance
|
|
@@ -272,11 +327,16 @@ export class IssueService {
|
|
|
272
327
|
|
|
273
328
|
// Business logic: Set default priority if not provided
|
|
274
329
|
if (!processedIssueData.priority) {
|
|
275
|
-
processedIssueData.priority = this.determineDefaultPriority(
|
|
330
|
+
processedIssueData.priority = this.determineDefaultPriority(
|
|
331
|
+
processedIssueData.category
|
|
332
|
+
);
|
|
276
333
|
}
|
|
277
334
|
|
|
278
335
|
// Business logic: Validate due date is in the future
|
|
279
|
-
if (
|
|
336
|
+
if (
|
|
337
|
+
processedIssueData.dueDate &&
|
|
338
|
+
processedIssueData.dueDate <= new Date()
|
|
339
|
+
) {
|
|
280
340
|
throw new Error("Due date must be in the future");
|
|
281
341
|
}
|
|
282
342
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Source } from "../constants";
|
|
1
2
|
import { IssueService } from "./Issue.service";
|
|
2
3
|
import { IssueBuilder } from "./IssueBuilder";
|
|
3
4
|
import { IssuesCategory, IssuePriority, EntityType } from "./issue.types";
|
|
@@ -96,7 +97,7 @@ export class IssueServiceExample {
|
|
|
96
97
|
"prop456",
|
|
97
98
|
"Device Battery Low",
|
|
98
99
|
"Device battery level is below 20%",
|
|
99
|
-
|
|
100
|
+
Source.CLOUD_EVENT,
|
|
100
101
|
undefined, // Use default category
|
|
101
102
|
undefined, // Use default priority
|
|
102
103
|
"maintenance-team",
|
|
@@ -109,7 +110,7 @@ export class IssueServiceExample {
|
|
|
109
110
|
"prop456",
|
|
110
111
|
"Device Firmware Update Available",
|
|
111
112
|
"New firmware version is available for installation",
|
|
112
|
-
|
|
113
|
+
Source.CLOUD_EVENT,
|
|
113
114
|
IssuesCategory.READINESS,
|
|
114
115
|
IssuePriority.MEDIUM,
|
|
115
116
|
"admin",
|
|
@@ -299,6 +300,7 @@ export class IssueServiceExample {
|
|
|
299
300
|
assignedTo: "tech-support",
|
|
300
301
|
createdBy: "legacy-system",
|
|
301
302
|
dueDate: new Date("2024-01-20"),
|
|
303
|
+
source: Source.CLOUD_EVENT,
|
|
302
304
|
};
|
|
303
305
|
|
|
304
306
|
// This still works with the updated createIssue method
|