Skip to content

Commit 2bb31fa

Browse files
Bugfix/#206 gateway metadata error (#287)
* Fix chirpstack gateway tags format to handle non-string JSON values like false * Also fix gateway edit + device profile
1 parent 8e66abc commit 2bb31fa

File tree

2 files changed

+109
-107
lines changed

2 files changed

+109
-107
lines changed

src/services/chirpstack/chirpstack-gateway.service.ts

Lines changed: 108 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
2-
Gateway as ChirpstackGateway,
32
CreateGatewayRequest,
43
DeleteGatewayRequest,
4+
Gateway as ChirpstackGateway,
55
GetGatewayMetricsRequest,
66
GetGatewayMetricsResponse,
77
GetGatewayRequest,
@@ -53,6 +53,12 @@ import { Repository } from "typeorm";
5353

5454
@Injectable()
5555
export class ChirpstackGatewayService extends GenericChirpstackConfigurationService {
56+
GATEWAY_STATS_INTERVAL_IN_DAYS = 29;
57+
GATEWAY_LAST_ACTIVE_SINCE_IN_MINUTES = 3;
58+
private readonly logger = new Logger(ChirpstackGatewayService.name, {
59+
timestamp: true,
60+
});
61+
5662
constructor(
5763
@InjectRepository(DbGateway)
5864
private gatewayRepository: Repository<DbGateway>,
@@ -62,11 +68,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
6268
) {
6369
super();
6470
}
65-
GATEWAY_STATS_INTERVAL_IN_DAYS = 29;
66-
GATEWAY_LAST_ACTIVE_SINCE_IN_MINUTES = 3;
67-
private readonly logger = new Logger(ChirpstackGatewayService.name, {
68-
timestamp: true,
69-
});
7071

7172
async createNewGateway(dto: CreateGatewayDto, userId: number): Promise<ChirpstackResponseStatus> {
7273
dto.gateway = await this.updateDtoContents(dto.gateway);
@@ -87,7 +88,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
8788

8889
const gatewayChirpstack = await this.mapToChirpstackGateway(dto, chirpstackLocation);
8990
Object.entries(dto.gateway.tags).forEach(([key, value]) => {
90-
gatewayChirpstack.getTagsMap().set(key, value);
91+
gatewayChirpstack.getTagsMap().set(key, value.toString());
9192
});
9293

9394
req.setGateway(gatewayChirpstack);
@@ -302,54 +303,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
302303
}
303304
}
304305

305-
//TODO: This could be moved to a helper function in the future, since it has a lot of similarities with metrics from chirpstack devices.
306-
private mapPackets(metrics: GetGatewayMetricsResponse) {
307-
const gatewayResponseDto: GatewayStatsElementDto[] = [];
308-
const packetCounts: { [timestamp: string]: { rx: number; tx: number } } = {};
309-
310-
const rxTimestamps = metrics.getRxPackets().getTimestampsList();
311-
const rxPackets = metrics
312-
.getRxPackets()
313-
.getDatasetsList()
314-
.find(e => e.getLabel() === "rx_count")
315-
.getDataList();
316-
317-
this.processPackets(rxTimestamps, rxPackets, "rx", packetCounts);
318-
319-
const txTimestamps = metrics.getTxPackets().getTimestampsList();
320-
const txPackets = metrics
321-
.getTxPackets()
322-
.getDatasetsList()
323-
.find(e => e.getLabel() === "tx_count")
324-
.getDataList();
325-
326-
this.processPackets(txTimestamps, txPackets, "tx", packetCounts);
327-
328-
Object.keys(packetCounts).forEach(timestamp => {
329-
const packetCount = packetCounts[timestamp];
330-
const dto: GatewayStatsElementDto = {
331-
timestamp,
332-
rxPacketsReceived: packetCount.rx,
333-
txPacketsEmitted: packetCount.tx,
334-
};
335-
gatewayResponseDto.push(dto);
336-
});
337-
return gatewayResponseDto;
338-
}
339-
340-
private processPackets(
341-
timestamps: Array<Timestamp>,
342-
packets: number[],
343-
key: string,
344-
packetCounts: { [timestamp: string]: { rx: number; tx: number } }
345-
) {
346-
timestamps.forEach((timestamp, index) => {
347-
const isoTimestamp = timestamp.toDate().toISOString();
348-
packetCounts[isoTimestamp] = packetCounts[isoTimestamp] || { rx: 0, tx: 0 };
349-
(packetCounts[isoTimestamp] as any)[key] = packets[index];
350-
});
351-
}
352-
353306
async modifyGateway(
354307
gatewayId: string,
355308
dto: UpdateGatewayDto,
@@ -370,7 +323,7 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
370323
const gatewayCs = await this.mapToChirpstackGateway(dto, location, gatewayId);
371324

372325
Object.entries(dto.gateway.tags).forEach(([key, value]) => {
373-
gatewayCs.getTagsMap().set(key, value);
326+
gatewayCs.getTagsMap().set(key, value.toString());
374327
});
375328

376329
request.setGateway(gatewayCs);
@@ -447,20 +400,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
447400
}
448401
}
449402

