Skip to content

Commit

Permalink
PR changes
Browse files Browse the repository at this point in the history
  • Loading branch information
August Andersen committed Sep 26, 2024
1 parent f2e5f23 commit 64c8e50
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class ChirpstackGatewayController {
@GatewayAdmin()
async create(@Req() req: AuthenticatedRequest, @Body() dto: CreateGatewayDto): Promise<ChirpstackResponseStatus> {
checkIfUserHasAccessToOrganization(req, dto.organizationId, OrganizationAccessScope.GatewayWrite);
this.chirpstackGatewayService.checkForMinMaxNumbers(dto);
this.chirpstackGatewayService.validatePackageAlarmInput(dto);
try {
const gateway = await this.chirpstackGatewayService.createNewGateway(dto, req.user.userId);
AuditLog.success(
Expand Down Expand Up @@ -111,7 +111,7 @@ export class ChirpstackGatewayController {
@Body() dto: UpdateGatewayDto
): Promise<ChirpstackResponseStatus> {
try {
this.chirpstackGatewayService.checkForMinMaxNumbers(dto);
this.chirpstackGatewayService.validatePackageAlarmInput(dto);
if (dto.gateway.gatewayId) {
throw new BadRequestException(ErrorCodes.GatewayIdNotAllowedInUpdate);
}
Expand Down
16 changes: 8 additions & 8 deletions src/entities/dto/chirpstack/gateway-contents.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,35 +111,35 @@ export class GatewayContentsDto {
@ApiProperty({ required: false })
@IsOptional()
@IsBoolean()
notificationOffline?: boolean;
notifyOffline?: boolean;

@ApiProperty({ required: false })
@IsOptional()
@IsBoolean()
notificationUnusualPackages?: boolean;
notifyUnusualPackages?: boolean;

@ApiProperty({ required: false })
@Min(0)
@Min(1)
@IsInt()
@ValidateIf(value => value.notificationOffline)
amountOfMinutes?: number;
@ValidateIf(value => value.notifyOffline)
offlineAlarmThresholdMinutes?: number;

@ApiProperty({ required: false })
@Min(0)
@IsInt()
@ValidateIf(value => value.notificationUnusualPackages)
@ValidateIf(value => value.notifyUnusualPackages)
minimumPackages?: number;

@ApiProperty({ required: false })
@Min(0)
@IsInt()
@ValidateIf(value => value.notificationUnusualPackages)
@ValidateIf(value => value.notifyUnusualPackages)
maximumPackages?: number;

@ApiProperty({ required: false })
@IsString()
@IsEmail()
@ValidateIf(value => (value.notificationOffline || value.notificationUnusualPackages) && !value.alarmMail)
@ValidateIf(value => (value.notifyOffline || value.notifyUnusualPackages) && !value.alarmMail)
alarmMail?: string;

@ApiHideProperty()
Expand Down
6 changes: 3 additions & 3 deletions src/entities/dto/chirpstack/gateway-response.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ export class GatewayResponseDto {
lastSeenAt?: Date;
updatedBy?: number;
createdBy?: number;
notificationOffline?: boolean;
notificationUnusualPackages?: boolean;
amountOfMinutes?: number;
notifyOffline?: boolean;
notifyUnusualPackages?: boolean;
offlineAlarmThresholdMinutes?: number;
minimumPackages?: number;
maximumPackages?: number;
alarmMail?: string;
Expand Down
6 changes: 3 additions & 3 deletions src/entities/gateway.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export class Gateway extends DbBaseEntity {
@Column({ nullable: true })
operationalResponsibleEmail?: string;
@Column({ nullable: true })
notificationOffline?: boolean;
notifyOffline?: boolean;
@Column({ nullable: true })
notificationUnusualPackages?: boolean;
notifyUnusualPackages?: boolean;
@Column({ nullable: true })
amountOfMinutes?: number;
offlineAlarmThresholdMinutes?: number;
@Column({ nullable: true })
minimumPackages?: number;
@Column({ nullable: true })
Expand Down
25 changes: 0 additions & 25 deletions src/migration/1727189075678-addedAlarmPropsToGateway.ts

This file was deleted.

26 changes: 26 additions & 0 deletions src/migration/1727271446786-addedAlarmPropsToGateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddedAlarmPropsToGateway1727271446786 implements MigrationInterface {
name = 'AddedAlarmPropsToGateway1727271446786'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "gateway" ADD "notifyOffline" boolean`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "notifyUnusualPackages" boolean`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "offlineAlarmThresholdMinutes" integer`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "minimumPackages" integer`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "maximumPackages" integer`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "alarmMail" character varying`);
await queryRunner.query(`ALTER TABLE "gateway" ADD "hasSentOfflineNotification" boolean`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "hasSentOfflineNotification"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "alarmMail"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "maximumPackages"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "minimumPackages"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "offlineAlarmThresholdMinutes"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "notifyUnusualPackages"`);
await queryRunner.query(`ALTER TABLE "gateway" DROP COLUMN "notifyOffline"`);
}

}
92 changes: 55 additions & 37 deletions src/services/chirpstack/chirpstack-gateway.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
UpdateGatewayRequest,
} from "@chirpstack/chirpstack-api/api/gateway_pb";
import { Aggregation, AggregationMap, Location } from "@chirpstack/chirpstack-api/common/common_pb";
import configuration from "@config/configuration";
import { ChirpstackErrorResponseDto } from "@dto/chirpstack/chirpstack-error-response.dto";
import { ChirpstackResponseStatus } from "@dto/chirpstack/chirpstack-response.dto";
import { CommonLocationDto } from "@dto/chirpstack/common-location.dto";
Expand Down Expand Up @@ -146,7 +145,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ

async getAllWithUnusualPackagesAlarms(): Promise<ListAllGatewaysResponseDto> {
const gateways = await this.gatewayRepository.find({
where: { notificationUnusualPackages: true },
where: { notifyUnusualPackages: true },
relations: ["organization"],
});
return {
Expand Down Expand Up @@ -461,9 +460,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
gateway.operationalResponsibleName = dto.operationalResponsibleName;
gateway.operationalResponsibleEmail = dto.operationalResponsibleEmail;
gateway.alarmMail = dto.alarmMail;
gateway.notificationOffline = dto.notificationOffline;
gateway.notificationUnusualPackages = dto.notificationUnusualPackages;
gateway.amountOfMinutes = dto.amountOfMinutes;
gateway.notifyOffline = dto.notifyOffline;
gateway.notifyUnusualPackages = dto.notifyUnusualPackages;
gateway.offlineAlarmThresholdMinutes = dto.offlineAlarmThresholdMinutes;
gateway.minimumPackages = dto.minimumPackages;
gateway.maximumPackages = dto.maximumPackages;

Expand Down Expand Up @@ -584,54 +583,76 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
return orderBy;
}

checkForMinMaxNumbers(dto: UpdateGatewayDto) {
validatePackageAlarmInput(dto: UpdateGatewayDto) {
if (dto.gateway.minimumPackages > dto.gateway.maximumPackages) {
throw new BadRequestException({
success: false,
error: "Minimum has to be under maximum, and maximum has to be over minimum",
});
}
}

async checkForAlarms(gateways: GatewayResponseDto[]) {
for (let index = 0; index < gateways.length; index++) {
if (gateways[index].notificationOffline) {
if (gateways[index].notifyOffline) {
await this.checkForNotificationOfflineAlarms(gateways[index]);
}
}
}

async checkForUnusualPackagesAlarms(gateways: GatewayResponseDto[]) {
for (let index = 0; index < gateways.length; index++) {
await this.checkForNotificationUnusualPackagesAlarms(gateways[index]);
}
}

private async checkForNotificationOfflineAlarms(gateway: GatewayResponseDto) {
const actualDate = dayjs();
const currentDate = dayjs();
const lastSeen = dayjs(gateway.lastSeenAt);
if (actualDate.diff(lastSeen, "minute") > gateway.amountOfMinutes && !gateway.hasSentOfflineNotification) {
await this.oS2IoTMail.sendMail({
to: gateway.alarmMail,
subject: `OS2iot alarm: ${gateway.name} er offline`,
html: `<p>OS2iot alarm</p>
<p>Gateway’en ${gateway.name} er offline.</p>
<p>Der udsendes først besked igen, når gateway’en kommer online.</p>
<p>Link: <a href="${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${
gateway.gatewayId
}">${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${gateway.gatewayId}</a></p>
`,
});
if (
currentDate.diff(lastSeen, "minute") >= gateway.offlineAlarmThresholdMinutes &&
!gateway.hasSentOfflineNotification
) {
await this.sendEmailForNotificationOffline(gateway);
await this.gatewayRepository.update({ gatewayId: gateway.gatewayId }, { hasSentOfflineNotification: true });
} else if (gateway.hasSentOfflineNotification && actualDate.diff(lastSeen, "minute") <= gateway.amountOfMinutes) {
await this.oS2IoTMail.sendMail({
to: gateway.alarmMail,
subject: `OS2iot alarm: ${gateway.name} er online igen`,
html: `<p>OS2iot alarm</p>
} else if (
gateway.hasSentOfflineNotification &&
currentDate.diff(lastSeen, "minute") <= gateway.offlineAlarmThresholdMinutes
) {
await this.sendEmailForNotificationOnlineAgain(gateway);
await this.gatewayRepository.update({ gatewayId: gateway.gatewayId }, { hasSentOfflineNotification: false });
}
}

private async sendEmailForNotificationOnlineAgain(gateway: GatewayResponseDto) {
await this.oS2IoTMail.sendMail({
to: gateway.alarmMail,
subject: `OS2iot alarm: ${gateway.name} er online igen`,
html: `<p>OS2iot alarm</p>
<p>Gateway’en ${gateway.name} er kommet online igen ${gateway.lastSeenAt.toLocaleString("da-DK", {
timeZone: "Europe/Copenhagen",
})}.</p>
timeZone: "Europe/Copenhagen",
})}.</p>
<p>Der udsendes først besked igen, når gateway’en kommer online.</p>
<p>Link: <a href="${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${
gateway.gatewayId
}">${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${gateway.gatewayId}</a></p>`,
});
await this.gatewayRepository.update({ gatewayId: gateway.gatewayId }, { hasSentOfflineNotification: false });
}
gateway.gatewayId
}">${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${gateway.gatewayId}</a></p>`,
});
}

private async sendEmailForNotificationOffline(gateway: GatewayResponseDto) {
await this.oS2IoTMail.sendMail({
to: gateway.alarmMail,
subject: `OS2iot alarm: ${gateway.name} er offline`,
html: `<p>OS2iot alarm</p>
<p>Gateway’en ${gateway.name} er offline.</p>
<p>Der udsendes først besked igen, når gateway’en kommer online.</p>
<p>Link: <a href="${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${
gateway.gatewayId
}">${this.configService.get<string>("frontend.baseurl")}/gateways/gateway-detail/${gateway.gatewayId}</a></p>
`,
});
}

public async checkForNotificationUnusualPackagesAlarms(gateway: GatewayResponseDto) {
if (!gateway.lastSeenAt) {
return;
Expand All @@ -647,12 +668,9 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
Aggregation.DAY
);

let receivedPackages = 0;
gatewayStats.forEach(stats => {
receivedPackages += stats.rxPacketsReceived;
});
const receivedPackages = gatewayStats[0].rxPacketsReceived;

if (receivedPackages > gateway.minimumPackages && receivedPackages < gateway.maximumPackages) {
if (gateway.minimumPackages < receivedPackages && receivedPackages < gateway.maximumPackages) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class LorawanDeviceDatabaseEnrichJob {
const gateways = await this.gatewayService.getAll();
const chirpstackGateways = await this.gatewayService.getAllGatewaysFromChirpstack();
try {
await this.gatewayService.checkForAlarms(gateways.resultList.filter(gw => gw.notificationOffline));
await this.gatewayService.checkForAlarms(gateways.resultList.filter(gw => gw.notifyOffline));
} catch (e) {
this.logger.error(`alarm check for gateways failed with: ${JSON.stringify(e)}`, e);
}
Expand Down Expand Up @@ -84,9 +84,7 @@ export class LorawanDeviceDatabaseEnrichJob {
async checkUnusualPackagesForGateways() {
const gateways = await this.gatewayService.getAllWithUnusualPackagesAlarms();
try {
for (let index = 0; index < gateways.resultList.length; index++) {
await this.gatewayService.checkForNotificationUnusualPackagesAlarms(gateways.resultList[index]);
}
await this.gatewayService.checkForUnusualPackagesAlarms(gateways.resultList.filter(gw => gw.notifyUnusualPackages));
} catch (e) {
this.logger.error(`alarm check for gateways failed with: ${JSON.stringify(e)}`, e);
throw e;
Expand Down

0 comments on commit 64c8e50

Please sign in to comment.