dt-common-device 1.0.12 → 1.0.14

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.
Files changed (65) hide show
  1. package/README.md +15 -35
  2. package/dist/config/config.d.ts +13 -0
  3. package/dist/config/config.js +30 -0
  4. package/dist/db/db.d.ts +2 -0
  5. package/dist/db/db.js +15 -0
  6. package/dist/db/index.d.ts +2 -0
  7. package/dist/db/index.js +18 -0
  8. package/dist/db/redis.d.ts +2 -0
  9. package/dist/db/redis.js +22 -0
  10. package/dist/device/cloud/entities/CloudDevice.d.ts +15 -0
  11. package/dist/device/cloud/entities/CloudDevice.js +42 -0
  12. package/dist/device/cloud/entities/DeviceFactory.d.ts +6 -0
  13. package/dist/device/cloud/entities/DeviceFactory.js +13 -0
  14. package/dist/device/cloud/entities/index.d.ts +2 -0
  15. package/dist/device/cloud/entities/index.js +18 -0
  16. package/dist/device/cloud/interfaces/ICloudDevice.d.ts +9 -0
  17. package/dist/device/cloud/interfaces/ICloudDevice.js +2 -0
  18. package/dist/device/cloud/interfaces/ICloudDeviceService.d.ts +4 -0
  19. package/dist/device/cloud/interfaces/ICloudDeviceService.js +2 -0
  20. package/dist/device/cloud/interfaces/IConnectionService.js +0 -1
  21. package/dist/device/cloud/interfaces/index.d.ts +2 -0
  22. package/dist/device/cloud/interfaces/index.js +2 -0
  23. package/dist/device/cloud/services/CloudDevice.service.d.ts +5 -0
  24. package/dist/device/cloud/services/CloudDevice.service.js +6 -0
  25. package/dist/device/cloud/services/Connection.service.d.ts +1 -1
  26. package/dist/device/cloud/services/index.d.ts +2 -3
  27. package/dist/device/cloud/services/index.js +16 -8
  28. package/dist/device/cloud/types.d.ts +9 -68
  29. package/dist/device/cloud/types.js +0 -12
  30. package/dist/device/local/interfaces/IConnection.d.ts +16 -0
  31. package/dist/device/local/interfaces/IConnection.js +2 -0
  32. package/dist/device/local/interfaces/IDevice.d.ts +4 -0
  33. package/dist/device/local/services/Connection.service.d.ts +5 -0
  34. package/dist/device/local/services/Connection.service.js +14 -0
  35. package/dist/device/local/services/Device.service.d.ts +7 -3
  36. package/dist/device/local/services/Device.service.js +85 -31
  37. package/dist/device/local/services/index.d.ts +2 -1
  38. package/dist/device/local/services/index.js +4 -2
  39. package/dist/index.d.ts +5 -4
  40. package/dist/index.js +8 -27
  41. package/package.json +7 -9
  42. package/src/config/config.ts +31 -0
  43. package/src/db/db.ts +15 -0
  44. package/src/db/index.ts +2 -0
  45. package/src/db/redis.ts +18 -0
  46. package/src/device/cloud/entities/CloudDevice.ts +56 -0
  47. package/src/device/cloud/entities/DeviceFactory.ts +14 -0
  48. package/src/device/cloud/entities/index.ts +2 -0
  49. package/src/device/cloud/interfaces/ICloudDevice.ts +15 -0
  50. package/src/device/cloud/interfaces/ICloudDeviceService.ts +6 -0
  51. package/src/device/cloud/interfaces/IConnectionService.ts +0 -2
  52. package/src/device/cloud/interfaces/index.ts +2 -0
  53. package/src/device/cloud/services/CloudDevice.service.ts +6 -0
  54. package/src/device/cloud/services/Connection.service.ts +1 -1
  55. package/src/device/cloud/services/index.ts +2 -5
  56. package/src/device/cloud/types.ts +9 -63
  57. package/src/device/local/interfaces/IConnection.ts +17 -0
  58. package/src/device/local/interfaces/IDevice.ts +4 -0
  59. package/src/device/local/interfaces/index.ts +1 -1
  60. package/src/device/local/services/Connection.service.ts +15 -0
  61. package/src/device/local/services/Device.service.ts +107 -31
  62. package/src/device/local/services/index.ts +2 -1
  63. package/src/index.ts +9 -5
  64. package/src/device/cloud/services/Device.service.ts +0 -41
  65. package/src/device/cloud/services/Hub.service.ts +0 -34
