mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-15 18:27:05 +00:00
Merge pull request #350 from SyncrowIOT/SP-1355-powr-clap-historical-data
SP-1355-powr-clap-historical-data
This commit is contained in:
@ -494,9 +494,10 @@ export class ControllerRoute {
|
|||||||
public static readonly ROUTE = 'power-clamp';
|
public static readonly ROUTE = 'power-clamp';
|
||||||
|
|
||||||
static ACTIONS = class {
|
static ACTIONS = class {
|
||||||
public static readonly GET_ENERGY_SUMMARY = 'Get power clamp data';
|
public static readonly GET_ENERGY_SUMMARY =
|
||||||
|
'Get power clamp historical data';
|
||||||
public static readonly GET_ENERGY_DESCRIPTION =
|
public static readonly GET_ENERGY_DESCRIPTION =
|
||||||
'This endpoint retrieves power clamp data for a specific device.';
|
'This endpoint retrieves the historical data of a power clamp device based on the provided parameters.';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
static DEVICE = class {
|
static DEVICE = class {
|
||||||
|
6
libs/common/src/constants/power.clamp.enargy.enum.ts
Normal file
6
libs/common/src/constants/power.clamp.enargy.enum.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum PowerClampEnergyEnum {
|
||||||
|
ENERGY_CONSUMED = 'EnergyConsumed',
|
||||||
|
ENERGY_CONSUMED_A = 'EnergyConsumedA',
|
||||||
|
ENERGY_CONSUMED_B = 'EnergyConsumedB',
|
||||||
|
ENERGY_CONSUMED_C = 'EnergyConsumedC',
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export const SQL_QUERIES_PATH = 'libs/common/src/sql/queries';
|
export const SQL_QUERIES_PATH = 'libs/common/src/sql/queries';
|
||||||
|
export const SQL_PROCEDURES_PATH = 'libs/common/src/sql/procedures';
|
||||||
|
@ -46,6 +46,11 @@ import { ClientEntity } from '../modules/client/entities';
|
|||||||
import { TypeOrmWinstonLogger } from '@app/common/logger/services/typeorm.logger';
|
import { TypeOrmWinstonLogger } from '@app/common/logger/services/typeorm.logger';
|
||||||
import { createLogger } from 'winston';
|
import { createLogger } from 'winston';
|
||||||
import { winstonLoggerOptions } from '../logger/services/winston.logger';
|
import { winstonLoggerOptions } from '../logger/services/winston.logger';
|
||||||
|
import {
|
||||||
|
PowerClampDailyEntity,
|
||||||
|
PowerClampHourlyEntity,
|
||||||
|
PowerClampMonthlyEntity,
|
||||||
|
} from '../modules/power-clamp/entities/power-clamp.entity';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forRootAsync({
|
TypeOrmModule.forRootAsync({
|
||||||
@ -101,6 +106,9 @@ import { winstonLoggerOptions } from '../logger/services/winston.logger';
|
|||||||
SpaceProductAllocationEntity,
|
SpaceProductAllocationEntity,
|
||||||
SubspaceProductAllocationEntity,
|
SubspaceProductAllocationEntity,
|
||||||
ClientEntity,
|
ClientEntity,
|
||||||
|
PowerClampHourlyEntity,
|
||||||
|
PowerClampDailyEntity,
|
||||||
|
PowerClampMonthlyEntity,
|
||||||
],
|
],
|
||||||
namingStrategy: new SnakeNamingStrategy(),
|
namingStrategy: new SnakeNamingStrategy(),
|
||||||
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
|
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
|
||||||
|
@ -3,12 +3,24 @@ import { DeviceStatusFirebaseController } from './controllers/devices-status.con
|
|||||||
import { DeviceStatusFirebaseService } from './services/devices-status.service';
|
import { DeviceStatusFirebaseService } from './services/devices-status.service';
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories/device-status.repository';
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories/device-status.repository';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
DeviceStatusFirebaseService,
|
DeviceStatusFirebaseService,
|
||||||
DeviceRepository,
|
DeviceRepository,
|
||||||
DeviceStatusLogRepository,
|
DeviceStatusLogRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
controllers: [DeviceStatusFirebaseController],
|
controllers: [DeviceStatusFirebaseController],
|
||||||
exports: [DeviceStatusFirebaseService, DeviceStatusLogRepository],
|
exports: [DeviceStatusFirebaseService, DeviceStatusLogRepository],
|
||||||
|
@ -18,6 +18,9 @@ import {
|
|||||||
runTransaction,
|
runTransaction,
|
||||||
} from 'firebase/database';
|
} from 'firebase/database';
|
||||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||||
|
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { PowerClampEnergyEnum } from '@app/common/constants/power.clamp.enargy.enum';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeviceStatusFirebaseService {
|
export class DeviceStatusFirebaseService {
|
||||||
private tuya: TuyaContext;
|
private tuya: TuyaContext;
|
||||||
@ -25,6 +28,7 @@ export class DeviceStatusFirebaseService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly deviceRepository: DeviceRepository,
|
private readonly deviceRepository: DeviceRepository,
|
||||||
|
private readonly powerClampService: PowerClampService,
|
||||||
private deviceStatusLogRepository: DeviceStatusLogRepository,
|
private deviceStatusLogRepository: DeviceStatusLogRepository,
|
||||||
) {
|
) {
|
||||||
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||||
@ -79,6 +83,7 @@ export class DeviceStatusFirebaseService {
|
|||||||
return await this.createDeviceStatusFirebase({
|
return await this.createDeviceStatusFirebase({
|
||||||
deviceUuid: device.uuid,
|
deviceUuid: device.uuid,
|
||||||
...addDeviceStatusDto,
|
...addDeviceStatusDto,
|
||||||
|
productType: device.productDevice.prodType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Return null if device not found or no UUID
|
// Return null if device not found or no UUID
|
||||||
@ -216,6 +221,25 @@ export class DeviceStatusFirebaseService {
|
|||||||
});
|
});
|
||||||
await this.deviceStatusLogRepository.save(newLogs);
|
await this.deviceStatusLogRepository.save(newLogs);
|
||||||
|
|
||||||
|
if (addDeviceStatusDto.productType === ProductType.PC) {
|
||||||
|
const energyCodes = new Set([
|
||||||
|
PowerClampEnergyEnum.ENERGY_CONSUMED,
|
||||||
|
PowerClampEnergyEnum.ENERGY_CONSUMED_A,
|
||||||
|
PowerClampEnergyEnum.ENERGY_CONSUMED_B,
|
||||||
|
PowerClampEnergyEnum.ENERGY_CONSUMED_C,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const energyStatus = addDeviceStatusDto?.log?.properties?.find((status) =>
|
||||||
|
energyCodes.has(status.code),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (energyStatus) {
|
||||||
|
await this.powerClampService.updateEnergyConsumedHistoricalData(
|
||||||
|
addDeviceStatusDto.deviceUuid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return the updated data
|
// Return the updated data
|
||||||
const snapshot: DataSnapshot = await get(dataRef);
|
const snapshot: DataSnapshot = await get(dataRef);
|
||||||
return snapshot.val();
|
return snapshot.val();
|
||||||
|
61
libs/common/src/helper/services/power.clamp.service.ts
Normal file
61
libs/common/src/helper/services/power.clamp.service.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { SqlLoaderService } from './sql-loader.service';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PowerClampService {
|
||||||
|
constructor(
|
||||||
|
private readonly sqlLoader: SqlLoaderService,
|
||||||
|
private readonly dataSource: DataSource,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async updateEnergyConsumedHistoricalData(deviceUuid: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const now = new Date();
|
||||||
|
const dateStr = now.toLocaleDateString('en-CA'); // YYYY-MM-DD
|
||||||
|
const hour = now.getHours();
|
||||||
|
const monthYear = now
|
||||||
|
.toLocaleDateString('en-US', {
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric',
|
||||||
|
})
|
||||||
|
.replace('/', '-'); // MM-YYYY
|
||||||
|
|
||||||
|
await this.executeProcedure('fact_hourly_energy_consumed_procedure', [
|
||||||
|
deviceUuid,
|
||||||
|
dateStr,
|
||||||
|
hour,
|
||||||
|
]);
|
||||||
|
|
||||||
|
await this.executeProcedure('fact_daily_energy_consumed_procedure', [
|
||||||
|
deviceUuid,
|
||||||
|
dateStr,
|
||||||
|
]);
|
||||||
|
|
||||||
|
await this.executeProcedure('fact_monthly_energy_consumed_procedure', [
|
||||||
|
deviceUuid,
|
||||||
|
monthYear,
|
||||||
|
]);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to insert or update energy data:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async executeProcedure(
|
||||||
|
procedureFileName: string,
|
||||||
|
params: (string | number | null)[],
|
||||||
|
): Promise<void> {
|
||||||
|
const query = this.loadQuery(procedureFileName);
|
||||||
|
await this.dataSource.query(query, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadQuery(fileName: string): string {
|
||||||
|
return this.sqlLoader.loadQuery(
|
||||||
|
'fact_energy_consumed',
|
||||||
|
fileName,
|
||||||
|
SQL_PROCEDURES_PATH,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
import { SQL_QUERIES_PATH } from '@app/common/constants/sql-query-path';
|
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
@ -8,13 +7,8 @@ export class SqlLoaderService {
|
|||||||
private readonly logger = new Logger(SqlLoaderService.name);
|
private readonly logger = new Logger(SqlLoaderService.name);
|
||||||
private readonly sqlRootPath = join(__dirname, '../sql/queries');
|
private readonly sqlRootPath = join(__dirname, '../sql/queries');
|
||||||
|
|
||||||
loadQuery(module: string, queryName: string): string {
|
loadQuery(module: string, queryName: string, path: string): string {
|
||||||
const filePath = join(
|
const filePath = join(process.cwd(), path, module, `${queryName}.sql`);
|
||||||
process.cwd(),
|
|
||||||
SQL_QUERIES_PATH,
|
|
||||||
module,
|
|
||||||
`${queryName}.sql`,
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
return readFileSync(filePath, 'utf8');
|
return readFileSync(filePath, 'utf8');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -17,6 +17,7 @@ import { SceneDeviceEntity } from '../../scene-device/entities';
|
|||||||
import { SpaceEntity } from '../../space/entities/space.entity';
|
import { SpaceEntity } from '../../space/entities/space.entity';
|
||||||
import { SubspaceEntity } from '../../space/entities/subspace/subspace.entity';
|
import { SubspaceEntity } from '../../space/entities/subspace/subspace.entity';
|
||||||
import { NewTagEntity } from '../../tag';
|
import { NewTagEntity } from '../../tag';
|
||||||
|
import { PowerClampHourlyEntity } from '../../power-clamp/entities/power-clamp.entity';
|
||||||
|
|
||||||
@Entity({ name: 'device' })
|
@Entity({ name: 'device' })
|
||||||
@Unique(['deviceTuyaUuid'])
|
@Unique(['deviceTuyaUuid'])
|
||||||
@ -79,7 +80,8 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
|||||||
@OneToMany(() => NewTagEntity, (tag) => tag.devices)
|
@OneToMany(() => NewTagEntity, (tag) => tag.devices)
|
||||||
// @JoinTable({ name: 'device_tags' })
|
// @JoinTable({ name: 'device_tags' })
|
||||||
public tag: NewTagEntity;
|
public tag: NewTagEntity;
|
||||||
|
@OneToMany(() => PowerClampHourlyEntity, (powerClamp) => powerClamp.device)
|
||||||
|
powerClampHourly: PowerClampHourlyEntity[];
|
||||||
constructor(partial: Partial<DeviceEntity>) {
|
constructor(partial: Partial<DeviceEntity>) {
|
||||||
super();
|
super();
|
||||||
Object.assign(this, partial);
|
Object.assign(this, partial);
|
||||||
|
1
libs/common/src/modules/power-clamp/dtos/index.ts
Normal file
1
libs/common/src/modules/power-clamp/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './power-clamp.dto';
|
43
libs/common/src/modules/power-clamp/dtos/power-clamp.dto.ts
Normal file
43
libs/common/src/modules/power-clamp/dtos/power-clamp.dto.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class PowerClampDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public uuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public deviceUuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
public hour?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
public day?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
public month?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public energyConsumedKw: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public energyConsumedA: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public energyConsumedB: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public energyConsumedC: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public prodType: string;
|
||||||
|
}
|
1
libs/common/src/modules/power-clamp/entities/index.ts
Normal file
1
libs/common/src/modules/power-clamp/entities/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './power-clamp.entity';
|
@ -0,0 +1,95 @@
|
|||||||
|
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||||
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { PowerClampDto } from '../dtos';
|
||||||
|
import { DeviceEntity } from '../../device/entities/device.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'power-clamp-energy-consumed-hourly' })
|
||||||
|
@Unique(['deviceUuid', 'date', 'hour'])
|
||||||
|
export class PowerClampHourlyEntity extends AbstractEntity<PowerClampDto> {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public deviceUuid: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public hour: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false, type: 'date' })
|
||||||
|
public date: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
public energyConsumedKw: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedA: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedB: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedC: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
|
||||||
|
device: DeviceEntity;
|
||||||
|
|
||||||
|
constructor(partial: Partial<PowerClampHourlyEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Entity({ name: 'power-clamp-energy-consumed-daily' })
|
||||||
|
@Unique(['deviceUuid', 'date'])
|
||||||
|
export class PowerClampDailyEntity extends AbstractEntity<PowerClampDto> {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public deviceUuid: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false, type: 'date' })
|
||||||
|
public date: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
public energyConsumedKw: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedA: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedB: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedC: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
|
||||||
|
device: DeviceEntity;
|
||||||
|
|
||||||
|
constructor(partial: Partial<PowerClampHourlyEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Entity({ name: 'power-clamp-energy-consumed-monthly' })
|
||||||
|
@Unique(['deviceUuid', 'month'])
|
||||||
|
export class PowerClampMonthlyEntity extends AbstractEntity<PowerClampDto> {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public deviceUuid: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public month: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
public energyConsumedKw: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedA: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedB: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
public energyConsumedC: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
|
||||||
|
device: DeviceEntity;
|
||||||
|
|
||||||
|
constructor(partial: Partial<PowerClampHourlyEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { PowerClampHourlyEntity } from './entities/power-clamp.entity';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [],
|
||||||
|
exports: [],
|
||||||
|
controllers: [],
|
||||||
|
imports: [TypeOrmModule.forFeature([PowerClampHourlyEntity])],
|
||||||
|
})
|
||||||
|
export class PowerClampRepositoryModule {}
|
@ -0,0 +1 @@
|
|||||||
|
export * from './power-clamp.repository';
|
@ -0,0 +1,28 @@
|
|||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
PowerClampDailyEntity,
|
||||||
|
PowerClampHourlyEntity,
|
||||||
|
PowerClampMonthlyEntity,
|
||||||
|
} from '../entities/power-clamp.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PowerClampHourlyRepository extends Repository<PowerClampHourlyEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(PowerClampHourlyEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PowerClampDailyRepository extends Repository<PowerClampDailyEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(PowerClampDailyEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PowerClampMonthlyRepository extends Repository<PowerClampMonthlyEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(PowerClampMonthlyEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
WITH params AS (
|
||||||
|
SELECT
|
||||||
|
$1::uuid AS device_id,
|
||||||
|
$2::date AS target_date
|
||||||
|
),
|
||||||
|
total_energy AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumed'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_A AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedA'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_B AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedB'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_C AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedC'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
final_data AS (
|
||||||
|
SELECT
|
||||||
|
t.device_id,
|
||||||
|
t.date,
|
||||||
|
t.event_year::text,
|
||||||
|
t.event_month,
|
||||||
|
t.hour,
|
||||||
|
(t.max_value - t.min_value) AS energy_consumed_kW,
|
||||||
|
(a.max_value - a.min_value) AS energy_consumed_A,
|
||||||
|
(b.max_value - b.min_value) AS energy_consumed_B,
|
||||||
|
(c.max_value - c.min_value) AS energy_consumed_C
|
||||||
|
FROM total_energy t
|
||||||
|
JOIN energy_phase_A a ON t.device_id = a.device_id AND t.date = a.date AND t.hour = a.hour
|
||||||
|
JOIN energy_phase_B b ON t.device_id = b.device_id AND t.date = b.date AND t.hour = b.hour
|
||||||
|
JOIN energy_phase_C c ON t.device_id = c.device_id AND t.date = c.date AND t.hour = c.hour
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Final upsert into daily table
|
||||||
|
INSERT INTO public."power-clamp-energy-consumed-daily" (
|
||||||
|
device_uuid,
|
||||||
|
energy_consumed_kw,
|
||||||
|
energy_consumed_a,
|
||||||
|
energy_consumed_b,
|
||||||
|
energy_consumed_c,
|
||||||
|
date
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
SUM(CAST(energy_consumed_kW AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_A AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_B AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_C AS NUMERIC))::VARCHAR,
|
||||||
|
date
|
||||||
|
FROM final_data
|
||||||
|
GROUP BY device_id, date
|
||||||
|
ON CONFLICT (device_uuid, date) DO UPDATE
|
||||||
|
SET
|
||||||
|
energy_consumed_kw = EXCLUDED.energy_consumed_kw,
|
||||||
|
energy_consumed_a = EXCLUDED.energy_consumed_a,
|
||||||
|
energy_consumed_b = EXCLUDED.energy_consumed_b,
|
||||||
|
energy_consumed_c = EXCLUDED.energy_consumed_c;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
|||||||
|
WITH params AS (
|
||||||
|
SELECT
|
||||||
|
$1::uuid AS device_id,
|
||||||
|
$2::date AS target_date,
|
||||||
|
$3::text AS target_hour
|
||||||
|
),
|
||||||
|
total_energy AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time)::text AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumed'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
AND EXTRACT(HOUR FROM log.event_time)::text = params.target_hour
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_A AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time)::text AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedA'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
AND EXTRACT(HOUR FROM log.event_time)::text = params.target_hour
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_B AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time)::text AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedB'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
AND EXTRACT(HOUR FROM log.event_time)::text = params.target_hour
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_C AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time)::text AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedC'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND log.event_time::date = params.target_date
|
||||||
|
AND EXTRACT(HOUR FROM log.event_time)::text = params.target_hour
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
final_data AS (
|
||||||
|
SELECT
|
||||||
|
t.device_id,
|
||||||
|
t.date,
|
||||||
|
t.event_year::text,
|
||||||
|
t.event_month,
|
||||||
|
t.hour,
|
||||||
|
(t.max_value - t.min_value) AS energy_consumed_kW,
|
||||||
|
(a.max_value - a.min_value) AS energy_consumed_A,
|
||||||
|
(b.max_value - b.min_value) AS energy_consumed_B,
|
||||||
|
(c.max_value - c.min_value) AS energy_consumed_C
|
||||||
|
FROM total_energy t
|
||||||
|
JOIN energy_phase_A a ON t.device_id = a.device_id AND t.date = a.date AND t.hour = a.hour
|
||||||
|
JOIN energy_phase_B b ON t.device_id = b.device_id AND t.date = b.date AND t.hour = b.hour
|
||||||
|
JOIN energy_phase_C c ON t.device_id = c.device_id AND t.date = c.date AND t.hour = c.hour
|
||||||
|
)
|
||||||
|
|
||||||
|
-- UPSERT into hourly table
|
||||||
|
INSERT INTO public."power-clamp-energy-consumed-hourly" (
|
||||||
|
device_uuid,
|
||||||
|
energy_consumed_kw,
|
||||||
|
energy_consumed_a,
|
||||||
|
energy_consumed_b,
|
||||||
|
energy_consumed_c,
|
||||||
|
date,
|
||||||
|
hour
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
SUM(CAST(energy_consumed_kW AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_A AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_B AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_C AS NUMERIC))::VARCHAR,
|
||||||
|
date,
|
||||||
|
hour
|
||||||
|
FROM final_data
|
||||||
|
GROUP BY 1,6,7
|
||||||
|
ON CONFLICT (device_uuid, date, hour) DO UPDATE
|
||||||
|
SET
|
||||||
|
energy_consumed_kw = EXCLUDED.energy_consumed_kw,
|
||||||
|
energy_consumed_a = EXCLUDED.energy_consumed_a,
|
||||||
|
energy_consumed_b = EXCLUDED.energy_consumed_b,
|
||||||
|
energy_consumed_c = EXCLUDED.energy_consumed_c;
|
@ -0,0 +1,107 @@
|
|||||||
|
WITH params AS (
|
||||||
|
SELECT
|
||||||
|
$1::uuid AS device_id,
|
||||||
|
$2::text AS target_month -- Format should match 'MM-YYYY'
|
||||||
|
),
|
||||||
|
total_energy AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumed'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND TO_CHAR(log.event_time, 'MM-YYYY') = params.target_month
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_A AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedA'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND TO_CHAR(log.event_time, 'MM-YYYY') = params.target_month
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_B AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedB'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND TO_CHAR(log.event_time, 'MM-YYYY') = params.target_month
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
energy_phase_C AS (
|
||||||
|
SELECT
|
||||||
|
log.device_id,
|
||||||
|
log.event_time::date AS date,
|
||||||
|
EXTRACT(HOUR FROM log.event_time) AS hour,
|
||||||
|
TO_CHAR(log.event_time, 'MM-YYYY') AS event_month,
|
||||||
|
EXTRACT(YEAR FROM log.event_time)::int AS event_year,
|
||||||
|
MIN(log.value)::integer AS min_value,
|
||||||
|
MAX(log.value)::integer AS max_value
|
||||||
|
FROM "device-status-log" log, params
|
||||||
|
WHERE log.code = 'EnergyConsumedC'
|
||||||
|
AND log.device_id = params.device_id
|
||||||
|
AND TO_CHAR(log.event_time, 'MM-YYYY') = params.target_month
|
||||||
|
GROUP BY 1,2,3,4,5
|
||||||
|
),
|
||||||
|
final_data AS (
|
||||||
|
SELECT
|
||||||
|
t.device_id,
|
||||||
|
t.date,
|
||||||
|
t.event_year::text,
|
||||||
|
t.event_month,
|
||||||
|
t.hour,
|
||||||
|
(t.max_value - t.min_value) AS energy_consumed_kW,
|
||||||
|
(a.max_value - a.min_value) AS energy_consumed_A,
|
||||||
|
(b.max_value - b.min_value) AS energy_consumed_B,
|
||||||
|
(c.max_value - c.min_value) AS energy_consumed_C
|
||||||
|
FROM total_energy t
|
||||||
|
JOIN energy_phase_A a ON t.device_id = a.device_id AND t.date = a.date AND t.hour = a.hour
|
||||||
|
JOIN energy_phase_B b ON t.device_id = b.device_id AND t.date = b.date AND t.hour = b.hour
|
||||||
|
JOIN energy_phase_C c ON t.device_id = c.device_id AND t.date = c.date AND t.hour = c.hour
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Final monthly UPSERT
|
||||||
|
INSERT INTO public."power-clamp-energy-consumed-monthly" (
|
||||||
|
device_uuid,
|
||||||
|
energy_consumed_kw,
|
||||||
|
energy_consumed_a,
|
||||||
|
energy_consumed_b,
|
||||||
|
energy_consumed_c,
|
||||||
|
month
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
SUM(CAST(energy_consumed_kW AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_A AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_B AS NUMERIC))::VARCHAR,
|
||||||
|
SUM(CAST(energy_consumed_C AS NUMERIC))::VARCHAR,
|
||||||
|
event_month
|
||||||
|
FROM final_data
|
||||||
|
GROUP BY device_id, event_month
|
||||||
|
ON CONFLICT (device_uuid, month) DO UPDATE
|
||||||
|
SET
|
||||||
|
energy_consumed_kw = EXCLUDED.energy_consumed_kw,
|
||||||
|
energy_consumed_a = EXCLUDED.energy_consumed_a,
|
||||||
|
energy_consumed_b = EXCLUDED.energy_consumed_b,
|
||||||
|
energy_consumed_c = EXCLUDED.energy_consumed_c;
|
||||||
|
|
@ -21,6 +21,13 @@ import {
|
|||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, SpaceRepositoryModule],
|
imports: [ConfigModule, SpaceRepositoryModule],
|
||||||
@ -43,6 +50,11 @@ import { SubspaceRepository } from '@app/common/modules/space/repositories/subsp
|
|||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
CommunityRepository,
|
CommunityRepository,
|
||||||
SubspaceRepository,
|
SubspaceRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [],
|
exports: [],
|
||||||
})
|
})
|
||||||
|
@ -56,6 +56,13 @@ import {
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
} from '@app/common/modules/scene/repositories';
|
} from '@app/common/modules/scene/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, SpaceRepositoryModule, UserRepositoryModule],
|
imports: [ConfigModule, SpaceRepositoryModule, UserRepositoryModule],
|
||||||
@ -102,6 +109,11 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie
|
|||||||
SceneIconRepository,
|
SceneIconRepository,
|
||||||
SceneRepository,
|
SceneRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [CommunityService, SpacePermissionService],
|
exports: [CommunityService, SpacePermissionService],
|
||||||
})
|
})
|
||||||
|
@ -20,6 +20,13 @@ import {
|
|||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, DeviceRepositoryModule],
|
imports: [ConfigModule, DeviceRepositoryModule],
|
||||||
controllers: [DoorLockController],
|
controllers: [DoorLockController],
|
||||||
@ -40,6 +47,11 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
SceneDeviceRepository,
|
SceneDeviceRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [DoorLockService],
|
exports: [DoorLockService],
|
||||||
})
|
})
|
||||||
|
@ -18,6 +18,13 @@ import {
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
} from '@app/common/modules/scene/repositories';
|
} from '@app/common/modules/scene/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, DeviceRepositoryModule],
|
imports: [ConfigModule, DeviceRepositoryModule],
|
||||||
controllers: [GroupController],
|
controllers: [GroupController],
|
||||||
@ -37,6 +44,11 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie
|
|||||||
SceneIconRepository,
|
SceneIconRepository,
|
||||||
SceneRepository,
|
SceneRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [GroupService],
|
exports: [GroupService],
|
||||||
})
|
})
|
||||||
|
@ -76,6 +76,13 @@ import {
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
} from '@app/common/modules/scene/repositories';
|
} from '@app/common/modules/scene/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, InviteUserRepositoryModule, CommunityModule],
|
imports: [ConfigModule, InviteUserRepositoryModule, CommunityModule],
|
||||||
@ -140,6 +147,11 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie
|
|||||||
SceneIconRepository,
|
SceneIconRepository,
|
||||||
SceneRepository,
|
SceneRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [InviteUserService],
|
exports: [InviteUserService],
|
||||||
})
|
})
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Param, Query, UseGuards } from '@nestjs/common';
|
||||||
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
||||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
import { ControllerRoute } from '@app/common/constants/controller-route';
|
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { PowerClampService } from '../services/power-clamp.service';
|
import { PowerClampService } from '../services/power-clamp.service';
|
||||||
|
import { GetPowerClampDto } from '../dto/get-power-clamp.dto';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
|
||||||
@ApiTags('Power Clamp Module')
|
@ApiTags('Power Clamp Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
@ -15,12 +17,18 @@ export class PowerClampController {
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get()
|
@Get(':powerClampUuid/historical')
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_SUMMARY,
|
summary: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_SUMMARY,
|
||||||
description: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_DESCRIPTION,
|
description: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_DESCRIPTION,
|
||||||
})
|
})
|
||||||
async getPowerClampData() {
|
async getPowerClampData(
|
||||||
return await this.powerClampService.getPowerClampData();
|
@Param('powerClampUuid') powerClampUuid: string,
|
||||||
|
@Query() params: GetPowerClampDto,
|
||||||
|
): Promise<BaseResponseDto> {
|
||||||
|
return await this.powerClampService.getPowerClampData(
|
||||||
|
powerClampUuid,
|
||||||
|
params,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/power-clamp/dto/get-power-clamp.dto.ts
Normal file
35
src/power-clamp/dto/get-power-clamp.dto.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, IsDateString, Matches } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetPowerClampDto {
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Input date in ISO format (YYYY-MM-DD) to filter the data',
|
||||||
|
example: '2025-04-23',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
dayDate?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Month and year in format YYYY-MM',
|
||||||
|
example: '2025-03',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@Matches(/^\d{4}-(0[1-9]|1[0-2])$/, {
|
||||||
|
message: 'monthDate must be in YYYY-MM format',
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
monthDate?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Input year in YYYY format to filter the data',
|
||||||
|
example: '2025',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@Matches(/^\d{4}$/, {
|
||||||
|
message: 'Year must be in YYYY format',
|
||||||
|
})
|
||||||
|
year?: string;
|
||||||
|
}
|
@ -2,11 +2,20 @@ import { Module } from '@nestjs/common';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { PowerClampService } from './services/power-clamp.service';
|
import { PowerClampService } from './services/power-clamp.service';
|
||||||
import { PowerClampController } from './controllers';
|
import { PowerClampController } from './controllers';
|
||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
controllers: [PowerClampController],
|
controllers: [PowerClampController],
|
||||||
providers: [PowerClampService, SqlLoaderService],
|
providers: [
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
],
|
||||||
exports: [PowerClampService],
|
exports: [PowerClampService],
|
||||||
})
|
})
|
||||||
export class PowerClampModule {}
|
export class PowerClampModule {}
|
||||||
|
@ -1,27 +1,88 @@
|
|||||||
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { GetPowerClampDto } from '../dto/get-power-clamp.dto';
|
||||||
import { DataSource } from 'typeorm';
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PowerClampService {
|
export class PowerClampService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sqlLoader: SqlLoaderService,
|
private readonly powerClampDailyRepository: PowerClampDailyRepository,
|
||||||
private readonly dataSource: DataSource,
|
private readonly powerClampHourlyRepository: PowerClampHourlyRepository,
|
||||||
|
private readonly powerClampMonthlyRepository: PowerClampMonthlyRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getPowerClampData() {
|
async getPowerClampData(powerClampUuid: string, params: GetPowerClampDto) {
|
||||||
const sql = this.sqlLoader.loadQuery(
|
const { dayDate, monthDate, year } = params;
|
||||||
'fact_daily_energy_consumed',
|
|
||||||
'fact_daily_energy_consumed',
|
try {
|
||||||
|
if (dayDate) {
|
||||||
|
const data = await this.powerClampHourlyRepository
|
||||||
|
.createQueryBuilder('hourly')
|
||||||
|
.where('hourly.deviceUuid = :deviceUuid', {
|
||||||
|
deviceUuid: powerClampUuid,
|
||||||
|
})
|
||||||
|
.andWhere('hourly.date = :date', { date: dayDate })
|
||||||
|
.orderBy('CAST(hourly.hour AS INTEGER)', 'ASC')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return this.buildResponse(
|
||||||
|
`Power clamp data for day ${dayDate} fetched successfully`,
|
||||||
|
data,
|
||||||
);
|
);
|
||||||
return this.dataSource.manager.query(sql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEnergyConsumed(code: string) {
|
if (monthDate) {
|
||||||
const sql = this.sqlLoader.loadQuery(
|
const data = await this.powerClampDailyRepository
|
||||||
'energy',
|
.createQueryBuilder('daily')
|
||||||
'energy_consumed_with_params',
|
.where('daily.deviceUuid = :deviceUuid', {
|
||||||
|
deviceUuid: powerClampUuid,
|
||||||
|
})
|
||||||
|
.andWhere("TO_CHAR(daily.date, 'YYYY-MM') = :monthDate", {
|
||||||
|
monthDate,
|
||||||
|
})
|
||||||
|
.orderBy('daily.date', 'ASC')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return this.buildResponse(
|
||||||
|
`Power clamp data for month ${monthDate} fetched successfully`,
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year) {
|
||||||
|
const data = await this.powerClampMonthlyRepository
|
||||||
|
.createQueryBuilder('monthly')
|
||||||
|
.where('monthly.deviceUuid = :deviceUuid', {
|
||||||
|
deviceUuid: powerClampUuid,
|
||||||
|
})
|
||||||
|
.andWhere('RIGHT(monthly.month, 4) = :year', { year })
|
||||||
|
.orderBy('monthly.month', 'ASC')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return this.buildResponse(
|
||||||
|
`Power clamp data for year ${year} fetched successfully`,
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.buildResponse(`Power clamp data fetched successfully`, []);
|
||||||
|
} catch (error) {
|
||||||
|
throw new HttpException(
|
||||||
|
'Error fetching power clamp data',
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
);
|
);
|
||||||
return this.dataSource.manager.query(sql, [code]);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildResponse(message: string, data: any[]) {
|
||||||
|
return new SuccessResponseDto({
|
||||||
|
message,
|
||||||
|
data,
|
||||||
|
statusCode: HttpStatus.OK,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,13 @@ import {
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
} from '@app/common/modules/scene/repositories';
|
} from '@app/common/modules/scene/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
const CommandHandlers = [CreateOrphanSpaceHandler];
|
const CommandHandlers = [CreateOrphanSpaceHandler];
|
||||||
|
|
||||||
@ -112,6 +119,11 @@ const CommandHandlers = [CreateOrphanSpaceHandler];
|
|||||||
SceneRepository,
|
SceneRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
SubspaceModelProductAllocationRepoitory,
|
SubspaceModelProductAllocationRepoitory,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [ProjectService, CqrsModule],
|
exports: [ProjectService, CqrsModule],
|
||||||
})
|
})
|
||||||
|
@ -58,6 +58,13 @@ import {
|
|||||||
} from '@app/common/modules/scene/repositories';
|
} from '@app/common/modules/scene/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
import { CommunityModule } from 'src/community/community.module';
|
import { CommunityModule } from 'src/community/community.module';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
const CommandHandlers = [
|
const CommandHandlers = [
|
||||||
PropogateUpdateSpaceModelHandler,
|
PropogateUpdateSpaceModelHandler,
|
||||||
@ -112,6 +119,11 @@ const CommandHandlers = [
|
|||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
SubSpaceService,
|
SubSpaceService,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [CqrsModule, SpaceModelService],
|
exports: [CqrsModule, SpaceModelService],
|
||||||
})
|
})
|
||||||
|
@ -83,6 +83,13 @@ import { SubspaceModelProductAllocationService } from 'src/space-model/services/
|
|||||||
import { SpaceProductAllocationService } from './services/space-product-allocation.service';
|
import { SpaceProductAllocationService } from './services/space-product-allocation.service';
|
||||||
import { SubspaceProductAllocationService } from './services/subspace/subspace-product-allocation.service';
|
import { SubspaceProductAllocationService } from './services/subspace/subspace-product-allocation.service';
|
||||||
import { SpaceValidationController } from './controllers/space-validation.controller';
|
import { SpaceValidationController } from './controllers/space-validation.controller';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
|
||||||
export const CommandHandlers = [DisableSpaceHandler];
|
export const CommandHandlers = [DisableSpaceHandler];
|
||||||
|
|
||||||
@ -154,6 +161,11 @@ export const CommandHandlers = [DisableSpaceHandler];
|
|||||||
SubspaceProductAllocationService,
|
SubspaceProductAllocationService,
|
||||||
SpaceProductAllocationRepository,
|
SpaceProductAllocationRepository,
|
||||||
SubspaceProductAllocationRepository,
|
SubspaceProductAllocationRepository,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
PowerClampService,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [SpaceService],
|
exports: [SpaceService],
|
||||||
})
|
})
|
||||||
|
@ -22,6 +22,13 @@ import {
|
|||||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||||
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
import { AutomationRepository } from '@app/common/modules/automation/repositories';
|
||||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||||
|
import { PowerClampService } from '@app/common/helper/services/power.clamp.service';
|
||||||
|
import {
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
} from '@app/common/modules/power-clamp/repositories';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, DeviceRepositoryModule, DoorLockModule],
|
imports: [ConfigModule, DeviceRepositoryModule, DoorLockModule],
|
||||||
controllers: [VisitorPasswordController],
|
controllers: [VisitorPasswordController],
|
||||||
@ -43,6 +50,11 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
|||||||
SceneDeviceRepository,
|
SceneDeviceRepository,
|
||||||
AutomationRepository,
|
AutomationRepository,
|
||||||
ProjectRepository,
|
ProjectRepository,
|
||||||
|
PowerClampService,
|
||||||
|
PowerClampHourlyRepository,
|
||||||
|
PowerClampDailyRepository,
|
||||||
|
PowerClampMonthlyRepository,
|
||||||
|
SqlLoaderService,
|
||||||
],
|
],
|
||||||
exports: [VisitorPasswordService],
|
exports: [VisitorPasswordService],
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user