Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Roadmap features: Mqtt broker/subscriber support #137

Merged
merged 25 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1e28140
Shell for supporting new device type, currently not fully working
fcv-iteratorIt Apr 25, 2023
387c281
Added broker details page
fcv-iteratorIt Apr 27, 2023
c54c015
Merge branch 'stage' into feature/mqtt-broker-support
fcv-iteratorIt Apr 27, 2023
5425001
Information bubbles for username/password for MQTT broker
fcv-iteratorIt Apr 27, 2023
e3613d5
Support added for receiving data from mqtt broker
fcv-iteratorIt May 8, 2023
909b493
Bulk import changes and new type
fcv-iteratorIt May 8, 2023
53beb12
Bulk import of mqtt devices and halfbaked csv export
fcv-iteratorIt May 11, 2023
b15d98f
Disabled most editing on mqtt subscriber
fcv-iteratorIt May 12, 2023
a30443e
IOT-1469
fcv-iteratorIt May 16, 2023
a020d0b
Fixes from PR
fcv-iteratorIt May 17, 2023
7021004
Added CA to password brokers. Added download button to cert files
fcv-iteratorIt May 17, 2023
1e7a848
Creating a new iotDevice now routes to detail page of device
fcv-iteratorIt May 17, 2023
cbe4140
Added helper text about autogenerated informations for mqtt
fcv-iteratorIt May 17, 2023
42d58b9
Fixed routing when creating iotDevice
fcv-iteratorIt May 19, 2023
b8f60c3
Ignore id on bulk import to not risk breaking things
fcv-iteratorIt May 19, 2023
a1685d6
Enabled editing of mqtt devices
fcv-iteratorIt May 19, 2023
b16fd8f
Fixed bulk mapping to have validation + error shown when failing
fcv-iteratorIt May 19, 2023
3d52150
Changed error message handling to handle differnet deeper nestings
fcv-iteratorIt May 19, 2023
0255228
Made error check open to all types with children
fcv-iteratorIt May 19, 2023
681fd00
Added info-text to a hover on MQTT subtype
fcv-iteratorIt May 22, 2023
895ad86
Changed to checkboxes instead of radio buttons and made logic so when…
May 22, 2023
7c723e7
Show message when not able to connect to external broker
May 23, 2023
9197d33
Renamed Mqtt device types
fcv-iteratorIt May 25, 2023
ae1d502
Fixed application connection types
fcv-iteratorIt May 25, 2023
a48aace
Added text about CA certificate when making password internal broker
fcv-iteratorIt May 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/app/applications/bulk-import/bulk-import.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import { IoTDeviceService } from '@applications/iot-devices/iot-device.service';
import { faDownload, faTrash } from '@fortawesome/free-solid-svg-icons';
import { TranslateService } from '@ngx-translate/core';
import { OrganizationAccessScope } from '@shared/enums/access-scopes';
import { ErrorMessageService } from '@shared/error-message.service';
import { splitList } from '@shared/helpers/array.helper';
import { Download } from '@shared/helpers/download.helper';
Expand All @@ -20,7 +19,7 @@ import { Papa } from 'ngx-papaparse';
import { Observable, Subject } from 'rxjs';
import { takeWhile } from 'rxjs/operators';
import { BulkImport } from './bulk-import.model';
import { BulkMapping } from './bulkMapping';
import { BulkMapping } from './bulk-mapping';