@@ -0,0 +1,15 @@
1
+ import { getPostgresClient } from "../../../db";
2
+ export class ConnectionService {
3
+ private readonly pool;
4
+ constructor() {
5
+ this.pool = getPostgresClient();
6
+ }
7
+
8
+ async getConnection(connectionId: string) {
9
+ const result = await this.pool.query(
10
+ "SELECT * FROM dt_connections WHERE id = $1",
11
+ [connectionId]
12
+ );
13
+ return result.rows[0];
14
+ }
15
+ }
@@ -1,4 +1,3 @@
1
- //TODO: Import Redis
2
1
  import axios from "axios";
3
2
  import {
4
3
  getConfig,
@@ -10,12 +9,16 @@ import { eventDispatcher } from "dt-pub-sub";
10
9
  import { publishAudit } from "dt-audit-library";
11
10
  import { EventHandler } from "../handler/EventHandler";
12
11
  import { isEqual } from "lodash";
12
+ import { AlertService } from "./Alert.service";
13
+ import { getRedisClient, getPostgresClient } from "../../../db";
13
14
 
14
- export class DeviceService {
15
+ export class LocalDeviceService {
15
16
  private readonly baseUrl: string;
16
17
  private readonly source = "dt-common-device";
17
18
  private readonly eventHandler: EventHandler;
18
-
19
+ private readonly alertService: AlertService;
20
+ private readonly redis;
21
+ private readonly postgres;
19
22
  constructor() {
20
23
  const { DEVICE_SERVICE } = getConfig();
21
24
  if (!DEVICE_SERVICE) {
@@ -23,10 +26,13 @@ export class DeviceService {
23
26
  "DEVICE_SERVICE is not configured. Call initialize() first with DEVICE_SERVICE."
24
27
  );
25
28
  }
29
+ this.redis = getRedisClient();
30
+ this.postgres = getPostgresClient();
26
31
  this.baseUrl = DEVICE_SERVICE;
27
32
  checkAwsEnv();
28
33
  ensureAuditInitialized();
29
34
  this.eventHandler = new EventHandler();
35
+ this.alertService = new AlertService();
30
36
  }
31
37
 
32
38
  async createDevice(body: IDevice): Promise<void> {
@@ -103,14 +109,11 @@ export class DeviceService {
103
109
  }
104
110
 
105
111
  async setState(deviceId: string, state: any) {
106
- // If old status and new status are different
112
+ // If old state and new state are different
107
113
  const oldState = await this.getState(deviceId);
108
- if (!isEqual(oldState, state)) {
109
- this.eventHandler.onStateChange(deviceId, state);
114
+ if (!isEqual(oldState?.data?.state, state)) {
115
+ return await this.eventHandler.onStateChange(deviceId, state);
110
116
  }
111
- // If offline, check the time difference between the last offline status and current time
112
- // Compare it with the baseline profile time of the device. If the difference is higher, then raise an operational alert
113
- //deviceAlertService.raiseOperationalAlert();
114
117
  }
115
118
 
116
119
  async getStatus(deviceId: string) {
@@ -121,25 +124,43 @@ export class DeviceService {
121
124
  // If old status and new status are different
122
125
  const oldStatus = await this.getStatus(deviceId);
123
126
  if (!isEqual(oldStatus, status)) {
124
- this.eventHandler.onStatusChange(deviceId, status);
127
+ return await this.eventHandler.onStatusChange(deviceId, status);
128
+ }
129
+ // If both old and new status are offline, check the time difference between the last offline status and current time
130
+ if (
131
+ oldStatus?.data?.online === false &&
132
+ oldStatus?.data?.lastUpdated &&
133
+ status?.online === false
134
+ ) {
135
+ const lastOfflineTime = new Date(oldStatus?.data?.lastUpdated).getTime();
136
+ const currentTime = Date.now();
137
+ const timeDifference = currentTime - lastOfflineTime;
138
+ // Compare it with the baseline profile time of the device. If the difference is higher, then raise an operational alert
139
+ if (timeDifference > 1000 * 60 * 60 * 24) {
140
+ return await this.alertService.raiseOperationsAlert();
141
+ }
125
142
  }
126
- // If offline, check the time difference between the last offline status and current time
127
- // Compare it with the baseline profile time of the device. If the difference is higher, then raise an operational alert
128
- //deviceAlertService.raiseOperationalAlert();
129
143
  }
130
144
 
131
145
  async getBatteryLevel(deviceId: string) {
132
146
  return await axios.get(`${this.baseUrl}/devices/${deviceId}/battery-level`);
133
147
  }
134
148
  async setBatteryLevel(deviceId: string, batteryLevel: number) {
135
- // If old status and new status are different
136
-
137
- // and the last battery level received time more than 8 hours {
138
- this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel);
139
- // if(batteryLevel < propertySettingBatteryThreshold) {
140
- // deviceAlertService.raiseEnergyAlert({});
141
- // }
142
- // }
149
+ // If old battery level and new battery level are different
150
+ const oldBatteryLevel = await this.getBatteryLevel(deviceId);
151
+ if (!isEqual(oldBatteryLevel?.data?.value, batteryLevel)) {
152
+ this.eventHandler.onBatteryLevelChange(deviceId, batteryLevel);
153
+ }
154
+ // If current battery level is less than 20% and lsat updated time is more than 8 hours, raise an energy alert
155
+ if (
156
+ batteryLevel < 20 &&
157
+ oldBatteryLevel?.data?.value < 20 &&
158
+ new Date(oldBatteryLevel?.data?.lastUpdated).getTime() <
159
+ Date.now() - 1000 * 60 * 60 * 8
160
+ ) {
161
+ //TODO: Raise an energy alert
162
+ await this.alertService.raiseEnergyAlert();
163
+ }
143
164
  }
144
165
  async getMetaData(deviceId: string) {
145
166
  return await axios.get(`${this.baseUrl}/devices/${deviceId}/metaData`);
@@ -162,11 +183,25 @@ export class DeviceService {
162
183
 
163
184
  async getDeviceByZone(zoneId: string) {
164
185
  try {
165
- //Step 1: Check if zone data available in redis
166
- //Step 2: If not available, fetch uaing smart-cloud-node zone api
167
- //Step 3: Store the zone data in redis
168
- //Step 4: Return the zone data
169
- //Step 5: If zone data is available in redis, return the zone data
186
+ // Step 1: Check if zone data is available in Redis
187
+ let cached = await this.redis.get(`zone:${zoneId}`);
188
+ if (cached) {
189
+ // Parse if stored as JSON string
190
+ return typeof cached === "string" ? JSON.parse(cached) : cached;
191
+ }
192
+
193
+ // If not available, fetch from PostgreSQL DB
194
+ const result = await this.postgres.query(
195
+ "SELECT * FROM dt_devices WHERE zoneId = $1",
196
+ [zoneId]
197
+ );
198
+ if (result.rows.length > 0) {
199
+ // Store in Redis as JSON string
200
+ await this.redis.set(`zone:${zoneId}`, JSON.stringify(result.rows[0]));
201
+ return result.rows[0];
202
+ }
203
+ // If data is not available, return null
204
+ return null;
170
205
  } catch (error) {
171
206
  console.log(error);
172
207
  throw new Error("Failed to get device by zone");
@@ -175,14 +210,55 @@ export class DeviceService {
175
210
 
176
211
  async getDevicesByAccessGroup(accessGroupId: string) {
177
212
  try {
178
- //Step 1: Check if access group data available in redis
179
- //Step 2: If not available, fetch using smart-cloud-node access-group api
180
- //Step 3: Store the access group data in redis
181
- //Step 4: Return the access group data
182
- //Step 5: If access group data is available in redis, return the access group data
213
+ // Try to get from Redis
214
+ let cached = await this.redis.get(`accessGroup:${accessGroupId}`);
215
+ if (cached) {
216
+ return typeof cached === "string" ? JSON.parse(cached) : cached;
217
+ }
218
+ // Fetch from Postgres if not in cache
219
+ const result = await this.postgres.query(
220
+ "SELECT * FROM access_groups WHERE id = $1",
221
+ [accessGroupId]
222
+ );
223
+ if (result.rows.length > 0) {
224
+ // Cache in Redis as JSON string
225
+ await this.redis.set(
226
+ `accessGroup:${accessGroupId}`,
227
+ JSON.stringify(result.rows[0])
228
+ );
229
+ return result.rows[0];
230
+ }
231
+ return null;
183
232
  } catch (error) {
184
233
  console.log(error);
185
234
  throw new Error("Failed to get devices by access group");
186
235
  }
187
236
  }
237
+
238
+ async getPropertyPreferences(propertyId: string) {
239
+ try {
240
+ const propertyPreferences = await this.redis.get(
241
+ `propertyPreferences:${propertyId}`
242
+ );
243
+ if (!propertyPreferences) {
244
+ const propertyPreferences = await this.postgres.query(
245
+ "SELECT * FROM property_preferences WHERE property_id = $1",
246
+ [propertyId]
247
+ );
248
+ if (propertyPreferences.rows.length > 0) {
249
+ await this.redis.set(
250
+ `propertyPreferences:${propertyId}`,
251
+ propertyPreferences.rows[0]
252
+ );
253
+ return propertyPreferences.rows[0];
254
+ }
255
+ return null;
256
+ } else {
257
+ return propertyPreferences;
258
+ }
259
+ } catch (error) {
260
+ console.log(error);
261
+ throw new Error("Failed to get property preferences");
262
+ }
263
+ }
188
264
  }
@@ -1,2 +1,3 @@
1
- export { DeviceService as LocalDeviceService } from "./Device.service";
1
+ export { LocalDeviceService } from "./Device.service";
2
2
  export { HubService as LocalHubService } from "./Hub.service";
3
+ export { ConnectionService } from "./Connection.service";
package/src/index.ts CHANGED
@@ -3,16 +3,20 @@
3
3
  // Cloud exports
4
4
  export {
5
5
  CloudDeviceService,
6
- CloudHubService,
7
- CloudConnectionService,
6
+ ConnectionService as CloudConnectionService,
8
7
  } from "./device/cloud/services";
9
- export { LocalDeviceService, LocalHubService } from "./device/local/services";
8
+ export { CloudDevice, DeviceFactory } from "./device/cloud/entities";
9
+ export {
10
+ LocalDeviceService,
11
+ LocalHubService,
12
+ ConnectionService,
13
+ } from "./device/local/services";
10
14
 
11
- export * as cloudInterfaces from "./device/cloud/interfaces";
15
+ export * from "./device/cloud/interfaces";
12
16
  export * from "./device/cloud/types";
13
17
 
14
18
  // Local exports
15
- export * as localInterfaces from "./device/local/interfaces";
19
+ export * from "./device/local/interfaces";
16
20
 
17
21
  //initialize export
18
22
  export { initialize, getConfig } from "./config/config";
@@ -1,41 +0,0 @@
1
- import { IDeviceService } from "../interfaces";
2
- import { IConnection, IDevice } from "../types";
3
-
4
- export abstract class DeviceService implements IDeviceService {
5
- // IDevice properties
6
- deviceId!: string;
7
- propertyId!: string;
8
- name!: string;
9
- hubId!: string[];
10
- deviceType!: {
11
- id: string;
12
- type: string;
13
- };
14
- status!: {
15
- online: boolean;
16
- error?: {
17
- type?: string;
18
- message?: string;
19
- };
20
- lastUpdated?: string;
21
- };
22
- state?: Record<string, any>;
23
- metaData?: Record<string, any>;
24
- zone?: {
25
- id: string;
26
- name: string;
27
- zoneType: string;
28
- parentZone?: { id: string; name: string; zoneType: string };
29
- };
30
- connection!: IConnection;
31
-
32
- constructor(device: IDevice) {
33
- Object.assign(this, device);
34
- }
35
-
36
- abstract getDevices(connection: IConnection): Promise<Record<string, any>[]>;
37
- abstract getDevice(connectionId: string, deviceId: string): Promise<any>;
38
- abstract getBattery(deviceId: string): Promise<number | string>;
39
- abstract getStatus(connectionId: string, deviceId: string): Promise<string>;
40
- abstract getState(deviceId: string): Promise<string>;
41
- }
@@ -1,34 +0,0 @@
1
- import { IHubService } from "../interfaces";
2
- import { IConnection, IDevice } from "../types";
3
-
4
- export abstract class HubService implements IHubService {
5
- // IDevice properties
6
- deviceId!: string;
7
- propertyId!: string;
8
- name!: string;
9
- deviceType!: {
10
- id: string;
11
- type: string;
12
- };
13
- status!: {
14
- online: boolean;
15
- error?: {
16
- type?: string;
17
- message?: string;
18
- };
19
- lastUpdated?: string;
20
- };
21
- metaData?: Record<string, any>;
22
- connection!: IConnection;
23
-
24
- constructor(hub: IDevice) {
25
- Object.assign(this, hub);
26
- }
27
-
28
- abstract getHubs(connectionId: string): Promise<any[] | null>;
29
- abstract getHub(
30
- connectionId: string,
31
- hubId: string
32
- ): Promise<Record<string, any>>;
33
- abstract getStatus(connectionId: string, hubId: string): Promise<string>;
34
- }