Compare commits

..

15 Commits

Author SHA1 Message Date
7ea53feddc add deviceName to handle password API 2025-06-30 08:54:25 +03:00
c7a4ff1194 fix: schedule device types (#441) 2025-06-29 15:27:55 +03:00
8a4633b158 Merge pull request #439 from SyncrowIOT/add-check-log-to-trace-the-map-issue
feat: enhance device status handling with caching and batch processin…
2025-06-25 18:59:37 -06:00
f80d097ff8 refactor: optimize log insertion and clean up device cache handling in TuyaWebSocketService 2025-06-25 18:57:56 -06:00
04bd156df1 Merge branch 'dev' into add-check-log-to-trace-the-map-issue 2025-06-25 18:42:43 -06:00
731819aeaa feat: enhance device status handling with caching and batch processing improvements 2025-06-25 18:37:46 -06:00
68d2d3b53d fix: improve device retrieval logic in addDeviceStatusToFirebase method 2025-06-25 08:13:02 -06:00
3fcfe2d92f Merge pull request #438 from SyncrowIOT/temp-fix-to-check
fix: enhance device status handling by integrating device cache for improved performance
2025-06-25 08:06:29 -06:00
c0a069b460 fix: enhance device status handling by integrating device cache for improved performance 2025-06-25 08:03:23 -06:00
30724d7d37 Merge pull request #436 from SyncrowIOT/add-check-log-to-trace-the-map-issue
fix: add validation for missing properties in device status logs
2025-06-25 05:32:50 -06:00
324661e1ee fix: add missing check for device UUID in batch processing logs 2025-06-25 05:30:15 -06:00
a83424f45b fix: remove unnecessary validation for missing properties in device status logs 2025-06-25 05:29:28 -06:00
71f6ccb4db fix: add validation for missing properties in device status logs 2025-06-25 05:20:26 -06:00
68692b7c8b increase rate limit to 100 per minute for each IP (#435) 2025-06-25 13:50:38 +03:00
4d60c1ed54 Merge pull request #434 from SyncrowIOT/fix-time-out-connections-db
Fix-time-out-connections-db
2025-06-25 04:47:59 -06:00
9 changed files with 223 additions and 205 deletions

View File

@ -68,33 +68,23 @@ export class DeviceStatusFirebaseService {
}
}
async addBatchDeviceStatusToOurDb(
batch: { deviceTuyaUuid: string; status: any; log: any }[],
batch: {
deviceTuyaUuid: string;
status: any;
log: any;
device: any;
}[],
): Promise<void> {
const allLogs = [];
const deviceMap = new Map<string, any>();
console.log(
`🧠 Starting device lookups for batch of ${batch.length} items...`,
);
console.log(`🔁 Preparing logs from batch of ${batch.length} items...`);
// Step 1: Parallel device fetching
await Promise.all(
batch.map(async (item) => {
if (!deviceMap.has(item.deviceTuyaUuid)) {
const device = await this.getDeviceByDeviceTuyaUuid(
item.deviceTuyaUuid,
);
device?.uuid && deviceMap.set(item.deviceTuyaUuid, device);
}
}),
);
console.log(`🔍 Found ${deviceMap.size} devices from batch`);
// Step 2: Prepare logs and updates
for (const item of batch) {
const device = deviceMap.get(item.deviceTuyaUuid);
if (!device?.uuid) continue;
const device = item.device;
if (!device?.uuid) {
console.log(`⛔ Skipped unknown device: ${item.deviceTuyaUuid}`);
continue;
}
const logs = item.log.properties.map((property) =>
this.deviceStatusLogRepository.create({
@ -112,7 +102,7 @@ export class DeviceStatusFirebaseService {
}
console.log(`📝 Total logs to insert: ${allLogs.length}`);
// Step 3: Insert logs in chunks with ON CONFLICT DO NOTHING
const insertLogsPromise = (async () => {
const chunkSize = 300;
let insertedCount = 0;
@ -142,29 +132,29 @@ export class DeviceStatusFirebaseService {
);
})();
// Step 5: Wait for both insert and post-processing to finish
await Promise.all([insertLogsPromise]);
await insertLogsPromise;
}
async addDeviceStatusToFirebase(
addDeviceStatusDto: AddDeviceStatusDto,
addDeviceStatusDto: AddDeviceStatusDto & { device?: any },
): Promise<AddDeviceStatusDto | null> {
try {
const device = await this.getDeviceByDeviceTuyaUuid(
addDeviceStatusDto.deviceTuyaUuid,
);
let device = addDeviceStatusDto.device;
if (!device) {
device = await this.getDeviceByDeviceTuyaUuid(
addDeviceStatusDto.deviceTuyaUuid,
);
}
if (device?.uuid) {
return await this.createDeviceStatusFirebase({
deviceUuid: device.uuid,
...addDeviceStatusDto,
productType: device.productDevice.prodType,
productType: device.productDevice?.prodType,
});
}
// Return null if device not found or no UUID
return null;
} catch (error) {
// Handle the error silently, perhaps log it internally or ignore it
return null;
}
}
@ -178,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);

View File

@ -8,7 +8,10 @@ import { TuyaWebSocketService } from './services/tuya.web.socket.service';
import { OneSignalService } from './services/onesignal.service';
import { DeviceMessagesService } from './services/device.messages.service';
import { DeviceRepositoryModule } from '../modules/device/device.repository.module';
import { DeviceNotificationRepository } from '../modules/device/repositories';
import {
DeviceNotificationRepository,
DeviceRepository,
} from '../modules/device/repositories';
import { DeviceStatusFirebaseModule } from '../firebase/devices-status/devices-status.module';
import { CommunityPermissionService } from './services/community.permission.service';
import { CommunityRepository } from '../modules/community/repositories';
@ -27,6 +30,7 @@ import { SosHandlerService } from './services/sos.handler.service';
DeviceNotificationRepository,
CommunityRepository,
SosHandlerService,
DeviceRepository,
],
exports: [
HelperHashService,

View File

@ -16,33 +16,44 @@ export class SosHandlerService {
);
}
async handleSosEventFirebase(devId: string, logData: any): Promise<void> {
async handleSosEventFirebase(device: any, logData: any): Promise<void> {
const sosTrueStatus = [{ code: 'sos', value: true }];
const sosFalseStatus = [{ code: 'sos', value: false }];
try {
// ✅ Send true status
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: devId,
status: [{ code: 'sos', value: true }],
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,
},
]);
// ✅ Schedule false status
setTimeout(async () => {
try {
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: devId,
status: [{ code: 'sos', value: false }],
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosFalseStatus,
log: logData,
device,
});
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb([
{
deviceTuyaUuid: devId,
status: [{ code: 'sos', value: false }],
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosFalseStatus,
log: logData,
device,
},
]);
} catch (err) {

View File

@ -1,18 +1,21 @@
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 * 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;
@ -38,12 +41,32 @@ export class TuyaWebSocketService {
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
}
async onModuleInit() {
await this.initializeDeviceCache();
}
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');
});
@ -51,27 +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)) {
this.client.ackMessage(message.messageId);
return;
}
const device = this.deviceCache.get(devId);
if (!device) {
// console.log(⛔ Unknown device: ${devId}, message ignored.);
this.client.ackMessage(message.messageId);
return;
}
if (this.sosHandlerService.isSosTriggered(status)) {
await this.sosHandlerService.handleSosEventFirebase(devId, logData);
} else {
// Firebase real-time update
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: devId,
status: status,
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');
});
@ -108,10 +142,11 @@ export class TuyaWebSocketService {
try {
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb(
batch?.map((item) => ({
batch.map((item) => ({
deviceTuyaUuid: item.devId,
status: item.status,
log: item.logData,
device: item.device,
})),
);
} catch (error) {

22
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -50,7 +50,7 @@ import { SchedulerModule } from './scheduler/scheduler.module';
load: config,
}),
ThrottlerModule.forRoot({
throttlers: [{ ttl: 60000, limit: 30 }],
throttlers: [{ ttl: 60000, limit: 100 }],
generateKey: (context) => {
const req = context.switchToHttp().getRequest();
console.log('Real IP:', req.headers['x-forwarded-for']);

View File

@ -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(

View File

@ -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> {