dt-common-device 1.0.13 → 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.
- package/README.md +15 -35
- package/dist/config/config.d.ts +13 -0
- package/dist/config/config.js +30 -0
- package/dist/db/db.d.ts +2 -0
- package/dist/db/db.js +15 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.js +18 -0
- package/dist/db/redis.d.ts +2 -0
- package/dist/db/redis.js +22 -0
- package/dist/device/cloud/entities/CloudDevice.d.ts +8 -3
- package/dist/device/cloud/entities/CloudDevice.js +33 -5
- package/dist/device/cloud/entities/DeviceFactory.js +1 -1
- package/dist/device/cloud/interfaces/ICloudDevice.d.ts +4 -0
- package/dist/device/cloud/interfaces/ICloudDeviceService.d.ts +1 -1
- package/dist/device/cloud/interfaces/IConnectionService.js +0 -1
- package/dist/device/cloud/services/CloudDevice.service.d.ts +2 -2
- package/dist/device/cloud/services/CloudDevice.service.js +0 -3
- package/dist/device/cloud/services/Connection.service.d.ts +1 -1
- package/dist/device/cloud/types.d.ts +9 -9
- package/dist/device/cloud/types.js +0 -12
- package/dist/device/local/interfaces/IConnection.d.ts +16 -0
- package/dist/device/local/interfaces/IConnection.js +2 -0
- package/dist/device/local/interfaces/IDevice.d.ts +4 -0
- package/dist/device/local/services/Connection.service.d.ts +5 -0
- package/dist/device/local/services/Connection.service.js +14 -0
- package/dist/device/local/services/Device.service.d.ts +6 -3
- package/dist/device/local/services/Device.service.js +54 -14
- package/dist/device/local/services/index.d.ts +2 -1
- package/dist/device/local/services/index.js +4 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/package.json +7 -9
- package/src/config/config.ts +31 -0
- package/src/db/db.ts +15 -0
- package/src/db/index.ts +2 -0
- package/src/db/redis.ts +18 -0
- package/src/device/cloud/entities/CloudDevice.ts +43 -6
- package/src/device/cloud/entities/DeviceFactory.ts +3 -3
- package/src/device/cloud/interfaces/ICloudDevice.ts +8 -0
- package/src/device/cloud/interfaces/ICloudDeviceService.ts +1 -1
- package/src/device/cloud/interfaces/IConnectionService.ts +0 -2
- package/src/device/cloud/services/CloudDevice.service.ts +2 -4
- package/src/device/cloud/services/Connection.service.ts +1 -1
- package/src/device/cloud/types.ts +9 -10
- package/src/device/local/interfaces/IConnection.ts +17 -0
- package/src/device/local/interfaces/IDevice.ts +4 -0
- package/src/device/local/interfaces/index.ts +1 -1
- package/src/device/local/services/Connection.service.ts +15 -0
- package/src/device/local/services/Device.service.ts +71 -13
- package/src/device/local/services/index.ts +2 -1
- package/src/index.ts +5 -1
package/README.md
CHANGED
|
@@ -20,6 +20,20 @@ npm install dt-common-device
|
|
|
20
20
|
- `dt-common-device` will automatically initialize audit logging using these environment variables when you create a local device service.
|
|
21
21
|
- If either variable is missing, the library will throw a clear error at runtime.
|
|
22
22
|
|
|
23
|
+
## Environment Variables
|
|
24
|
+
|
|
25
|
+
This library requires the following environment variable to be set in your project's environment or in a `.env` file:
|
|
26
|
+
|
|
27
|
+
- `POSTGRESQL_DB_URI`: The connection URI for your PostgreSQL database.
|
|
28
|
+
|
|
29
|
+
Example `.env` file:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
POSTGRESQL_DB_URI=postgres://username:password@host:port/database
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The library will throw an error if this variable is not set when attempting to connect to the database.
|
|
36
|
+
|
|
23
37
|
---
|
|
24
38
|
|
|
25
39
|
## Initialization (Required)
|
|
@@ -176,38 +190,4 @@ import { IDevice, IHub, IConnection } from "dt-common-device";
|
|
|
176
190
|
|
|
177
191
|
- You **must** call `initialize()` before using any service. If not, you will get a runtime error.
|
|
178
192
|
- **You must set `POSTHOG_API_KEY` and `POSTHOG_HOST` in your environment before using any local device service.**
|
|
179
|
-
- You do **not** need to call `initializeAudit()
|
|
180
|
-
- Cloud service methods are stubs and must be implemented by the consuming project.
|
|
181
|
-
- All types are strongly typed for TypeScript support.
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## Example Usage
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
import {
|
|
189
|
-
initialize,
|
|
190
|
-
CloudDeviceService,
|
|
191
|
-
LocalDeviceService,
|
|
192
|
-
IDevice,
|
|
193
|
-
} from "dt-common-device";
|
|
194
|
-
|
|
195
|
-
initialize({
|
|
196
|
-
DEVICE_SERVICE: "https://api.example.com/device",
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const cloudService = new CloudDeviceService();
|
|
200
|
-
const localService = new LocalDeviceService();
|
|
201
|
-
|
|
202
|
-
async function main() {
|
|
203
|
-
// Example: get devices from cloud (must implement in your project)
|
|
204
|
-
// const devices: IDevice[] = await cloudService.getDevices(connection);
|
|
205
|
-
|
|
206
|
-
// Example: create a device locally
|
|
207
|
-
await localService.createDevice({
|
|
208
|
-
/* device params */
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
main();
|
|
213
|
-
```
|
|
193
|
+
- You do **not** need to call `initializeAudit()`
|
package/dist/config/config.d.ts
CHANGED
|
@@ -3,3 +3,16 @@ export declare function initialize(cfg: DeviceConfig): void;
|
|
|
3
3
|
export declare function getConfig(): DeviceConfig;
|
|
4
4
|
export declare function checkAwsEnv(): void;
|
|
5
5
|
export declare function ensureAuditInitialized(): void;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the PostgreSQL DB URI from environment variables.
|
|
8
|
+
* Throws an error if not set.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getPostgresDbUri(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the Redis DB Host and port from environment variables.
|
|
13
|
+
* Throws an error if not set.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getRedisDbHostAndPort(): {
|
|
16
|
+
host: string;
|
|
17
|
+
port: number;
|
|
18
|
+
};
|
package/dist/config/config.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.initialize = initialize;
|
|
4
7
|
exports.getConfig = getConfig;
|
|
5
8
|
exports.checkAwsEnv = checkAwsEnv;
|
|
6
9
|
exports.ensureAuditInitialized = ensureAuditInitialized;
|
|
10
|
+
exports.getPostgresDbUri = getPostgresDbUri;
|
|
11
|
+
exports.getRedisDbHostAndPort = getRedisDbHostAndPort;
|
|
7
12
|
const dt_audit_library_1 = require("dt-audit-library");
|
|
13
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
14
|
+
dotenv_1.default.config();
|
|
8
15
|
let config = null;
|
|
9
16
|
let auditInitialized = false;
|
|
10
17
|
function initialize(cfg) {
|
|
@@ -50,3 +57,26 @@ function ensureAuditInitialized() {
|
|
|
50
57
|
(0, dt_audit_library_1.initializeAudit)(apiKey, host);
|
|
51
58
|
auditInitialized = true;
|
|
52
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the PostgreSQL DB URI from environment variables.
|
|
62
|
+
* Throws an error if not set.
|
|
63
|
+
*/
|
|
64
|
+
function getPostgresDbUri() {
|
|
65
|
+
const uri = process.env.DATABASE_URL;
|
|
66
|
+
if (!uri) {
|
|
67
|
+
throw new Error("dt-common-device: POSTGRESQL_DB_URI must be set in environment variables or .env file");
|
|
68
|
+
}
|
|
69
|
+
return uri;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the Redis DB Host and port from environment variables.
|
|
73
|
+
* Throws an error if not set.
|
|
74
|
+
*/
|
|
75
|
+
function getRedisDbHostAndPort() {
|
|
76
|
+
const host = process.env.REDIS_HOST;
|
|
77
|
+
const port = process.env.REDIS_PORT;
|
|
78
|
+
if (!host || !port) {
|
|
79
|
+
throw new Error("dt-common-device: REDIS_HOST and REDIS_PORT must be set in environment variables");
|
|
80
|
+
}
|
|
81
|
+
return { host, port: Number(port) };
|
|
82
|
+
}
|
package/dist/db/db.d.ts
ADDED
package/dist/db/db.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPostgresClient = getPostgresClient;
|
|
4
|
+
const pg_1 = require("pg");
|
|
5
|
+
const config_1 = require("../config/config");
|
|
6
|
+
const dbUri = (0, config_1.getPostgresDbUri)();
|
|
7
|
+
let pool = null;
|
|
8
|
+
function getPostgresClient() {
|
|
9
|
+
if (!pool) {
|
|
10
|
+
pool = new pg_1.Pool({
|
|
11
|
+
connectionString: dbUri,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return pool;
|
|
15
|
+
}
|
package/dist/db/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./db"), exports);
|
|
18
|
+
__exportStar(require("./redis"), exports);
|
package/dist/db/redis.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getRedisClient = getRedisClient;
|
|
7
|
+
const config_1 = require("../config/config");
|
|
8
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
9
|
+
let redisClient = null;
|
|
10
|
+
function getRedisClient() {
|
|
11
|
+
if (!redisClient) {
|
|
12
|
+
const { host, port } = (0, config_1.getRedisDbHostAndPort)();
|
|
13
|
+
redisClient = new ioredis_1.default({
|
|
14
|
+
host,
|
|
15
|
+
port,
|
|
16
|
+
});
|
|
17
|
+
redisClient.on("error", (error) => {
|
|
18
|
+
console.error("Redis error:", error);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return redisClient;
|
|
22
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { IDevice } from "../../local/interfaces";
|
|
1
2
|
import { ICloudDevice } from "../interfaces/ICloudDevice";
|
|
2
3
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
3
4
|
import { IConnection } from "../types";
|
|
4
5
|
export declare abstract class CloudDevice implements ICloudDevice {
|
|
5
6
|
deviceId: string;
|
|
6
|
-
|
|
7
|
+
localDevice?: IDevice;
|
|
8
|
+
connection?: IConnection;
|
|
7
9
|
cloudDeviceService: ICloudDeviceService;
|
|
8
|
-
constructor(
|
|
9
|
-
|
|
10
|
+
constructor(device: IDevice, cloudDeviceService: ICloudDeviceService);
|
|
11
|
+
getDevice(connectionId: string, deviceId: string): Promise<Record<string, any>>;
|
|
12
|
+
getBattery(deviceId: string): Promise<number | string>;
|
|
13
|
+
getState(deviceId: string): Promise<string>;
|
|
14
|
+
getStatus(connectionId: string, deviceId: string): Promise<string>;
|
|
10
15
|
}
|
|
@@ -2,13 +2,41 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CloudDevice = void 0;
|
|
4
4
|
class CloudDevice {
|
|
5
|
-
constructor(
|
|
6
|
-
this.deviceId = deviceId;
|
|
5
|
+
constructor(device, cloudDeviceService) {
|
|
6
|
+
this.deviceId = device.deviceId;
|
|
7
|
+
this.localDevice = device;
|
|
7
8
|
this.cloudDeviceService = cloudDeviceService;
|
|
8
|
-
this.connection = this.getConnection(deviceId);
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
async getDevice(connectionId, deviceId) {
|
|
11
|
+
throw new Error("Method not implemented in Super Class.");
|
|
12
|
+
}
|
|
13
|
+
async getBattery(deviceId) {
|
|
14
|
+
throw new Error("Method not implemented in Super Class.");
|
|
15
|
+
}
|
|
16
|
+
async getState(deviceId) {
|
|
17
|
+
throw new Error("Method not implemented in Super Class.");
|
|
18
|
+
}
|
|
19
|
+
async getStatus(connectionId, deviceId) {
|
|
20
|
+
throw new Error("Method not implemented in Super Class.");
|
|
12
21
|
}
|
|
13
22
|
}
|
|
14
23
|
exports.CloudDevice = CloudDevice;
|
|
24
|
+
/*
|
|
25
|
+
Usage Example:
|
|
26
|
+
|
|
27
|
+
// When extending CloudDevice, you can now do:
|
|
28
|
+
class MyCloudDevice extends CloudDevice {
|
|
29
|
+
constructor(device: IDevice, cloudDeviceService: ICloudDeviceService) {
|
|
30
|
+
super(device, cloudDeviceService);
|
|
31
|
+
// Additional initialization if needed
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Create and initialize in one step:
|
|
36
|
+
const device = await MyCloudDevice.create(device, cloudDeviceService);
|
|
37
|
+
// The device is now fully initialized with connection and localDevice loaded
|
|
38
|
+
|
|
39
|
+
// Or if you need to create without auto-initialization:
|
|
40
|
+
const device = new MyCloudDevice(device, cloudDeviceService);
|
|
41
|
+
await device.initialize(); // Manual initialization
|
|
42
|
+
*/
|
|
@@ -4,7 +4,7 @@ exports.DeviceFactory = void 0;
|
|
|
4
4
|
const Device_service_1 = require("../../local/services/Device.service");
|
|
5
5
|
class DeviceFactory {
|
|
6
6
|
constructor() {
|
|
7
|
-
this.localDeviceService = new Device_service_1.
|
|
7
|
+
this.localDeviceService = new Device_service_1.LocalDeviceService();
|
|
8
8
|
}
|
|
9
9
|
async getDevice(deviceId) {
|
|
10
10
|
return await this.localDeviceService.getDevice(deviceId);
|
|
@@ -2,4 +2,8 @@ import { ICloudDeviceService } from "./ICloudDeviceService";
|
|
|
2
2
|
export interface ICloudDevice {
|
|
3
3
|
deviceId: string;
|
|
4
4
|
cloudDeviceService: ICloudDeviceService;
|
|
5
|
+
getDevice(connectionId: string, deviceId: string): Promise<Record<string, any>>;
|
|
6
|
+
getBattery(deviceId: string): Promise<number | string>;
|
|
7
|
+
getState(deviceId: string): Promise<string>;
|
|
8
|
+
getStatus(connectionId: string, deviceId: string): Promise<string>;
|
|
5
9
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
2
2
|
import { IConnection } from "../types";
|
|
3
|
-
export declare class CloudDeviceService implements ICloudDeviceService {
|
|
4
|
-
getConnection(deviceId: string): IConnection
|
|
3
|
+
export declare abstract class CloudDeviceService implements ICloudDeviceService {
|
|
4
|
+
abstract getConnection(deviceId: string): Promise<IConnection>;
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IConnectionService } from "../interfaces";
|
|
2
|
-
import {
|
|
2
|
+
import { IDeviceAccountResponse, IConnectionConnectParams, IConnection } from "../types";
|
|
3
3
|
export declare abstract class ConnectionService implements IConnectionService {
|
|
4
4
|
abstract createConnection(data: IConnection, userId: string): Promise<any>;
|
|
5
5
|
abstract getDeviceAccount(connection: IConnection): Promise<IDeviceAccountResponse>;
|
|
@@ -39,13 +39,13 @@ export interface IConnectionConnectParams {
|
|
|
39
39
|
propertyId?: string;
|
|
40
40
|
[key: string]: unknown;
|
|
41
41
|
}
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
export interface ConnectionProvider {
|
|
43
|
+
DEVICETHREAD: "Devicethread";
|
|
44
|
+
SMARTTHINGS: "Smartthings";
|
|
45
|
+
SALTOKS: "SaltoKS";
|
|
46
|
+
TUYA: "Tuya";
|
|
47
|
+
TTLOCK: "TTLock";
|
|
48
|
+
SCHLAGE: "Schlage";
|
|
49
|
+
YALEWIFI: "YaleWifi";
|
|
50
|
+
SENSIBO: "Sensibo";
|
|
51
51
|
}
|
|
@@ -1,15 +1,3 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Device Cloud Type Interfaces for DeviceThread Common Library
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.ConnectionProvider = void 0;
|
|
5
|
-
var ConnectionProvider;
|
|
6
|
-
(function (ConnectionProvider) {
|
|
7
|
-
ConnectionProvider["Devicethread"] = "Devicethread";
|
|
8
|
-
ConnectionProvider["Smartthings"] = "Smartthings";
|
|
9
|
-
ConnectionProvider["SaltoKS"] = "SaltoKS";
|
|
10
|
-
ConnectionProvider["Tuya"] = "Tuya";
|
|
11
|
-
ConnectionProvider["TTLock"] = "TTLock";
|
|
12
|
-
ConnectionProvider["Schlage"] = "Schlage";
|
|
13
|
-
ConnectionProvider["YaleWifi"] = "YaleWifi";
|
|
14
|
-
ConnectionProvider["Sensibo"] = "Sensibo";
|
|
15
|
-
})(ConnectionProvider || (exports.ConnectionProvider = ConnectionProvider = {}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ConnectionProvider } from "../../cloud/types";
|
|
2
|
+
export interface IConnection {
|
|
3
|
+
id?: string;
|
|
4
|
+
createdAt?: Date;
|
|
5
|
+
updatedAt?: Date;
|
|
6
|
+
isDeleted?: boolean;
|
|
7
|
+
connectionName: string;
|
|
8
|
+
connectionRefId: string;
|
|
9
|
+
propertyId: string;
|
|
10
|
+
connectionProvider: ConnectionProvider;
|
|
11
|
+
accessToken?: string;
|
|
12
|
+
clientId?: string;
|
|
13
|
+
clientSecret?: string;
|
|
14
|
+
isActive?: boolean;
|
|
15
|
+
metaData?: any;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionService = void 0;
|
|
4
|
+
const db_1 = require("../../../db");
|
|
5
|
+
class ConnectionService {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.pool = (0, db_1.getPostgresClient)();
|
|
8
|
+
}
|
|
9
|
+
async getConnection(connectionId) {
|
|
10
|
+
const result = await this.pool.query("SELECT * FROM dt_connections WHERE id = $1", [connectionId]);
|
|
11
|
+
return result.rows[0];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.ConnectionService = ConnectionService;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { IDevice } from "../interfaces";
|
|
2
|
-
export declare class
|
|
2
|
+
export declare class LocalDeviceService {
|
|
3
3
|
private readonly baseUrl;
|
|
4
4
|
private readonly source;
|
|
5
5
|
private readonly eventHandler;
|
|
6
6
|
private readonly alertService;
|
|
7
|
+
private readonly redis;
|
|
8
|
+
private readonly postgres;
|
|
7
9
|
constructor();
|
|
8
10
|
createDevice(body: IDevice): Promise<void>;
|
|
9
11
|
getDevice(deviceId: string, withHubDetails?: boolean): Promise<IDevice>;
|
|
@@ -19,6 +21,7 @@ export declare class DeviceService {
|
|
|
19
21
|
setBatteryLevel(deviceId: string, batteryLevel: number): Promise<void>;
|
|
20
22
|
getMetaData(deviceId: string): Promise<import("axios").AxiosResponse<any, any>>;
|
|
21
23
|
setMetaData(deviceId: string, metaData: Record<string, any>): Promise<void>;
|
|
22
|
-
getDeviceByZone(zoneId: string): Promise<
|
|
23
|
-
getDevicesByAccessGroup(accessGroupId: string): Promise<
|
|
24
|
+
getDeviceByZone(zoneId: string): Promise<any>;
|
|
25
|
+
getDevicesByAccessGroup(accessGroupId: string): Promise<any>;
|
|
26
|
+
getPropertyPreferences(propertyId: string): Promise<any>;
|
|
24
27
|
}
|
|
@@ -3,8 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
//TODO: Import Redis
|
|
6
|
+
exports.LocalDeviceService = void 0;
|
|
8
7
|
const axios_1 = __importDefault(require("axios"));
|
|
9
8
|
const config_1 = require("../../../config/config");
|
|
10
9
|
const dt_pub_sub_1 = require("dt-pub-sub");
|
|
@@ -12,13 +11,16 @@ const dt_audit_library_1 = require("dt-audit-library");
|
|
|
12
11
|
const EventHandler_1 = require("../handler/EventHandler");
|
|
13
12
|
const lodash_1 = require("lodash");
|
|
14
13
|
const Alert_service_1 = require("./Alert.service");
|
|
15
|
-
|
|
14
|
+
const db_1 = require("../../../db");
|
|
15
|
+
class LocalDeviceService {
|
|
16
16
|
constructor() {
|
|
17
17
|
this.source = "dt-common-device";
|
|
18
18
|
const { DEVICE_SERVICE } = (0, config_1.getConfig)();
|
|
19
19
|
if (!DEVICE_SERVICE) {
|
|
20
20
|
throw new Error("DEVICE_SERVICE is not configured. Call initialize() first with DEVICE_SERVICE.");
|
|
21
21
|
}
|
|
22
|
+
this.redis = (0, db_1.getRedisClient)();
|
|
23
|
+
this.postgres = (0, db_1.getPostgresClient)();
|
|
22
24
|
this.baseUrl = DEVICE_SERVICE;
|
|
23
25
|
(0, config_1.checkAwsEnv)();
|
|
24
26
|
(0, config_1.ensureAuditInitialized)();
|
|
@@ -135,11 +137,21 @@ class DeviceService {
|
|
|
135
137
|
}
|
|
136
138
|
async getDeviceByZone(zoneId) {
|
|
137
139
|
try {
|
|
138
|
-
//Step 1: Check if zone data available in
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
// Step 1: Check if zone data is available in Redis
|
|
141
|
+
let cached = await this.redis.get(`zone:${zoneId}`);
|
|
142
|
+
if (cached) {
|
|
143
|
+
// Parse if stored as JSON string
|
|
144
|
+
return typeof cached === "string" ? JSON.parse(cached) : cached;
|
|
145
|
+
}
|
|
146
|
+
// If not available, fetch from PostgreSQL DB
|
|
147
|
+
const result = await this.postgres.query("SELECT * FROM dt_devices WHERE zoneId = $1", [zoneId]);
|
|
148
|
+
if (result.rows.length > 0) {
|
|
149
|
+
// Store in Redis as JSON string
|
|
150
|
+
await this.redis.set(`zone:${zoneId}`, JSON.stringify(result.rows[0]));
|
|
151
|
+
return result.rows[0];
|
|
152
|
+
}
|
|
153
|
+
// If data is not available, return null
|
|
154
|
+
return null;
|
|
143
155
|
}
|
|
144
156
|
catch (error) {
|
|
145
157
|
console.log(error);
|
|
@@ -148,16 +160,44 @@ class DeviceService {
|
|
|
148
160
|
}
|
|
149
161
|
async getDevicesByAccessGroup(accessGroupId) {
|
|
150
162
|
try {
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
// Try to get from Redis
|
|
164
|
+
let cached = await this.redis.get(`accessGroup:${accessGroupId}`);
|
|
165
|
+
if (cached) {
|
|
166
|
+
return typeof cached === "string" ? JSON.parse(cached) : cached;
|
|
167
|
+
}
|
|
168
|
+
// Fetch from Postgres if not in cache
|
|
169
|
+
const result = await this.postgres.query("SELECT * FROM access_groups WHERE id = $1", [accessGroupId]);
|
|
170
|
+
if (result.rows.length > 0) {
|
|
171
|
+
// Cache in Redis as JSON string
|
|
172
|
+
await this.redis.set(`accessGroup:${accessGroupId}`, JSON.stringify(result.rows[0]));
|
|
173
|
+
return result.rows[0];
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
156
176
|
}
|
|
157
177
|
catch (error) {
|
|
158
178
|
console.log(error);
|
|
159
179
|
throw new Error("Failed to get devices by access group");
|
|
160
180
|
}
|
|
161
181
|
}
|
|
182
|
+
async getPropertyPreferences(propertyId) {
|
|
183
|
+
try {
|
|
184
|
+
const propertyPreferences = await this.redis.get(`propertyPreferences:${propertyId}`);
|
|
185
|
+
if (!propertyPreferences) {
|
|
186
|
+
const propertyPreferences = await this.postgres.query("SELECT * FROM property_preferences WHERE property_id = $1", [propertyId]);
|
|
187
|
+
if (propertyPreferences.rows.length > 0) {
|
|
188
|
+
await this.redis.set(`propertyPreferences:${propertyId}`, propertyPreferences.rows[0]);
|
|
189
|
+
return propertyPreferences.rows[0];
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
return propertyPreferences;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
console.log(error);
|
|
199
|
+
throw new Error("Failed to get property preferences");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
162
202
|
}
|
|
163
|
-
exports.
|
|
203
|
+
exports.LocalDeviceService = LocalDeviceService;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LocalHubService = exports.LocalDeviceService = void 0;
|
|
3
|
+
exports.ConnectionService = exports.LocalHubService = exports.LocalDeviceService = void 0;
|
|
4
4
|
var Device_service_1 = require("./Device.service");
|
|
5
|
-
Object.defineProperty(exports, "LocalDeviceService", { enumerable: true, get: function () { return Device_service_1.
|
|
5
|
+
Object.defineProperty(exports, "LocalDeviceService", { enumerable: true, get: function () { return Device_service_1.LocalDeviceService; } });
|
|
6
6
|
var Hub_service_1 = require("./Hub.service");
|
|
7
7
|
Object.defineProperty(exports, "LocalHubService", { enumerable: true, get: function () { return Hub_service_1.HubService; } });
|
|
8
|
+
var Connection_service_1 = require("./Connection.service");
|
|
9
|
+
Object.defineProperty(exports, "ConnectionService", { enumerable: true, get: function () { return Connection_service_1.ConnectionService; } });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { CloudDeviceService, ConnectionService as CloudConnectionService, } from "./device/cloud/services";
|
|
2
2
|
export { CloudDevice, DeviceFactory } from "./device/cloud/entities";
|
|
3
|
-
export { LocalDeviceService, LocalHubService } from "./device/local/services";
|
|
3
|
+
export { LocalDeviceService, LocalHubService, ConnectionService, } from "./device/local/services";
|
|
4
4
|
export * from "./device/cloud/interfaces";
|
|
5
5
|
export * from "./device/cloud/types";
|
|
6
6
|
export * from "./device/local/interfaces";
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.getConfig = exports.initialize = exports.LocalHubService = exports.LocalDeviceService = exports.DeviceFactory = exports.CloudDevice = exports.CloudConnectionService = exports.CloudDeviceService = void 0;
|
|
18
|
+
exports.getConfig = exports.initialize = exports.ConnectionService = exports.LocalHubService = exports.LocalDeviceService = exports.DeviceFactory = exports.CloudDevice = exports.CloudConnectionService = exports.CloudDeviceService = void 0;
|
|
19
19
|
// Cloud exports
|
|
20
20
|
var services_1 = require("./device/cloud/services");
|
|
21
21
|
Object.defineProperty(exports, "CloudDeviceService", { enumerable: true, get: function () { return services_1.CloudDeviceService; } });
|
|
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "DeviceFactory", { enumerable: true, get: functio
|
|
|
26
26
|
var services_2 = require("./device/local/services");
|
|
27
27
|
Object.defineProperty(exports, "LocalDeviceService", { enumerable: true, get: function () { return services_2.LocalDeviceService; } });
|
|
28
28
|
Object.defineProperty(exports, "LocalHubService", { enumerable: true, get: function () { return services_2.LocalHubService; } });
|
|
29
|
+
Object.defineProperty(exports, "ConnectionService", { enumerable: true, get: function () { return services_2.ConnectionService; } });
|
|
29
30
|
__exportStar(require("./device/cloud/interfaces"), exports);
|
|
30
31
|
__exportStar(require("./device/cloud/types"), exports);
|
|
31
32
|
// Local exports
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dt-common-device",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -30,19 +30,17 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/lodash": "^4.17.19",
|
|
32
32
|
"@types/node": "^20.0.0",
|
|
33
|
+
"@types/pg": "8.15.4",
|
|
33
34
|
"ts-node": "^10.9.2",
|
|
34
35
|
"typescript": "^5.8.3"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"axios": "
|
|
38
|
+
"axios": "1.10.0",
|
|
38
39
|
"dt-audit-library": "^1.0.3",
|
|
39
40
|
"dt-pub-sub": "^1.0.0",
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
},
|
|
45
|
-
"overrides": {
|
|
46
|
-
"axios": "^1.10.0"
|
|
41
|
+
"ioredis": "5.6.1",
|
|
42
|
+
"lodash": "^4.17.21",
|
|
43
|
+
"pg": "8.16.3",
|
|
44
|
+
"redis": "5.5.6"
|
|
47
45
|
}
|
|
48
46
|
}
|
package/src/config/config.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DeviceConfig } from "../types";
|
|
2
2
|
import { initializeAudit } from "dt-audit-library";
|
|
3
|
+
import dotenv from "dotenv";
|
|
4
|
+
dotenv.config();
|
|
3
5
|
|
|
4
6
|
let config: DeviceConfig | null = null;
|
|
5
7
|
let auditInitialized = false;
|
|
@@ -61,3 +63,32 @@ export function ensureAuditInitialized() {
|
|
|
61
63
|
initializeAudit(apiKey, host);
|
|
62
64
|
auditInitialized = true;
|
|
63
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns the PostgreSQL DB URI from environment variables.
|
|
69
|
+
* Throws an error if not set.
|
|
70
|
+
*/
|
|
71
|
+
export function getPostgresDbUri(): string {
|
|
72
|
+
const uri = process.env.DATABASE_URL;
|
|
73
|
+
if (!uri) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"dt-common-device: POSTGRESQL_DB_URI must be set in environment variables or .env file"
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return uri;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Returns the Redis DB Host and port from environment variables.
|
|
83
|
+
* Throws an error if not set.
|
|
84
|
+
*/
|
|
85
|
+
export function getRedisDbHostAndPort(): { host: string; port: number } {
|
|
86
|
+
const host = process.env.REDIS_HOST;
|
|
87
|
+
const port = process.env.REDIS_PORT;
|
|
88
|
+
if (!host || !port) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
"dt-common-device: REDIS_HOST and REDIS_PORT must be set in environment variables"
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return { host, port: Number(port) };
|
|
94
|
+
}
|
package/src/db/db.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Pool } from "pg";
|
|
2
|
+
import { getPostgresDbUri } from "../config/config";
|
|
3
|
+
|
|
4
|
+
const dbUri = getPostgresDbUri();
|
|
5
|
+
|
|
6
|
+
let pool: Pool | null = null;
|
|
7
|
+
|
|
8
|
+
export function getPostgresClient() {
|
|
9
|
+
if (!pool) {
|
|
10
|
+
pool = new Pool({
|
|
11
|
+
connectionString: dbUri,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return pool;
|
|
15
|
+
}
|
package/src/db/index.ts
ADDED
package/src/db/redis.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getRedisDbHostAndPort } from "../config/config";
|
|
2
|
+
import Redis from "ioredis";
|
|
3
|
+
|
|
4
|
+
let redisClient: Redis | null = null;
|
|
5
|
+
|
|
6
|
+
export function getRedisClient() {
|
|
7
|
+
if (!redisClient) {
|
|
8
|
+
const { host, port } = getRedisDbHostAndPort();
|
|
9
|
+
redisClient = new Redis({
|
|
10
|
+
host,
|
|
11
|
+
port,
|
|
12
|
+
});
|
|
13
|
+
redisClient.on("error", (error) => {
|
|
14
|
+
console.error("Redis error:", error);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return redisClient;
|
|
18
|
+
}
|
|
@@ -1,19 +1,56 @@
|
|
|
1
|
+
import { IDevice } from "../../local/interfaces";
|
|
1
2
|
import { ICloudDevice } from "../interfaces/ICloudDevice";
|
|
2
3
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
3
4
|
import { IConnection } from "../types";
|
|
4
5
|
|
|
5
6
|
export abstract class CloudDevice implements ICloudDevice {
|
|
6
7
|
deviceId: string;
|
|
7
|
-
|
|
8
|
+
localDevice?: IDevice;
|
|
9
|
+
connection?: IConnection;
|
|
8
10
|
cloudDeviceService: ICloudDeviceService;
|
|
9
11
|
|
|
10
|
-
constructor(
|
|
11
|
-
this.deviceId = deviceId;
|
|
12
|
+
constructor(device: IDevice, cloudDeviceService: ICloudDeviceService) {
|
|
13
|
+
this.deviceId = device.deviceId;
|
|
14
|
+
this.localDevice = device;
|
|
12
15
|
this.cloudDeviceService = cloudDeviceService;
|
|
13
|
-
this.connection = this.getConnection(deviceId);
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
async getDevice(
|
|
19
|
+
connectionId: string,
|
|
20
|
+
deviceId: string
|
|
21
|
+
): Promise<Record<string, any>> {
|
|
22
|
+
throw new Error("Method not implemented in Super Class.");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async getBattery(deviceId: string): Promise<number | string> {
|
|
26
|
+
throw new Error("Method not implemented in Super Class.");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getState(deviceId: string): Promise<string> {
|
|
30
|
+
throw new Error("Method not implemented in Super Class.");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async getStatus(connectionId: string, deviceId: string): Promise<string> {
|
|
34
|
+
throw new Error("Method not implemented in Super Class.");
|
|
18
35
|
}
|
|
19
36
|
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
Usage Example:
|
|
40
|
+
|
|
41
|
+
// When extending CloudDevice, you can now do:
|
|
42
|
+
class MyCloudDevice extends CloudDevice {
|
|
43
|
+
constructor(device: IDevice, cloudDeviceService: ICloudDeviceService) {
|
|
44
|
+
super(device, cloudDeviceService);
|
|
45
|
+
// Additional initialization if needed
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create and initialize in one step:
|
|
50
|
+
const device = await MyCloudDevice.create(device, cloudDeviceService);
|
|
51
|
+
// The device is now fully initialized with connection and localDevice loaded
|
|
52
|
+
|
|
53
|
+
// Or if you need to create without auto-initialization:
|
|
54
|
+
const device = new MyCloudDevice(device, cloudDeviceService);
|
|
55
|
+
await device.initialize(); // Manual initialization
|
|
56
|
+
*/
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { IDevice } from "../../local/interfaces";
|
|
2
|
-
import {
|
|
2
|
+
import { LocalDeviceService } from "../../local/services/Device.service";
|
|
3
3
|
|
|
4
4
|
export class DeviceFactory {
|
|
5
|
-
private readonly localDeviceService:
|
|
5
|
+
private readonly localDeviceService: LocalDeviceService;
|
|
6
6
|
|
|
7
7
|
constructor() {
|
|
8
|
-
this.localDeviceService = new
|
|
8
|
+
this.localDeviceService = new LocalDeviceService();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
async getDevice(deviceId: string): Promise<IDevice> {
|
|
@@ -4,4 +4,12 @@ import { ICloudDeviceService } from "./ICloudDeviceService";
|
|
|
4
4
|
export interface ICloudDevice {
|
|
5
5
|
deviceId: string;
|
|
6
6
|
cloudDeviceService: ICloudDeviceService;
|
|
7
|
+
|
|
8
|
+
getDevice(
|
|
9
|
+
connectionId: string,
|
|
10
|
+
deviceId: string
|
|
11
|
+
): Promise<Record<string, any>>;
|
|
12
|
+
getBattery(deviceId: string): Promise<number | string>;
|
|
13
|
+
getState(deviceId: string): Promise<string>;
|
|
14
|
+
getStatus(connectionId: string, deviceId: string): Promise<string>;
|
|
7
15
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
2
2
|
import { IConnection } from "../types";
|
|
3
3
|
|
|
4
|
-
export class CloudDeviceService implements ICloudDeviceService {
|
|
5
|
-
getConnection(deviceId: string): IConnection
|
|
6
|
-
throw new Error("Method not implemented.");
|
|
7
|
-
}
|
|
4
|
+
export abstract class CloudDeviceService implements ICloudDeviceService {
|
|
5
|
+
abstract getConnection(deviceId: string): Promise<IConnection>;
|
|
8
6
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Device Cloud Service - Class Implementation
|
|
2
2
|
import { IConnectionService } from "../interfaces";
|
|
3
3
|
import {
|
|
4
|
-
IConnection,
|
|
5
4
|
IDeviceAccountResponse,
|
|
6
5
|
IConnectionConnectParams,
|
|
6
|
+
IConnection,
|
|
7
7
|
} from "../types";
|
|
8
8
|
|
|
9
9
|
export abstract class ConnectionService implements IConnectionService {
|
|
@@ -25,7 +25,6 @@ export interface IConnectionPagination {
|
|
|
25
25
|
limit: number;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
/**
|
|
30
29
|
* Device account response from provider.
|
|
31
30
|
* WARNING: Do not log or expose connection_access_token.
|
|
@@ -46,13 +45,13 @@ export interface IConnectionConnectParams {
|
|
|
46
45
|
[key: string]: unknown;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
export
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
export interface ConnectionProvider {
|
|
49
|
+
DEVICETHREAD: "Devicethread";
|
|
50
|
+
SMARTTHINGS: "Smartthings";
|
|
51
|
+
SALTOKS: "SaltoKS";
|
|
52
|
+
TUYA: "Tuya";
|
|
53
|
+
TTLOCK: "TTLock";
|
|
54
|
+
SCHLAGE: "Schlage";
|
|
55
|
+
YALEWIFI: "YaleWifi";
|
|
56
|
+
SENSIBO: "Sensibo";
|
|
58
57
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ConnectionProvider } from "../../cloud/types";
|
|
2
|
+
|
|
3
|
+
export interface IConnection {
|
|
4
|
+
id?: string;
|
|
5
|
+
createdAt?: Date;
|
|
6
|
+
updatedAt?: Date;
|
|
7
|
+
isDeleted?: boolean;
|
|
8
|
+
connectionName: string;
|
|
9
|
+
connectionRefId: string;
|
|
10
|
+
propertyId: string;
|
|
11
|
+
connectionProvider: ConnectionProvider;
|
|
12
|
+
accessToken?: string;
|
|
13
|
+
clientId?: string;
|
|
14
|
+
clientSecret?: string;
|
|
15
|
+
isActive?: boolean;
|
|
16
|
+
metaData?: any;
|
|
17
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./IDevice";
|
|
2
|
-
export * from "./IHub";
|
|
2
|
+
export * from "./IHub";
|
|
@@ -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,
|
|
@@ -11,13 +10,15 @@ import { publishAudit } from "dt-audit-library";
|
|
|
11
10
|
import { EventHandler } from "../handler/EventHandler";
|
|
12
11
|
import { isEqual } from "lodash";
|
|
13
12
|
import { AlertService } from "./Alert.service";
|
|
13
|
+
import { getRedisClient, getPostgresClient } from "../../../db";
|
|
14
14
|
|
|
15
|
-
export class
|
|
15
|
+
export class LocalDeviceService {
|
|
16
16
|
private readonly baseUrl: string;
|
|
17
17
|
private readonly source = "dt-common-device";
|
|
18
18
|
private readonly eventHandler: EventHandler;
|
|
19
19
|
private readonly alertService: AlertService;
|
|
20
|
-
|
|
20
|
+
private readonly redis;
|
|
21
|
+
private readonly postgres;
|
|
21
22
|
constructor() {
|
|
22
23
|
const { DEVICE_SERVICE } = getConfig();
|
|
23
24
|
if (!DEVICE_SERVICE) {
|
|
@@ -25,6 +26,8 @@ export class DeviceService {
|
|
|
25
26
|
"DEVICE_SERVICE is not configured. Call initialize() first with DEVICE_SERVICE."
|
|
26
27
|
);
|
|
27
28
|
}
|
|
29
|
+
this.redis = getRedisClient();
|
|
30
|
+
this.postgres = getPostgresClient();
|
|
28
31
|
this.baseUrl = DEVICE_SERVICE;
|
|
29
32
|
checkAwsEnv();
|
|
30
33
|
ensureAuditInitialized();
|
|
@@ -180,11 +183,25 @@ export class DeviceService {
|
|
|
180
183
|
|
|
181
184
|
async getDeviceByZone(zoneId: string) {
|
|
182
185
|
try {
|
|
183
|
-
//Step 1: Check if zone data available in
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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;
|
|
188
205
|
} catch (error) {
|
|
189
206
|
console.log(error);
|
|
190
207
|
throw new Error("Failed to get device by zone");
|
|
@@ -193,14 +210,55 @@ export class DeviceService {
|
|
|
193
210
|
|
|
194
211
|
async getDevicesByAccessGroup(accessGroupId: string) {
|
|
195
212
|
try {
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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;
|
|
201
232
|
} catch (error) {
|
|
202
233
|
console.log(error);
|
|
203
234
|
throw new Error("Failed to get devices by access group");
|
|
204
235
|
}
|
|
205
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
|
+
}
|
|
206
264
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,11 @@ export {
|
|
|
6
6
|
ConnectionService as CloudConnectionService,
|
|
7
7
|
} from "./device/cloud/services";
|
|
8
8
|
export { CloudDevice, DeviceFactory } from "./device/cloud/entities";
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
LocalDeviceService,
|
|
11
|
+
LocalHubService,
|
|
12
|
+
ConnectionService,
|
|
13
|
+
} from "./device/local/services";
|
|
10
14
|
|
|
11
15
|
export * from "./device/cloud/interfaces";
|
|
12
16
|
export * from "./device/cloud/types";
|