mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +00:00
Compare commits
9 Commits
temp-fix-t
...
refactor/a
Author | SHA1 | Date | |
---|---|---|---|
7ea53feddc | |||
c7a4ff1194 | |||
8a4633b158 | |||
f80d097ff8 | |||
04bd156df1 | |||
731819aeaa | |||
68d2d3b53d | |||
3fcfe2d92f | |||
30724d7d37 |
@ -68,22 +68,21 @@ export class DeviceStatusFirebaseService {
|
||||
}
|
||||
}
|
||||
async addBatchDeviceStatusToOurDb(
|
||||
batch: { deviceTuyaUuid: string; status: any; log: any }[],
|
||||
deviceCache: Map<string, any>,
|
||||
batch: {
|
||||
deviceTuyaUuid: string;
|
||||
status: any;
|
||||
log: any;
|
||||
device: any;
|
||||
}[],
|
||||
): Promise<void> {
|
||||
const allLogs = [];
|
||||
|
||||
console.log(
|
||||
`🧠 Preparing logs from batch of ${batch.length} items using cached devices only...`,
|
||||
);
|
||||
console.log(`🔁 Preparing logs from batch of ${batch.length} items...`);
|
||||
|
||||
for (const item of batch) {
|
||||
const device = deviceCache.get(item.deviceTuyaUuid);
|
||||
|
||||
const device = item.device;
|
||||
if (!device?.uuid) {
|
||||
console.log(
|
||||
`⛔ Ignored unknown device in batch: ${item.deviceTuyaUuid}`,
|
||||
);
|
||||
console.log(`⛔ Skipped unknown device: ${item.deviceTuyaUuid}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -103,53 +102,59 @@ export class DeviceStatusFirebaseService {
|
||||
}
|
||||
|
||||
console.log(`📝 Total logs to insert: ${allLogs.length}`);
|
||||
const chunkSize = 300;
|
||||
let insertedCount = 0;
|
||||
|
||||
for (let i = 0; i < allLogs.length; i += chunkSize) {
|
||||
const chunk = allLogs.slice(i, i + chunkSize);
|
||||
try {
|
||||
const result = await this.deviceStatusLogRepository
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into('device-status-log') // or use DeviceStatusLogEntity
|
||||
.values(chunk)
|
||||
.orIgnore() // skip duplicates
|
||||
.execute();
|
||||
const insertLogsPromise = (async () => {
|
||||
const chunkSize = 300;
|
||||
let insertedCount = 0;
|
||||
|
||||
insertedCount += result.identifiers.length;
|
||||
console.log(
|
||||
`✅ Inserted ${result.identifiers.length} / ${chunk.length} logs (chunk)`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('❌ Insert error (skipped chunk):', error.message);
|
||||
for (let i = 0; i < allLogs.length; i += chunkSize) {
|
||||
const chunk = allLogs.slice(i, i + chunkSize);
|
||||
try {
|
||||
const result = await this.deviceStatusLogRepository
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into('device-status-log') // or use DeviceStatusLogEntity
|
||||
.values(chunk)
|
||||
.orIgnore() // skip duplicates
|
||||
.execute();
|
||||
|
||||
insertedCount += result.identifiers.length;
|
||||
console.log(
|
||||
`✅ Inserted ${result.identifiers.length} / ${chunk.length} logs (chunk)`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('❌ Insert error (skipped chunk):', error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Total logs inserted: ${insertedCount} / ${allLogs.length}`);
|
||||
console.log(
|
||||
`✅ Total logs inserted: ${insertedCount} / ${allLogs.length}`,
|
||||
);
|
||||
})();
|
||||
|
||||
await insertLogsPromise;
|
||||
}
|
||||
|
||||
async addDeviceStatusToFirebase(
|
||||
addDeviceStatusDto: AddDeviceStatusDto,
|
||||
deviceCache: Map<string, any>,
|
||||
addDeviceStatusDto: AddDeviceStatusDto & { device?: any },
|
||||
): Promise<AddDeviceStatusDto | null> {
|
||||
try {
|
||||
const device = deviceCache.get(addDeviceStatusDto.deviceTuyaUuid);
|
||||
if (!device?.uuid) {
|
||||
console.log(
|
||||
`⛔ Skipping Firebase update for unknown device: ${addDeviceStatusDto.deviceTuyaUuid}`,
|
||||
let device = addDeviceStatusDto.device;
|
||||
if (!device) {
|
||||
device = await this.getDeviceByDeviceTuyaUuid(
|
||||
addDeviceStatusDto.deviceTuyaUuid,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure product info and uuid are attached
|
||||
addDeviceStatusDto.deviceUuid = device.uuid;
|
||||
addDeviceStatusDto.productUuid = device.productDevice?.uuid;
|
||||
addDeviceStatusDto.productType = device.productDevice?.prodType;
|
||||
|
||||
return await this.createDeviceStatusFirebase(addDeviceStatusDto);
|
||||
if (device?.uuid) {
|
||||
return await this.createDeviceStatusFirebase({
|
||||
deviceUuid: device.uuid,
|
||||
...addDeviceStatusDto,
|
||||
productType: device.productDevice?.prodType,
|
||||
});
|
||||
}
|
||||
// Return null if device not found or no UUID
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('❌ Error in addDeviceStatusToFirebase:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -163,6 +168,15 @@ export class DeviceStatusFirebaseService {
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
}
|
||||
async getAllDevices() {
|
||||
return await this.deviceRepository.find({
|
||||
where: {
|
||||
isActive: true,
|
||||
},
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
}
|
||||
|
||||
async getDevicesInstructionStatus(deviceUuid: string) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
@ -16,53 +16,46 @@ export class SosHandlerService {
|
||||
);
|
||||
}
|
||||
|
||||
async handleSosEventFirebase(
|
||||
devId: string,
|
||||
logData: any,
|
||||
deviceCache: Map<string, any>,
|
||||
): Promise<void> {
|
||||
async handleSosEventFirebase(device: any, logData: any): Promise<void> {
|
||||
const sosTrueStatus = [{ code: 'sos', value: true }];
|
||||
const sosFalseStatus = [{ code: 'sos', value: false }];
|
||||
|
||||
try {
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase(
|
||||
// ✅ Send true status
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
|
||||
deviceTuyaUuid: device.deviceTuyaUuid,
|
||||
status: sosTrueStatus,
|
||||
log: logData,
|
||||
device,
|
||||
});
|
||||
|
||||
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb([
|
||||
{
|
||||
deviceTuyaUuid: devId,
|
||||
status: [{ code: 'sos', value: true }],
|
||||
deviceTuyaUuid: device.deviceTuyaUuid,
|
||||
status: sosTrueStatus,
|
||||
log: logData,
|
||||
device,
|
||||
},
|
||||
deviceCache,
|
||||
);
|
||||
|
||||
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb(
|
||||
[
|
||||
{
|
||||
deviceTuyaUuid: devId,
|
||||
status: [{ code: 'sos', value: true }],
|
||||
log: logData,
|
||||
},
|
||||
],
|
||||
deviceCache,
|
||||
);
|
||||
]);
|
||||
|
||||
// ✅ Schedule false status
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase(
|
||||
{
|
||||
deviceTuyaUuid: devId,
|
||||
status: [{ code: 'sos', value: false }],
|
||||
log: logData,
|
||||
},
|
||||
deviceCache,
|
||||
);
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
|
||||
deviceTuyaUuid: device.deviceTuyaUuid,
|
||||
status: sosFalseStatus,
|
||||
log: logData,
|
||||
device,
|
||||
});
|
||||
|
||||
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb(
|
||||
[
|
||||
{
|
||||
deviceTuyaUuid: devId,
|
||||
status: [{ code: 'sos', value: false }],
|
||||
log: logData,
|
||||
},
|
||||
],
|
||||
deviceCache,
|
||||
);
|
||||
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb([
|
||||
{
|
||||
deviceTuyaUuid: device.deviceTuyaUuid,
|
||||
status: sosFalseStatus,
|
||||
log: logData,
|
||||
device,
|
||||
},
|
||||
]);
|
||||
} catch (err) {
|
||||
this.logger.error('Failed to send SOS false value', err);
|
||||
}
|
||||
|
@ -1,29 +1,29 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import TuyaWebsocket from '../../config/tuya-web-socket-config';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||
import { SosHandlerService } from './sos.handler.service';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import * as NodeCache from 'node-cache';
|
||||
|
||||
@Injectable()
|
||||
export class TuyaWebSocketService {
|
||||
export class TuyaWebSocketService implements OnModuleInit {
|
||||
private client: any;
|
||||
private readonly isDevEnv: boolean;
|
||||
private readonly deviceCache = new NodeCache({ stdTTL: 7200 }); // TTL = 2 hour
|
||||
|
||||
private messageQueue: {
|
||||
devId: string;
|
||||
status: any;
|
||||
logData: any;
|
||||
device: any;
|
||||
}[] = [];
|
||||
|
||||
private isProcessing = false;
|
||||
private deviceCache: Map<string, any> = new Map();
|
||||
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly deviceStatusFirebaseService: DeviceStatusFirebaseService,
|
||||
private readonly sosHandlerService: SosHandlerService,
|
||||
private readonly deviceRepository: DeviceRepository,
|
||||
) {
|
||||
this.isDevEnv =
|
||||
this.configService.get<string>('NODE_ENV') === 'development';
|
||||
@ -36,38 +36,37 @@ export class TuyaWebSocketService {
|
||||
maxRetryTimes: 100,
|
||||
});
|
||||
|
||||
this.loadAllActiveDevices();
|
||||
|
||||
// Reload device cache every 1 hour
|
||||
setInterval(() => this.loadAllActiveDevices(), 60 * 60 * 1000);
|
||||
|
||||
if (this.configService.get<string>('tuya-config.TRUN_ON_TUYA_SOCKET')) {
|
||||
this.setupEventHandlers();
|
||||
this.client.start();
|
||||
}
|
||||
|
||||
// Trigger the queue processor every 15 seconds
|
||||
// Run the queue processor every 15 seconds
|
||||
setInterval(() => this.processQueue(), 15000);
|
||||
|
||||
// Refresh the cache every 1 hour
|
||||
setInterval(() => this.initializeDeviceCache(), 30 * 60 * 1000); // 30 minutes
|
||||
}
|
||||
|
||||
private async loadAllActiveDevices(): Promise<void> {
|
||||
const devices = await this.deviceRepository.find({
|
||||
where: { isActive: true },
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
async onModuleInit() {
|
||||
await this.initializeDeviceCache();
|
||||
}
|
||||
|
||||
this.deviceCache.clear();
|
||||
devices.forEach((device) => {
|
||||
this.deviceCache.set(device.deviceTuyaUuid, device);
|
||||
});
|
||||
|
||||
console.log(
|
||||
`🔄 Device cache reloaded: ${this.deviceCache.size} active devices at ${new Date().toISOString()}`,
|
||||
);
|
||||
private async initializeDeviceCache() {
|
||||
try {
|
||||
const allDevices = await this.deviceStatusFirebaseService.getAllDevices();
|
||||
allDevices.forEach((device) => {
|
||||
if (device.deviceTuyaUuid) {
|
||||
this.deviceCache.set(device.deviceTuyaUuid, device);
|
||||
}
|
||||
});
|
||||
console.log(`✅ Refreshed cache with ${allDevices.length} devices.`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize device cache:', error);
|
||||
}
|
||||
}
|
||||
|
||||
private setupEventHandlers() {
|
||||
// Event handlers
|
||||
this.client.open(() => {
|
||||
console.log('open');
|
||||
});
|
||||
@ -75,42 +74,38 @@ export class TuyaWebSocketService {
|
||||
this.client.message(async (ws: WebSocket, message: any) => {
|
||||
try {
|
||||
const { devId, status, logData } = this.extractMessageData(message);
|
||||
if (!Array.isArray(logData?.properties)) return;
|
||||
if (!Array.isArray(logData?.properties)) {
|
||||
this.client.ackMessage(message.messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
const device = this.deviceCache.get(devId);
|
||||
if (!device) {
|
||||
// console.log(`⛔ Ignored unknown device: ${devId}`);
|
||||
// console.log(⛔ Unknown device: ${devId}, message ignored.);
|
||||
this.client.ackMessage(message.messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sosHandlerService.isSosTriggered(status)) {
|
||||
await this.sosHandlerService.handleSosEventFirebase(
|
||||
devId,
|
||||
logData,
|
||||
this.deviceCache,
|
||||
);
|
||||
await this.sosHandlerService.handleSosEventFirebase(devId, logData);
|
||||
} else {
|
||||
// Firebase real-time update
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase(
|
||||
{
|
||||
deviceTuyaUuid: devId,
|
||||
status,
|
||||
log: logData,
|
||||
},
|
||||
this.deviceCache,
|
||||
);
|
||||
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
|
||||
deviceTuyaUuid: devId,
|
||||
status,
|
||||
log: logData,
|
||||
device,
|
||||
});
|
||||
}
|
||||
|
||||
// Push to internal queue
|
||||
this.messageQueue.push({ devId, status, logData });
|
||||
this.messageQueue.push({ devId, status, logData, device });
|
||||
|
||||
// Acknowledge the message
|
||||
this.client.ackMessage(message.messageId);
|
||||
} catch (error) {
|
||||
console.error('Error receiving message:', error);
|
||||
console.error('❌ Error receiving message:', error);
|
||||
}
|
||||
});
|
||||
|
||||
this.client.reconnect(() => {
|
||||
console.log('reconnect');
|
||||
});
|
||||
@ -151,8 +146,8 @@ export class TuyaWebSocketService {
|
||||
deviceTuyaUuid: item.devId,
|
||||
status: item.status,
|
||||
log: item.logData,
|
||||
device: item.device,
|
||||
})),
|
||||
this.deviceCache,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('❌ Error processing batch:', error);
|
||||
|
22
package-lock.json
generated
22
package-lock.json
generated
@ -39,6 +39,7 @@
|
||||
"ioredis": "^5.3.2",
|
||||
"morgan": "^1.10.0",
|
||||
"nest-winston": "^1.10.2",
|
||||
"node-cache": "^5.1.2",
|
||||
"nodemailer": "^6.9.10",
|
||||
"onesignal-node": "^3.4.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
@ -10184,6 +10185,27 @@
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cache": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz",
|
||||
"integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clone": "2.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cache/node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/node-emoji": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"ioredis": "^5.3.2",
|
||||
"morgan": "^1.10.0",
|
||||
"nest-winston": "^1.10.2",
|
||||
"node-cache": "^5.1.2",
|
||||
"nodemailer": "^6.9.10",
|
||||
"onesignal-node": "^3.4.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
|
@ -50,7 +50,7 @@ export class ScheduleService {
|
||||
|
||||
// Corrected condition for supported device types
|
||||
this.ensureProductTypeSupportedForSchedule(
|
||||
ProductType[deviceDetails.productDevice.prodType],
|
||||
deviceDetails.productDevice.prodType as ProductType,
|
||||
);
|
||||
|
||||
return this.enableScheduleDeviceInTuya(
|
||||
@ -74,7 +74,7 @@ export class ScheduleService {
|
||||
|
||||
// Corrected condition for supported device types
|
||||
this.ensureProductTypeSupportedForSchedule(
|
||||
ProductType[deviceDetails.productDevice.prodType],
|
||||
deviceDetails.productDevice.prodType as ProductType,
|
||||
);
|
||||
|
||||
return await this.deleteScheduleDeviceInTuya(
|
||||
@ -97,7 +97,7 @@ export class ScheduleService {
|
||||
}
|
||||
|
||||
this.ensureProductTypeSupportedForSchedule(
|
||||
ProductType[deviceDetails.productDevice.prodType],
|
||||
deviceDetails.productDevice.prodType as ProductType,
|
||||
);
|
||||
|
||||
await this.addScheduleDeviceInTuya(
|
||||
@ -120,9 +120,8 @@ export class ScheduleService {
|
||||
}
|
||||
// Corrected condition for supported device types
|
||||
this.ensureProductTypeSupportedForSchedule(
|
||||
ProductType[deviceDetails.productDevice.prodType],
|
||||
deviceDetails.productDevice.prodType as ProductType,
|
||||
);
|
||||
|
||||
const schedules = await this.getScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
category,
|
||||
@ -162,7 +161,7 @@ export class ScheduleService {
|
||||
|
||||
// Corrected condition for supported device types
|
||||
this.ensureProductTypeSupportedForSchedule(
|
||||
ProductType[deviceDetails.productDevice.prodType],
|
||||
deviceDetails.productDevice.prodType as ProductType,
|
||||
);
|
||||
|
||||
await this.updateScheduleDeviceInTuya(
|
||||
|
@ -1,39 +1,39 @@
|
||||
import { VisitorPasswordRepository } from './../../../libs/common/src/modules/visitor-password/repositories/visitor-password.repository';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import {
|
||||
Injectable,
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import {
|
||||
addDeviceObjectInterface,
|
||||
createTickInterface,
|
||||
} from '../interfaces/visitor-password.interface';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
import { VisitorPasswordRepository } from './../../../libs/common/src/modules/visitor-password/repositories/visitor-password.repository';
|
||||
|
||||
import { AddDoorLockTemporaryPasswordDto } from '../dtos';
|
||||
import { EmailService } from '@app/common/util/email.service';
|
||||
import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services';
|
||||
import { DoorLockService } from 'src/door-lock/services';
|
||||
import { DeviceService } from 'src/device/services';
|
||||
import { DeviceStatuses } from '@app/common/constants/device-status.enum';
|
||||
import {
|
||||
DaysEnum,
|
||||
EnableDisableStatusEnum,
|
||||
} from '@app/common/constants/days.enum';
|
||||
import { PasswordType } from '@app/common/constants/password-type.enum';
|
||||
import { DeviceStatuses } from '@app/common/constants/device-status.enum';
|
||||
import {
|
||||
CommonHourMinutes,
|
||||
CommonHours,
|
||||
} from '@app/common/constants/hours-minutes.enum';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant';
|
||||
import { PasswordType } from '@app/common/constants/password-type.enum';
|
||||
import { VisitorPasswordEnum } from '@app/common/constants/visitor-password.enum';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { EmailService } from '@app/common/util/email.service';
|
||||
import { DeviceService } from 'src/device/services';
|
||||
import { DoorLockService } from 'src/door-lock/services';
|
||||
import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services';
|
||||
import { Not } from 'typeorm';
|
||||
import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant';
|
||||
import { AddDoorLockTemporaryPasswordDto } from '../dtos';
|
||||
|
||||
@Injectable()
|
||||
export class VisitorPasswordService {
|
||||
@ -57,6 +57,67 @@ export class VisitorPasswordService {
|
||||
secretKey,
|
||||
});
|
||||
}
|
||||
|
||||
async getPasswords(projectUuid: string) {
|
||||
await this.validateProject(projectUuid);
|
||||
|
||||
const deviceIds = await this.deviceRepository.find({
|
||||
where: {
|
||||
productDevice: {
|
||||
prodType: ProductType.DL,
|
||||
},
|
||||
spaceDevice: {
|
||||
spaceName: Not(ORPHAN_SPACE_NAME),
|
||||
community: {
|
||||
project: {
|
||||
uuid: projectUuid,
|
||||
},
|
||||
},
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const data = [];
|
||||
deviceIds.forEach((deviceId) => {
|
||||
data.push(
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsOneTime(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsOneTime(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsMultiple(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsMultiple(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineOneTimeTemporaryPasswords(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineOneTimeTemporaryPasswords(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineMultipleTimeTemporaryPasswords(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineMultipleTimeTemporaryPasswords(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
);
|
||||
});
|
||||
const result = (await Promise.all(data)).flat().filter((datum) => {
|
||||
return datum != null;
|
||||
});
|
||||
|
||||
return new SuccessResponseDto({
|
||||
message: 'Successfully retrieved temporary passwords',
|
||||
data: result,
|
||||
statusCode: HttpStatus.OK,
|
||||
});
|
||||
}
|
||||
|
||||
async handleTemporaryPassword(
|
||||
addDoorLockTemporaryPasswordDto: AddDoorLockTemporaryPasswordDto,
|
||||
userUuid: string,
|
||||
@ -105,7 +166,7 @@ export class VisitorPasswordService {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
});
|
||||
}
|
||||
async addOfflineMultipleTimeTemporaryPassword(
|
||||
private async addOfflineMultipleTimeTemporaryPassword(
|
||||
addDoorLockOfflineMultipleDto: AddDoorLockTemporaryPasswordDto,
|
||||
userUuid: string,
|
||||
projectUuid: string,
|
||||
@ -169,6 +230,7 @@ export class VisitorPasswordService {
|
||||
success: true,
|
||||
result: createMultipleOfflinePass.result,
|
||||
deviceUuid,
|
||||
deviceName: deviceDetails.name,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
@ -231,7 +293,7 @@ export class VisitorPasswordService {
|
||||
}
|
||||
}
|
||||
|
||||
async addOfflineOneTimeTemporaryPassword(
|
||||
private async addOfflineOneTimeTemporaryPassword(
|
||||
addDoorLockOfflineOneTimeDto: AddDoorLockTemporaryPasswordDto,
|
||||
userUuid: string,
|
||||
projectUuid: string,
|
||||
@ -295,6 +357,7 @@ export class VisitorPasswordService {
|
||||
success: true,
|
||||
result: createOnceOfflinePass.result,
|
||||
deviceUuid,
|
||||
deviceName: deviceDetails.name,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
@ -357,7 +420,7 @@ export class VisitorPasswordService {
|
||||
}
|
||||
}
|
||||
|
||||
async addOfflineTemporaryPasswordTuya(
|
||||
private async addOfflineTemporaryPasswordTuya(
|
||||
doorLockUuid: string,
|
||||
type: string,
|
||||
addDoorLockOfflineMultipleDto: AddDoorLockTemporaryPasswordDto,
|
||||
@ -387,7 +450,7 @@ export class VisitorPasswordService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async addOnlineTemporaryPasswordMultipleTime(
|
||||
private async addOnlineTemporaryPasswordMultipleTime(
|
||||
addDoorLockOnlineMultipleDto: AddDoorLockTemporaryPasswordDto,
|
||||
userUuid: string,
|
||||
projectUuid: string,
|
||||
@ -448,6 +511,7 @@ export class VisitorPasswordService {
|
||||
success: true,
|
||||
id: createPass.result.id,
|
||||
deviceUuid,
|
||||
deviceName: passwordData.deviceName,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
@ -508,67 +572,8 @@ export class VisitorPasswordService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async getPasswords(projectUuid: string) {
|
||||
await this.validateProject(projectUuid);
|
||||
|
||||
const deviceIds = await this.deviceRepository.find({
|
||||
where: {
|
||||
productDevice: {
|
||||
prodType: ProductType.DL,
|
||||
},
|
||||
spaceDevice: {
|
||||
spaceName: Not(ORPHAN_SPACE_NAME),
|
||||
community: {
|
||||
project: {
|
||||
uuid: projectUuid,
|
||||
},
|
||||
},
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const data = [];
|
||||
deviceIds.forEach((deviceId) => {
|
||||
data.push(
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsOneTime(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsOneTime(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsMultiple(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOnlineTemporaryPasswordsMultiple(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineOneTimeTemporaryPasswords(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineOneTimeTemporaryPasswords(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineMultipleTimeTemporaryPasswords(deviceId.uuid, true, false)
|
||||
.catch(() => {}),
|
||||
this.doorLockService
|
||||
.getOfflineMultipleTimeTemporaryPasswords(deviceId.uuid, true, true)
|
||||
.catch(() => {}),
|
||||
);
|
||||
});
|
||||
const result = (await Promise.all(data)).flat().filter((datum) => {
|
||||
return datum != null;
|
||||
});
|
||||
|
||||
return new SuccessResponseDto({
|
||||
message: 'Successfully retrieved temporary passwords',
|
||||
data: result,
|
||||
statusCode: HttpStatus.OK,
|
||||
});
|
||||
}
|
||||
|
||||
async addOnlineTemporaryPasswordOneTime(
|
||||
private async addOnlineTemporaryPasswordOneTime(
|
||||
addDoorLockOnlineOneTimeDto: AddDoorLockTemporaryPasswordDto,
|
||||
userUuid: string,
|
||||
projectUuid: string,
|
||||
@ -627,6 +632,7 @@ export class VisitorPasswordService {
|
||||
return {
|
||||
success: true,
|
||||
id: createPass.result.id,
|
||||
deviceName: passwordData.deviceName,
|
||||
deviceUuid,
|
||||
};
|
||||
} catch (error) {
|
||||
@ -688,7 +694,7 @@ export class VisitorPasswordService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async getTicketAndEncryptedPassword(
|
||||
private async getTicketAndEncryptedPassword(
|
||||
doorLockUuid: string,
|
||||
passwordPlan: string,
|
||||
projectUuid: string,
|
||||
@ -725,6 +731,7 @@ export class VisitorPasswordService {
|
||||
ticketKey: ticketDetails.result.ticket_key,
|
||||
encryptedPassword: decrypted,
|
||||
deviceTuyaUuid: deviceDetails.deviceTuyaUuid,
|
||||
deviceName: deviceDetails.name,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
@ -734,7 +741,7 @@ export class VisitorPasswordService {
|
||||
}
|
||||
}
|
||||
|
||||
async createDoorLockTicketTuya(
|
||||
private async createDoorLockTicketTuya(
|
||||
deviceUuid: string,
|
||||
): Promise<createTickInterface> {
|
||||
try {
|
||||
@ -753,7 +760,7 @@ export class VisitorPasswordService {
|
||||
}
|
||||
}
|
||||
|
||||
async addOnlineTemporaryPasswordMultipleTuya(
|
||||
private async addOnlineTemporaryPasswordMultipleTuya(
|
||||
addDeviceObj: addDeviceObjectInterface,
|
||||
doorLockUuid: string,
|
||||
): Promise<createTickInterface> {
|
||||
@ -795,7 +802,7 @@ export class VisitorPasswordService {
|
||||
}
|
||||
}
|
||||
|
||||
getWorkingDayValue(days) {
|
||||
private getWorkingDayValue(days) {
|
||||
// Array representing the days of the week
|
||||
const weekDays = [
|
||||
DaysEnum.SAT,
|
||||
@ -827,36 +834,7 @@ export class VisitorPasswordService {
|
||||
|
||||
return workingDayValue;
|
||||
}
|
||||
getDaysFromWorkingDayValue(workingDayValue) {
|
||||
// Array representing the days of the week
|
||||
const weekDays = [
|
||||
DaysEnum.SAT,
|
||||
DaysEnum.FRI,
|
||||
DaysEnum.THU,
|
||||
DaysEnum.WED,
|
||||
DaysEnum.TUE,
|
||||
DaysEnum.MON,
|
||||
DaysEnum.SUN,
|
||||
];
|
||||
|
||||
// Convert the integer to a binary string and pad with leading zeros to ensure 7 bits
|
||||
const binaryString = workingDayValue
|
||||
.toString(2)
|
||||
.padStart(7, EnableDisableStatusEnum.DISABLED);
|
||||
|
||||
// Initialize an array to hold the days of the week
|
||||
const days = [];
|
||||
|
||||
// Iterate through the binary string and weekDays array
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
if (binaryString[i] === EnableDisableStatusEnum.ENABLED) {
|
||||
days.push(weekDays[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
timeToMinutes(timeStr) {
|
||||
private timeToMinutes(timeStr) {
|
||||
try {
|
||||
// Special case for "24:00"
|
||||
if (timeStr === CommonHours.TWENTY_FOUR) {
|
||||
@ -883,38 +861,7 @@ export class VisitorPasswordService {
|
||||
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
minutesToTime(totalMinutes) {
|
||||
try {
|
||||
if (
|
||||
typeof totalMinutes !== 'number' ||
|
||||
totalMinutes < 0 ||
|
||||
totalMinutes > CommonHourMinutes.TWENTY_FOUR
|
||||
) {
|
||||
throw new Error('Invalid minutes value');
|
||||
}
|
||||
|
||||
if (totalMinutes === CommonHourMinutes.TWENTY_FOUR) {
|
||||
return CommonHours.TWENTY_FOUR;
|
||||
}
|
||||
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
|
||||
const formattedHours = String(hours).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
const formattedMinutes = String(minutes).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
|
||||
return `${formattedHours}:${formattedMinutes}`;
|
||||
} catch (error) {
|
||||
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
async getDeviceByDeviceUuid(
|
||||
private async getDeviceByDeviceUuid(
|
||||
deviceUuid: string,
|
||||
withProductDevice: boolean = true,
|
||||
projectUuid: string,
|
||||
@ -939,7 +886,7 @@ export class VisitorPasswordService {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
async addOnlineTemporaryPasswordOneTimeTuya(
|
||||
private async addOnlineTemporaryPasswordOneTimeTuya(
|
||||
addDeviceObj: addDeviceObjectInterface,
|
||||
doorLockUuid: string,
|
||||
): Promise<createTickInterface> {
|
||||
|
Reference in New Issue
Block a user