450-
private async updateDtoContents(
451-
contentsDto: GatewayContentsDto | UpdateGatewayContentsDto
452-
): Promise<GatewayContentsDto | UpdateGatewayContentsDto> {
453-
if (contentsDto?.tagsString) {
454-
contentsDto.tags = JSON.parse(contentsDto.tagsString);
455-
} else {
456-
contentsDto.tags = {};
457-
}
458-
459-
contentsDto.id = contentsDto.gatewayId;
460-
461-
return contentsDto;
462-
}
463-
464403
public mapContentsDtoToGateway(dto: GatewayContentsDto) {
465404
const gateway = new DbGateway();
466405
gateway.name = dto.name;
@@ -536,24 +475,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
536475

537476
return gateway;
538477
}
539-
private mapGatewayToResponseDto(gateway: DbGateway, forMap = false): GatewayResponseDto {
540-
const responseDto = gateway as unknown as GatewayResponseDto;
541-
responseDto.organizationId = gateway.organization.id;
542-
responseDto.organizationName = gateway.organization.name;
543-
544-
const commonLocation = new CommonLocationDto();
545-
commonLocation.latitude = gateway.location.coordinates[1];
546-
commonLocation.longitude = gateway.location.coordinates[0];
547-
548-
if (!forMap) {
549-
commonLocation.altitude = gateway.altitude;
550-
responseDto.tags = JSON.parse(gateway.tags);
551-
}
552-
553-
responseDto.location = commonLocation;
554-
555-
return responseDto;
556-
}
557478

558479
async getAllGatewaysFromChirpstack(): Promise<ListAllChirpstackGatewaysResponseDto> {
559480
const limit = 1000;
@@ -587,24 +508,6 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
587508
return responseList;
588509
}
589510

