mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 23:27:31 +00:00
Add PowerClamp module with controller and service for energy data retrieval
This commit is contained in:
@ -482,7 +482,15 @@ export class ControllerRoute {
|
|||||||
'This endpoint retrieves all devices in a specified group within a space, based on the group name and space UUID.';
|
'This endpoint retrieves all devices in a specified group within a space, based on the group name and space UUID.';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
static PowerClamp = class {
|
||||||
|
public static readonly ROUTE = 'power-clamp';
|
||||||
|
|
||||||
|
static ACTIONS = class {
|
||||||
|
public static readonly GET_ENERGY_SUMMARY = 'Get power clamp data';
|
||||||
|
public static readonly GET_ENERGY_DESCRIPTION =
|
||||||
|
'This endpoint retrieves power clamp data for a specific device.';
|
||||||
|
};
|
||||||
|
};
|
||||||
static DEVICE = class {
|
static DEVICE = class {
|
||||||
public static readonly ROUTE = 'devices';
|
public static readonly ROUTE = 'devices';
|
||||||
|
|
||||||
|
1
libs/common/src/constants/sql-query-path.ts
Normal file
1
libs/common/src/constants/sql-query-path.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const SQL_QUERIES_PATH = 'libs/common/src/sql/queries';
|
28
libs/common/src/helper/services/sql-loader.service.ts
Normal file
28
libs/common/src/helper/services/sql-loader.service.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { SQL_QUERIES_PATH } from '@app/common/constants/sql-query-path';
|
||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SqlLoaderService {
|
||||||
|
private readonly logger = new Logger(SqlLoaderService.name);
|
||||||
|
private readonly sqlRootPath = join(__dirname, '../sql/queries');
|
||||||
|
|
||||||
|
loadQuery(module: string, queryName: string): string {
|
||||||
|
const filePath = join(
|
||||||
|
process.cwd(),
|
||||||
|
SQL_QUERIES_PATH,
|
||||||
|
module,
|
||||||
|
`${queryName}.sql`,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
return readFileSync(filePath, 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`Failed to load SQL query: ${module}/${queryName}`,
|
||||||
|
error.stack,
|
||||||
|
);
|
||||||
|
throw new Error(`SQL query not found: ${module}/${queryName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
|||||||
})
|
})
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
||||||
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false })
|
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: true })
|
||||||
user: UserEntity;
|
user: UserEntity;
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
-- model shows the energy consumed per day per device
|
||||||
|
|
||||||
|
WITH total_energy AS (
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
event_time::date AS date,
|
||||||
|
MIN(value)::integer AS min_value,
|
||||||
|
MAX(value)::integer AS max_value
|
||||||
|
FROM "device-status-log"
|
||||||
|
where code='EnergyConsumed'
|
||||||
|
GROUP BY device_id, date
|
||||||
|
)
|
||||||
|
|
||||||
|
, energy_phase_A AS (
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
event_time::date AS date,
|
||||||
|
MIN(value)::integer AS min_value,
|
||||||
|
MAX(value)::integer AS max_value
|
||||||
|
FROM "device-status-log"
|
||||||
|
where code='EnergyConsumedA'
|
||||||
|
GROUP BY device_id, date
|
||||||
|
)
|
||||||
|
|
||||||
|
, energy_phase_B AS (
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
event_time::date AS date,
|
||||||
|
MIN(value)::integer AS min_value,
|
||||||
|
MAX(value)::integer AS max_value
|
||||||
|
FROM "device-status-log"
|
||||||
|
where code='EnergyConsumedB'
|
||||||
|
GROUP BY device_id, date
|
||||||
|
)
|
||||||
|
|
||||||
|
, energy_phase_C AS (
|
||||||
|
SELECT
|
||||||
|
device_id,
|
||||||
|
event_time::date AS date,
|
||||||
|
MIN(value)::integer AS min_value,
|
||||||
|
MAX(value)::integer AS max_value
|
||||||
|
FROM "device-status-log"
|
||||||
|
where code='EnergyConsumedC'
|
||||||
|
GROUP BY device_id, date
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
total_energy.device_id,
|
||||||
|
total_energy.date,
|
||||||
|
(total_energy.max_value-total_energy.min_value) as energy_consumed_kW,
|
||||||
|
(energy_phase_A.max_value-energy_phase_A.min_value) as energy_consumed_A,
|
||||||
|
(energy_phase_B.max_value-energy_phase_B.min_value) as energy_consumed_B,
|
||||||
|
(energy_phase_C.max_value-energy_phase_C.min_value) as energy_consumed_C
|
||||||
|
FROM total_energy
|
||||||
|
JOIN energy_phase_A
|
||||||
|
ON total_energy.device_id=energy_phase_A.device_id
|
||||||
|
and total_energy.date=energy_phase_A.date
|
||||||
|
JOIN energy_phase_B
|
||||||
|
ON total_energy.device_id=energy_phase_B.device_id
|
||||||
|
and total_energy.date=energy_phase_B.date
|
||||||
|
JOIN energy_phase_C
|
||||||
|
ON total_energy.device_id=energy_phase_C.device_id
|
||||||
|
and total_energy.date=energy_phase_C.date
|
||||||
|
|
@ -31,6 +31,7 @@ import { PrivacyPolicyModule } from './privacy-policy/privacy-policy.module';
|
|||||||
import { TagModule } from './tags/tags.module';
|
import { TagModule } from './tags/tags.module';
|
||||||
import { ClientModule } from './client/client.module';
|
import { ClientModule } from './client/client.module';
|
||||||
import { DeviceCommissionModule } from './commission-device/commission-device.module';
|
import { DeviceCommissionModule } from './commission-device/commission-device.module';
|
||||||
|
import { PowerClampModule } from './power-clamp/power-clamp.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
@ -64,8 +65,8 @@ import { DeviceCommissionModule } from './commission-device/commission-device.mo
|
|||||||
TermsConditionsModule,
|
TermsConditionsModule,
|
||||||
PrivacyPolicyModule,
|
PrivacyPolicyModule,
|
||||||
TagModule,
|
TagModule,
|
||||||
|
|
||||||
DeviceCommissionModule,
|
DeviceCommissionModule,
|
||||||
|
PowerClampModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
|
1
src/power-clamp/controllers/index.ts
Normal file
1
src/power-clamp/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './power-clamp.controller';
|
26
src/power-clamp/controllers/power-clamp.controller.ts
Normal file
26
src/power-clamp/controllers/power-clamp.controller.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||||
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
import { PowerClampService } from '../services/power-clamp.service';
|
||||||
|
|
||||||
|
@ApiTags('Power Clamp Module')
|
||||||
|
@Controller({
|
||||||
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
|
path: ControllerRoute.PowerClamp.ROUTE,
|
||||||
|
})
|
||||||
|
export class PowerClampController {
|
||||||
|
constructor(private readonly powerClampService: PowerClampService) {}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get()
|
||||||
|
@ApiOperation({
|
||||||
|
summary: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_SUMMARY,
|
||||||
|
description: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_DESCRIPTION,
|
||||||
|
})
|
||||||
|
async getPowerClampData() {
|
||||||
|
return await this.powerClampService.getPowerClampData();
|
||||||
|
}
|
||||||
|
}
|
12
src/power-clamp/power-clamp.module.ts
Normal file
12
src/power-clamp/power-clamp.module.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { PowerClampService } from './services/power-clamp.service';
|
||||||
|
import { PowerClampController } from './controllers';
|
||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
controllers: [PowerClampController],
|
||||||
|
providers: [PowerClampService, SqlLoaderService],
|
||||||
|
exports: [PowerClampService],
|
||||||
|
})
|
||||||
|
export class PowerClampModule {}
|
1
src/power-clamp/services/index.ts
Normal file
1
src/power-clamp/services/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './power-clamp.service';
|
27
src/power-clamp/services/power-clamp.service.ts
Normal file
27
src/power-clamp/services/power-clamp.service.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { SqlLoaderService } from '@app/common/helper/services/sql-loader.service';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PowerClampService {
|
||||||
|
constructor(
|
||||||
|
private readonly sqlLoader: SqlLoaderService,
|
||||||
|
private readonly dataSource: DataSource,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async getPowerClampData() {
|
||||||
|
const sql = this.sqlLoader.loadQuery(
|
||||||
|
'power-clamp',
|
||||||
|
'fact_daily_energy_consumed',
|
||||||
|
);
|
||||||
|
return this.dataSource.manager.query(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEnergyConsumed(code: string) {
|
||||||
|
const sql = this.sqlLoader.loadQuery(
|
||||||
|
'energy',
|
||||||
|
'energy_consumed_with_params',
|
||||||
|
);
|
||||||
|
return this.dataSource.manager.query(sql, [code]);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user