@Component({
selector: 'app-bulk-import',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export class BulkMapping {
default:
break;
}
//return new IotDevice();
}

private lorawanMapper(data: any, applicationId): IotDevice {
Expand Down Expand Up @@ -53,13 +52,13 @@ export class BulkMapping {
private mqttBrokerMapper(data: any, applicationId: number) {
const newDevice = this.baseMapper(data, applicationId);
newDevice.mqttBrokerSettings = {
authenticationType: data.authenticationType,
caCertificate: undefined,
deviceCertificate: undefined,
deviceCertificateKey: undefined,
mqttPort: undefined,
mqttURL: undefined,
mqtttopicname: undefined,
authenticationType: data.authenticationType,
mqttusername: data.mqttusername,
mqttpassword: data.mqttpassword,
};
Expand All @@ -74,10 +73,10 @@ export class BulkMapping {
caCertificate: this.base64Decode(data.caCertificate),
deviceCertificate: this.base64Decode(data.deviceCertificate),
deviceCertificateKey: this.base64Decode(data.deviceCertificateKey),
mqttPort: data.mqttPort,
mqttPort: data.mqttPort ? Number(data.mqttPort) : undefined,
mqttURL: data.mqttURL,
mqttpassword: data.mqttpassword,
mqtttopicname: data.mqtttopicname,
mqttpassword: data.mqttpassword,
mqttusername: data.mqttusername,
};
newDevice.type = DeviceType.MQTT_SUBSCRIBER;
Expand Down Expand Up @@ -110,7 +109,7 @@ export class BulkMapping {
receivedMessagesMetadata: undefined,
metadata: undefined,
apiKey: undefined,
id: data.id ? data.id : undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that we don't want the id to be set in base scenario?

id: undefined,
createdAt: undefined,
updatedAt: undefined,
applicationId: applicationId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,8 @@ <h3>{{ 'IOTDEVICE.DETAIL' | translate }}</h3>
<mat-divider></mat-divider>
<div class="d-flex align-items-center">
<p class="mr-1"><strong>{{ 'IOT-TABLE.BATTERY' | translate }}</strong></p>
<app-batteri-status *ngIf="device.type === DeviceType.LORAWAN; else noBatteryStatus" [color]="batteryStatusColor"
<app-batteri-status [color]="batteryStatusColor"
[percentage]="batteryStatusPercentage"></app-batteri-status>
<ng-template #noBatteryStatus>
<div>
<p>{{ 'IOTDEVICE-TABLE-ROW.NOT-SUPPORTED-SHORT' | translate }}</p>
</div>
</ng-template>
<ng-template #notAvailable>
<span>{{'IOTDEVICE-TABLE-ROW.NOT-AVAILABLE' | translate}}</span>
</ng-template>
</div>
</ng-template>
<mat-divider></mat-divider>
Expand All @@ -34,7 +26,7 @@ <h3>{{ 'IOTDEVICE.DETAIL' | translate }}</h3>
<ng-container *ngIf="device.type === DeviceType.SIGFOX && device.sigfoxSettings">
<app-iot-device-detail-sigfox [device]="device"></app-iot-device-detail-sigfox>
</ng-container>
<ng-container *ngIf="device.type === DeviceType.GENERIC_HTTP">
<ng-container *ngIf="device.type === DeviceType.GENERIC_HTTP">
<mat-divider></mat-divider>
<p>
<strong>{{ 'IOTDEVICE.GENERIC_HTTP.APIKEY' | translate }}</strong>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
<p><strong>{{ 'IOTDEVICE.MQTT.PORT' | translate }}</strong>{{ device.mqttBrokerSettings.mqttPort }}</p>
<p><strong>{{ 'IOTDEVICE.MQTT.TOPIC_NAME' | translate }}</strong>{{device.mqttBrokerSettings.mqtttopicname}}</p>

<ng-container *ngIf="device.mqttBrokerSettings.authenticationType === AuthenticationType.PASSWORD; else certificate">
<ng-container *ngIf="device.mqttBrokerSettings.authenticationType === AuthenticationType.PASSWORD">
<p><strong>{{ 'QUESTION.MQTT.USERNAME-LABEL' | translate }}</strong>{{ device.mqttBrokerSettings.mqttusername }}</p>
<!-- <p><strong>{{ 'QUESTION.MQTT.PASSWORD-LABEL' | translate }}</strong>{{ device.mqttBrokerSettings.mqttPassword }}</p>-->
</ng-container>
<ng-template #certificate>
<p><strong>{{ 'QUESTION.MQTT.CA-CERTIFICATE' | translate }}</strong>
<button [cdkCopyToClipboard]="device.mqttBrokerSettings.caCertificate" class="btn">{{ 'IOTDEVICE.MQTT.COPY-TO-CLIPBOARD' | translate }}</button>
fcv-iteratorIt marked this conversation as resolved.
Show resolved Hide resolved
<textarea class="form-control" [readOnly]="true">{{ device.mqttBrokerSettings.caCertificate }}</textarea></p>
<button class="btn ml-2" (click)="downloadCaCertificate(device.mqttBrokerSettings.caCertificate, 'ca.crt')">{{ 'IOTDEVICE.MQTT.DOWNLOAD' | translate }}</button>
<textarea class="form-control mt-1" [readOnly]="true">{{ device.mqttBrokerSettings.caCertificate }}</textarea></p>
<ng-container *ngIf="device.mqttBrokerSettings.authenticationType === AuthenticationType.CERTIFICATE">
<p><strong>{{ 'QUESTION.MQTT.DEVICE-CERTIFICATE' | translate }}</strong>
<button [cdkCopyToClipboard]="device.mqttBrokerSettings.deviceCertificate" class="btn">{{ 'IOTDEVICE.MQTT.COPY-TO-CLIPBOARD' | translate }}</button>
<textarea class="form-control" [readOnly]="true">{{ device.mqttBrokerSettings.deviceCertificate }}</textarea>
<button class="btn ml-2" (click)="downloadCaCertificate(device.mqttBrokerSettings.deviceCertificate, device.name +'.crt')">{{ 'IOTDEVICE.MQTT.DOWNLOAD' | translate }}</button>
<textarea class="form-control mt-1" [readOnly]="true">{{ device.mqttBrokerSettings.deviceCertificate }}</textarea>
</p>
<p><strong>{{ 'QUESTION.MQTT.DEVICE-CERTIFICATE-KEY' | translate }}</strong>
<button [cdkCopyToClipboard]="device.mqttBrokerSettings.deviceCertificateKey" class="btn">{{ 'IOTDEVICE.MQTT.COPY-TO-CLIPBOARD' | translate }}</button>
<textarea class="form-control" [readOnly]="true">{{ device.mqttBrokerSettings.deviceCertificateKey }}</textarea>
<button class="btn ml-2" (click)="downloadCaCertificate(device.mqttBrokerSettings.deviceCertificateKey, device.name + '.key')">{{ 'IOTDEVICE.MQTT.DOWNLOAD' | translate }}</button>
<textarea class="form-control mt-1" [readOnly]="true">{{ device.mqttBrokerSettings.deviceCertificateKey }}</textarea>
</p>
</ng-template>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { IotDevice } from '@applications/iot-devices/iot-device.model';
import { AuthenticationType } from '@shared/enums/authentication-type';
import { simpleDownload } from '@shared/helpers/download.helper';

@Component({
selector: 'app-iot-device-details-mqtt-broker',
Expand All @@ -15,4 +16,8 @@ export class IotDeviceDetailsMqttBrokerComponent implements OnInit {
ngOnInit(): void {}

protected readonly AuthenticationType = AuthenticationType;

downloadCaCertificate(caCertificate: string, filename: string) {
simpleDownload(caCertificate, filename);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,35 @@
[ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('type'), 'is-valid' : formFailedSubmit && !errorFields.includes('type')}">
<div class="form-check-inline radio-image">
<label class="form-check-label d-flex flex-column-reverse">
<input attr.aria-label="LoRaWAN" type="radio" name="type" value="LORAWAN" class="form-check-input" required
[(ngModel)]="iotDevice.type" [attr.disabled]="editmode ? '' : null">
<input attr.aria-label="LoRaWAN" type="checkbox" name="LORAWAN" class="form-check-input" required
[attr.disabled]="editmode ? '' : null" (change)="isChecked($event)" [checked]="iotDevice.type.toString().includes('LORAWAN')">
<div class="image-container">
<img src="assets/images/lora.png" alt="LoRaWAN">
</div>
</label>
</div>
<div class="form-check-inline radio-image">
<label class="form-check-label d-flex flex-column-reverse">
<input attr.aria-label="{{'GEN.HTTP' | translate}}" type="radio" name="type" value="GENERIC_HTTP"
class="form-check-input" required [(ngModel)]="iotDevice.type" [attr.disabled]="editmode ? '' : null">
<input attr.aria-label="{{'GEN.HTTP' | translate}}" type="checkbox" name="GENERIC_HTTP"
class="form-check-input" required [attr.disabled]="editmode ? '' : null" (change)="isChecked($event)" [checked]="iotDevice.type.toString().includes('GENERIC_HTTP')">
<div class="image-container">
<app-dynamic-img [altText]="'GEN.HTTP' | translate" [image]="'iot'"></app-dynamic-img>
</div>
</label>
</div>
<div class="form-check-inline radio-image">
<label class="form-check-label d-flex flex-column-reverse">
<input attr.aria-label="MQTT Broker" type="radio" name="type" value="MQTT" required
[checked]="true"
class="form-check-input" [(ngModel)]="iotDevice.type" [attr.disabled]="editmode ? '' : null">
<input attr.aria-label="MQTT" type="checkbox" name="MQTT" required
class="form-check-input" [attr.disabled]="editmode ? '' : null" (change)="isChecked($event)" [checked]="iotDevice.type.toString().includes('MQTT')">
<div class="image-container">
<img src="assets/images/logo_mqtt.png" alt="MQTT">
</div>
</label>
</div>
<div class="form-check-inline radio-image">
<label class="form-check-label d-flex flex-column-reverse">
<input attr.aria-label="Sigfox" type="radio" name="type" value="SIGFOX" class="form-check-input" required
[(ngModel)]="iotDevice.type" [attr.disabled]="editmode ? '' : null">
<input attr.aria-label="Sigfox" type="checkbox" name="SIGFOX" class="form-check-input" required
[attr.disabled]="editmode ? '' : null" (change)="isChecked($event)" [checked]="iotDevice.type.toString().includes('SIGFOX')">
<div class="image-container">
<img src="assets/images/Sigfox_Logo.png" alt="Sigfox">
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy {
public OTAA = true;
metadataTags: { key?: string; value?: string }[] = [];
errorMetadataFieldId: string | undefined;
public console = console;
public deviceSubscription: Subscription;
private applicationsSubscription: Subscription;
private serviceProfilesSubscription: Subscription;
Expand Down Expand Up @@ -129,6 +128,17 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy {
});
}

isChecked(event) {
if (event.target.checked) {
this.iotDevice.type = event.target.name;
} else if (
!event.target.checked &&
this.iotDevice.type.toString().includes(event.target.name)
) {
event.target.checked = true;
}
}

getDevice(id: number): void {
this.deviceSubscription = this.iotDeviceService
.getIoTDevice(id)
Expand Down Expand Up @@ -311,8 +321,14 @@ export class IotDeviceEditComponent implements OnInit, OnDestroy {

postIoTDevice() {
this.iotDeviceService.createIoTDevice(this.iotDevice).subscribe(
() => {
this.router.navigate(['applications/', this.iotDevice.applicationId]);
(response: IotDevice) => {
this.router.navigate([
'applications/' +
this.iotDevice.applicationId +
'/iot-device/' +
response.id +
'/details',
]);
},
(error: HttpErrorResponse) => {
this.handleError(error);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<div class="form-group mt-3 col-12">
<label class="form-label" for="autheticationType">{{'QUESTION.MQTT.AUTHENTICATIONTYPE' | translate}}*</label>
<label class="form-label" for="authenticationType">{{'QUESTION.MQTT.AUTHENTICATIONTYPE' | translate}}*</label>
<select
id="autheticationType" class="form-select" name="autheticationType"
id="authenticationType" class="form-select" name="authenticationType"
[(ngModel)]="settings.authenticationType"
[disabled]="editMode"
[value]="settings.authenticationType"
>
<option *ngFor="let type of AuthenticationType | keyvalue" [value]="type.key">
Expand All @@ -30,7 +29,6 @@
name="username"
[placeholder]="'QUESTION.MQTT.USERNAME-PLACEHOLDER' | translate"
required
[disabled]="editMode"
[(ngModel)]="settings.mqttusername"
[ngClass]="{
'is-invalid': formFailedSubmit && errorFields.includes('mqttusername'),
Expand All @@ -49,15 +47,14 @@
matTooltipHideDelay="2000">
</fa-icon>
<input
[type]="editMode ? 'password' : 'text'"
type="text"
class="form-control"
id="password"
name="password"
[placeholder]="'QUESTION.MQTT.PASSWORD-PLACEHOLDER' | translate"
required
datatype=""
[(ngModel)]="settings.mqttpassword"
[disabled]="editMode"
[ngClass]="{
'is-invalid': formFailedSubmit && errorFields.includes('mqttpassword'),
'is-valid': formFailedSubmit && !errorFields.includes('mqttpassword')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { AuthenticationType } from '@shared/enums/authentication-type';
import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { IotDevice } from '@applications/iot-devices/iot-device.model';
import { MqttSharedSettings } from '@shared/models/mqtt-shared-settings.model';

@Component({
Expand Down
Loading