590-
private getSortingForGateways(query: ListAllEntitiesDto) {
591-
let orderBy = "gateway.id";
592-
593-
if (!query.orderOn) {
594-
return orderBy;
595-
}
596-
597-
if (query.orderOn === "organizationName") {
598-
orderBy = "organization.name";
599-
} else if (query.orderOn === "status") {
600-
orderBy = "gateway.lastSeenAt";
601-
} else {
602-
orderBy = `gateway.${query.orderOn}`;
603-
}
604-
605-
return orderBy;
606-
}
607-
608511
validatePackageAlarmInput(dto: UpdateGatewayDto) {
609512
if (dto.gateway.minimumPackages > dto.gateway.maximumPackages) {
610513
throw new BadRequestException({
@@ -628,6 +531,105 @@ export class ChirpstackGatewayService extends GenericChirpstackConfigurationServ
628531
}
629532
}
630533

534+
//TODO: This could be moved to a helper function in the future, since it has a lot of similarities with metrics from chirpstack devices.
535+
private mapPackets(metrics: GetGatewayMetricsResponse) {
536+
const gatewayResponseDto: GatewayStatsElementDto[] = [];
537+
const packetCounts: { [timestamp: string]: { rx: number; tx: number } } = {};
538+
539+
const rxTimestamps = metrics.getRxPackets().getTimestampsList();
540+
const rxPackets = metrics
541+
.getRxPackets()
542+
.getDatasetsList()
543+
.find(e => e.getLabel() === "rx_count")
544+
.getDataList();
545+
546+
this.processPackets(rxTimestamps, rxPackets, "rx", packetCounts);
547+
548+
const txTimestamps = metrics.getTxPackets().getTimestampsList();
549+
const txPackets = metrics
550+
.getTxPackets()
551+
.getDatasetsList()
552+
.find(e => e.getLabel() === "tx_count")
553+
.getDataList();
554+
555+
this.processPackets(txTimestamps, txPackets, "tx", packetCounts);
556+
557+
Object.keys(packetCounts).forEach(timestamp => {
558+
const packetCount = packetCounts[timestamp];
559+
const dto: GatewayStatsElementDto = {
560+
timestamp,
561+
rxPacketsReceived: packetCount.rx,
562+
txPacketsEmitted: packetCount.tx,
563+
};
564+
gatewayResponseDto.push(dto);
565+
});
566+
return gatewayResponseDto;
567+
}
568+
569+
private processPackets(
570+
timestamps: Array<Timestamp>,
571+
packets: number[],
572+
key: string,
573+
packetCounts: { [timestamp: string]: { rx: number; tx: number } }
574+
) {
575+
timestamps.forEach((timestamp, index) => {
576+
const isoTimestamp = timestamp.toDate().toISOString();
577+
packetCounts[isoTimestamp] = packetCounts[isoTimestamp] || { rx: 0, tx: 0 };
578+
(packetCounts[isoTimestamp] as any)[key] = packets[index];
579+
});
580+
}
581+
582+
private async updateDtoContents(
583+
contentsDto: GatewayContentsDto | UpdateGatewayContentsDto
584+
): Promise<GatewayContentsDto | UpdateGatewayContentsDto> {
585+
if (contentsDto?.tagsString) {
586+
contentsDto.tags = JSON.parse(contentsDto.tagsString);
587+
} else {
588+
contentsDto.tags = {};
589+
}
590+
591+
contentsDto.id = contentsDto.gatewayId;
592+
593+
return contentsDto;
594+
}
595+
596+
private mapGatewayToResponseDto(gateway: DbGateway, forMap = false): GatewayResponseDto {
597+
const responseDto = gateway as unknown as GatewayResponseDto;
598+
responseDto.organizationId = gateway.organization.id;
599+
responseDto.organizationName = gateway.organization.name;
600+
601+
const commonLocation = new CommonLocationDto();
602+
commonLocation.latitude = gateway.location.coordinates[1];
603+
commonLocation.longitude = gateway.location.coordinates[0];
604+
605+
if (!forMap) {
606+
commonLocation.altitude = gateway.altitude;
607+
responseDto.tags = JSON.parse(gateway.tags);
608+
}
609+
610+
responseDto.location = commonLocation;
611+
612+
return responseDto;
613+
}
614+
615+
private getSortingForGateways(query: ListAllEntitiesDto) {
616+
let orderBy = "gateway.id";
617+
618+
if (!query.orderOn) {
619+
return orderBy;
620+
}
621+
622+
if (query.orderOn === "organizationName") {
623+
orderBy = "organization.name";
624+
} else if (query.orderOn === "status") {
625+
orderBy = "gateway.lastSeenAt";
626+
} else {
627+
orderBy = `gateway.${query.orderOn}`;
628+
}
629+
630+
return orderBy;
631+
}
632+
631633
private async checkForNotificationUnusualPackagesAlarms(gateway: GatewayResponseDto) {
632634
if (!gateway.lastSeenAt) {
633635
return;

src/services/chirpstack/device-profile.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export class DeviceProfileService extends GenericChirpstackConfigurationService
5252
const deviceProfile = this.mapToChirpstackDto(dto, true);
5353

5454
Object.entries(dto.deviceProfile.tags).forEach(([key, value]) => {
55-
deviceProfile.getTagsMap().set(key, value);
55+
deviceProfile.getTagsMap().set(key, value.toString());
5656
});
5757

5858
req.setDeviceProfile(deviceProfile);

0 commit comments

Comments
 (0)