From a445364ce370d7336c01777b8979b7a7ac748d3b Mon Sep 17 00:00:00 2001 From: deaflynx Date: Wed, 7 May 2025 13:23:47 +0300 Subject: [PATCH 01/12] UI: mqtt node add protocol version. --- .../external/mqtt-config.component.html | 10 ++++++++++ .../rule-node/external/mqtt-config.component.ts | 5 +++++ ui-ngx/src/app/shared/models/device.models.ts | 16 +++++++++++++++- .../src/assets/locale/locale.constant-en_US.json | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html index 090fea41f3..1fb41b4548 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html @@ -72,6 +72,16 @@ {{ 'rule-node-config.parse-to-plain-text' | translate }}
{{ "rule-node-config.parse-to-plain-text-hint" | translate }}
+ + device-profile.mqtt-protocol-version + + @for (version of mqttVersions; track version) { + + {{ mqttVersionTranslation.get(version) }} + + } + + {{ 'rule-node-config.clean-session' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts index 00a95e5ce6..3efeb3d61e 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts @@ -18,6 +18,7 @@ import { Component } from '@angular/core'; import { isNotEmptyStr } from '@core/public-api'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; +import { MqttVersions, MqttVersionTranslation } from '@shared/models/device.models'; @Component({ selector: 'tb-external-node-mqtt-config', @@ -28,6 +29,9 @@ export class MqttConfigComponent extends RuleNodeConfigurationComponent { mqttConfigForm: UntypedFormGroup; + mqttVersions = MqttVersions; + mqttVersionTranslation = MqttVersionTranslation; + constructor(private fb: UntypedFormBuilder) { super(); } @@ -52,6 +56,7 @@ export class MqttConfigComponent extends RuleNodeConfigurationComponent { cleanSession: [configuration ? configuration.cleanSession : false, []], retainedMessage: [configuration ? configuration.retainedMessage : false, []], ssl: [configuration ? configuration.ssl : false, []], + protocolVersion: [configuration ? configuration.protocolVersion : null, []], credentials: [configuration ? configuration.credentials : null, []] }); } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 8298d3a1fe..d0bbdd9b0f 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -36,7 +36,7 @@ import { PowerMode } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; import { PageLink } from '@shared/models/page/page-link'; -import { isDefinedAndNotNull, isNotEmptyStr } from '@core/utils'; +import { isDefinedAndNotNull, isNotEmptyStr, isNumber } from '@core/utils'; import { EdgeId } from '@shared/models/id/edge-id'; export enum DeviceProfileType { @@ -902,3 +902,17 @@ export const getAlarmScheduleRangeText = (startsOn: Date | number, endsOn: Date return `12:00 AM – ${end.format('hh:mm A')}` + ` and ${start.format('hh:mm A')} – 12:00 PM`; }; + +export enum MqttVersion { + MQTT_3_1 = 3, + MQTT_3_1_1 = 4, + MQTT_5 = 5 +} + +export const MqttVersions = Object.values(MqttVersion).filter(v => isNumber(v)) as MqttVersion[]; + +export const MqttVersionTranslation = new Map([ + [MqttVersion.MQTT_3_1, 'MQTT 3.1'], + [MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'], + [MqttVersion.MQTT_5, 'MQTT 5.0'] +]); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 72afcfc0b9..21f430c1ba 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1914,6 +1914,7 @@ "mqtt-use-json-format-for-default-downlink-topics-hint": "When enabled, the platform will use Json payload format to push attributes and RPC via the following topics: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Where $request_id is an integer request identifier.", "mqtt-send-ack-on-validation-exception": "Send PUBACK on PUBLISH message validation failure", "mqtt-send-ack-on-validation-exception-hint": "By default, the platform will close the MQTT session on message validation failure. When enabled, the platform will send publish acknowledgment instead of closing the session.", + "mqtt-protocol-version": "Protocol version", "snmp-add-mapping": "Add SNMP mapping", "snmp-mapping-not-configured": "No mapping for OID to time series/telemetry configured", "snmp-timseries-or-attribute-name": "Time series/attribute name for mapping", From e237be0fb2d4fda4b75c9738b87e20ed2c98e3c4 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Fri, 9 May 2025 10:55:31 +0300 Subject: [PATCH 02/12] TbMqttNode: add protocolVersion config --- .../rule/engine/mqtt/TbMqttNode.java | 10 +++++++ .../engine/mqtt/TbMqttNodeConfiguration.java | 4 ++- .../rule/engine/mqtt/TbMqttNodeTest.java | 28 +++++++++++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 28a9e1ff4b..6de6e1ae5d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.buffer.Unpooled; import io.netty.handler.codec.mqtt.MqttQoS; +import io.netty.handler.codec.mqtt.MqttVersion; import io.netty.handler.ssl.SslContext; import io.netty.util.concurrent.Promise; import lombok.extern.slf4j.Slf4j; @@ -126,6 +127,7 @@ public class TbMqttNode extends TbAbstractExternalNode { config.setClientId(getClientId(ctx)); } config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); + config.setProtocolVersion(this.mqttNodeConfiguration.getProtocolVersion()); MqttClientSettings mqttClientSettings = ctx.getMqttClientSettings(); config.setRetransmissionConfig(new MqttClientConfig.RetransmissionConfig( @@ -202,9 +204,17 @@ public class TbMqttNode extends TbAbstractExternalNode { ((ObjectNode) oldConfiguration).put(parseToPlainText, false); } break; + case 1: + String protocolVersion = "protocolVersion"; + if (!oldConfiguration.has(protocolVersion)) { + hasChanges = true; + ((ObjectNode) oldConfiguration).put(protocolVersion, MqttVersion.MQTT_3_1_1.name()); + } + break; default: break; } return new TbPair<>(hasChanges, oldConfiguration); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index faa465193a..8bbe920277 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.mqtt; +import io.netty.handler.codec.mqtt.MqttVersion; import lombok.Data; import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.credentials.AnonymousCredentials; @@ -30,10 +31,10 @@ public class TbMqttNodeConfiguration implements NodeConfiguration configCaptor = ArgumentCaptor.forClass(MqttClientConfig.class); + then(mqttNode).should().prepareMqttClientConfig(configCaptor.capture()); + assertThat(expectedVersion).isEqualTo(configCaptor.getValue().getProtocolVersion()); + } + + private static Stream verifyProtocolVersionMapping() { + return Stream.of(MqttVersion.values()).map(Arguments::of); + } + private static Stream givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() { return Stream.of( // default config for version 0 @@ -391,10 +411,14 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { // default config for version 1 with upgrade from version 0 Arguments.of(1, "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}", + true, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}"), + // default config for version 2 with upgrade from version 1 + Arguments.of(2, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}", false, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}") + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}") ); - } @Override From 610806487d4592d0fc164f67fcce9b85bb2de17d Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 9 May 2025 11:25:17 +0300 Subject: [PATCH 03/12] UI: update MqttVersion enum. --- ui-ngx/src/app/shared/models/device.models.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index d0bbdd9b0f..01e29dfe10 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -36,7 +36,7 @@ import { PowerMode } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models'; import { PageLink } from '@shared/models/page/page-link'; -import { isDefinedAndNotNull, isNotEmptyStr, isNumber } from '@core/utils'; +import { isDefinedAndNotNull, isNotEmptyStr } from '@core/utils'; import { EdgeId } from '@shared/models/id/edge-id'; export enum DeviceProfileType { @@ -904,12 +904,12 @@ export const getAlarmScheduleRangeText = (startsOn: Date | number, endsOn: Date }; export enum MqttVersion { - MQTT_3_1 = 3, - MQTT_3_1_1 = 4, - MQTT_5 = 5 + MQTT_3_1 = 'MQTT_3_1', + MQTT_3_1_1 = 'MQTT_3_1_1', + MQTT_5 = 'MQTT_5' } -export const MqttVersions = Object.values(MqttVersion).filter(v => isNumber(v)) as MqttVersion[]; +export const MqttVersions = Object.values(MqttVersion); export const MqttVersionTranslation = new Map([ [MqttVersion.MQTT_3_1, 'MQTT 3.1'], From c945e47732cba2468dd122bf2d0b44118517733d Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 9 May 2025 12:32:30 +0300 Subject: [PATCH 04/12] UI: mqtt version select refactor as component. --- .../external/mqtt-config.component.html | 11 +-- .../external/mqtt-config.component.ts | 4 - .../mqtt-version-select.component.html | 30 +++++++ .../mqtt-version-select.component.ts | 84 +++++++++++++++++++ ui-ngx/src/app/shared/shared.module.ts | 3 + 5 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/mqtt-version-select.component.html create mode 100644 ui-ngx/src/app/shared/components/mqtt-version-select.component.ts diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html index 1fb41b4548..60adadd6bb 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.html @@ -72,16 +72,7 @@ {{ 'rule-node-config.parse-to-plain-text' | translate }}
{{ "rule-node-config.parse-to-plain-text-hint" | translate }}
- - device-profile.mqtt-protocol-version - - @for (version of mqttVersions; track version) { - - {{ mqttVersionTranslation.get(version) }} - - } - - + {{ 'rule-node-config.clean-session' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts index 3efeb3d61e..08c8e284a9 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/mqtt-config.component.ts @@ -18,7 +18,6 @@ import { Component } from '@angular/core'; import { isNotEmptyStr } from '@core/public-api'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; -import { MqttVersions, MqttVersionTranslation } from '@shared/models/device.models'; @Component({ selector: 'tb-external-node-mqtt-config', @@ -29,9 +28,6 @@ export class MqttConfigComponent extends RuleNodeConfigurationComponent { mqttConfigForm: UntypedFormGroup; - mqttVersions = MqttVersions; - mqttVersionTranslation = MqttVersionTranslation; - constructor(private fb: UntypedFormBuilder) { super(); } diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.html b/ui-ngx/src/app/shared/components/mqtt-version-select.component.html new file mode 100644 index 0000000000..81029a3445 --- /dev/null +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.html @@ -0,0 +1,30 @@ + + + device-profile.mqtt-protocol-version + + @for (version of mqttVersions; track version) { + + {{ mqttVersionTranslation.get(version) }} + + } + + diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts new file mode 100644 index 0000000000..4003925e60 --- /dev/null +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts @@ -0,0 +1,84 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { MqttVersion, MqttVersions, MqttVersionTranslation } from '@shared/models/device.models'; +import { SubscriptSizing, MatFormFieldAppearance } from '@angular/material/form-field'; + +@Component({ + selector: 'tb-mqtt-version-select', + templateUrl: './mqtt-version-select.component.html', + styleUrls: [], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttVersionSelectComponent), + multi: true + }] +}) +export class MqttVersionSelectComponent implements ControlValueAccessor { + + @Input() + disabled: boolean; + + @Input() + subscriptSizing: SubscriptSizing = 'dynamic'; + + @Input() + appearance: MatFormFieldAppearance = 'fill'; + + mqttVersions = MqttVersions; + mqttVersionTranslation = MqttVersionTranslation; + modelValue: MqttVersion; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + private propagateChange = (v: any) => { }; + + constructor() { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: MqttVersion | null): void { + this.modelValue = value; + } + + mqttVersionChanged() { + this.updateView(); + } + + private updateView() { + this.propagateChange(this.modelValue); + } +} diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 8eec19379e..68786dca77 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -226,6 +226,7 @@ import { JsFuncModulesComponent } from '@shared/components/js-func-modules.compo import { JsFuncModuleRowComponent } from '@shared/components/js-func-module-row.component'; import { EntityKeyAutocompleteComponent } from '@shared/components/entity/entity-key-autocomplete.component'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; +import { MqttVersionSelectComponent } from '@shared/components/mqtt-version-select.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -437,6 +438,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) HexInputComponent, ScadaSymbolInputComponent, EntityKeyAutocompleteComponent, + MqttVersionSelectComponent, ], imports: [ CommonModule, @@ -700,6 +702,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetButtonComponent, ScadaSymbolInputComponent, EntityKeyAutocompleteComponent, + MqttVersionSelectComponent, ] }) export class SharedModule { } From 2c1f55f55ae14d9084b4acc882e8b174012ee944 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 9 May 2025 13:04:36 +0300 Subject: [PATCH 05/12] UI: mqtt version refactoring. --- .../components/mqtt-version-select.component.ts | 17 +++++++++++++++-- ui-ngx/src/app/shared/models/device.models.ts | 14 -------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts index 4003925e60..2d88b220c6 100644 --- a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts @@ -17,9 +17,22 @@ import { Component, forwardRef, Input } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { MqttVersion, MqttVersions, MqttVersionTranslation } from '@shared/models/device.models'; import { SubscriptSizing, MatFormFieldAppearance } from '@angular/material/form-field'; +export enum MqttVersion { + MQTT_3_1 = 'MQTT_3_1', + MQTT_3_1_1 = 'MQTT_3_1_1', + MQTT_5 = 'MQTT_5' +} + +export const DEFAULT_MQTT_VERSION = MqttVersion.MQTT_3_1_1; + +export const MqttVersionTranslation = new Map([ + [MqttVersion.MQTT_3_1, 'MQTT 3.1'], + [MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'], + [MqttVersion.MQTT_5, 'MQTT 5.0'] +]); + @Component({ selector: 'tb-mqtt-version-select', templateUrl: './mqtt-version-select.component.html', @@ -41,7 +54,7 @@ export class MqttVersionSelectComponent implements ControlValueAccessor { @Input() appearance: MatFormFieldAppearance = 'fill'; - mqttVersions = MqttVersions; + mqttVersions = Object.values(MqttVersion); mqttVersionTranslation = MqttVersionTranslation; modelValue: MqttVersion; diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 01e29dfe10..8298d3a1fe 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -902,17 +902,3 @@ export const getAlarmScheduleRangeText = (startsOn: Date | number, endsOn: Date return `12:00 AM – ${end.format('hh:mm A')}` + ` and ${start.format('hh:mm A')} – 12:00 PM`; }; - -export enum MqttVersion { - MQTT_3_1 = 'MQTT_3_1', - MQTT_3_1_1 = 'MQTT_3_1_1', - MQTT_5 = 'MQTT_5' -} - -export const MqttVersions = Object.values(MqttVersion); - -export const MqttVersionTranslation = new Map([ - [MqttVersion.MQTT_3_1, 'MQTT 3.1'], - [MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'], - [MqttVersion.MQTT_5, 'MQTT 5.0'] -]); From 1af417dfd52f4e05d191199a854ae9bb5b79eba1 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Fri, 9 May 2025 13:38:44 +0300 Subject: [PATCH 06/12] Remove break for TbMqttNode upgrade --- .../main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 6de6e1ae5d..c9c1f9f3f0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -203,7 +203,6 @@ public class TbMqttNode extends TbAbstractExternalNode { hasChanges = true; ((ObjectNode) oldConfiguration).put(parseToPlainText, false); } - break; case 1: String protocolVersion = "protocolVersion"; if (!oldConfiguration.has(protocolVersion)) { From 564baea894335f866ad9238f8a90feda1dca9682 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Mon, 12 May 2025 12:42:12 +0300 Subject: [PATCH 07/12] Update TbMqttNodeTest --- .../java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java index a03a05ce14..55ce8bf53e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java @@ -407,7 +407,7 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { Arguments.of(0, "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"}}", true, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}"), + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}"), // default config for version 1 with upgrade from version 0 Arguments.of(1, "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}", From 73044bb1f2dd86e308277d272679e4ebddee57d5 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Mon, 12 May 2025 14:57:09 +0300 Subject: [PATCH 08/12] mqtt version refactor models, add to node 'azure iot hub'. --- .../azure-iot-hub-config.component.html | 1 + .../azure-iot-hub-config.component.ts | 1 + .../mqtt-version-select.component.ts | 15 +--------- ui-ngx/src/app/shared/models/mqtt.models.ts | 29 +++++++++++++++++++ 4 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 ui-ngx/src/app/shared/models/mqtt.models.ts diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.html b/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.html index ee9c46d8c1..79c4a2f00d 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.html @@ -38,6 +38,7 @@ {{ 'rule-node-config.device-id-required' | translate }} + diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.ts index 7c96131fef..7dd934ccd9 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/azure-iot-hub-config.component.ts @@ -53,6 +53,7 @@ export class AzureIotHubConfigComponent extends RuleNodeConfigurationComponent { clientId: [configuration ? configuration.clientId : null, [Validators.required]], cleanSession: [configuration ? configuration.cleanSession : false, []], ssl: [configuration ? configuration.ssl : false, []], + protocolVersion: [configuration ? configuration.protocolVersion : null, []], credentials: this.fb.group( { type: [configuration && configuration.credentials ? configuration.credentials.type : null, [Validators.required]], diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts index 2d88b220c6..277995cba0 100644 --- a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts @@ -18,20 +18,7 @@ import { Component, forwardRef, Input } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { SubscriptSizing, MatFormFieldAppearance } from '@angular/material/form-field'; - -export enum MqttVersion { - MQTT_3_1 = 'MQTT_3_1', - MQTT_3_1_1 = 'MQTT_3_1_1', - MQTT_5 = 'MQTT_5' -} - -export const DEFAULT_MQTT_VERSION = MqttVersion.MQTT_3_1_1; - -export const MqttVersionTranslation = new Map([ - [MqttVersion.MQTT_3_1, 'MQTT 3.1'], - [MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'], - [MqttVersion.MQTT_5, 'MQTT 5.0'] -]); +import { MqttVersionTranslation, MqttVersion } from '@shared/models/mqtt.models'; @Component({ selector: 'tb-mqtt-version-select', diff --git a/ui-ngx/src/app/shared/models/mqtt.models.ts b/ui-ngx/src/app/shared/models/mqtt.models.ts new file mode 100644 index 0000000000..2bd40f3681 --- /dev/null +++ b/ui-ngx/src/app/shared/models/mqtt.models.ts @@ -0,0 +1,29 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export enum MqttVersion { + MQTT_3_1 = 'MQTT_3_1', + MQTT_3_1_1 = 'MQTT_3_1_1', + MQTT_5 = 'MQTT_5' +} + +export const DEFAULT_MQTT_VERSION = MqttVersion.MQTT_3_1_1; + +export const MqttVersionTranslation = new Map([ + [MqttVersion.MQTT_3_1, 'MQTT 3.1'], + [MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'], + [MqttVersion.MQTT_5, 'MQTT 5.0'] +]); From f8932da09a07c9e5719b1fc309019982be6a934c Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Mon, 12 May 2025 15:01:06 +0300 Subject: [PATCH 09/12] Add config for AzureNode --- .../rule/engine/mqtt/TbMqttNode.java | 2 +- .../engine/mqtt/azure/TbAzureIotHubNode.java | 24 ++++++++++++++- .../azure/TbAzureIotHubNodeConfiguration.java | 2 ++ .../engine/AbstractRuleNodeUpgradeTest.java | 1 + .../mqtt/azure/TbAzureIotHubNodeTest.java | 29 +++++++++++++++++-- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index c9c1f9f3f0..2cd26e667d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -55,7 +55,7 @@ import java.util.concurrent.TimeoutException; type = ComponentType.EXTERNAL, name = "mqtt", configClazz = TbMqttNodeConfiguration.class, - version = 1, + version = 2, clusteringMode = ComponentClusteringMode.USER_PREFERENCE, nodeDescription = "Publish messages to the MQTT broker", nodeDetails = "Will publish message payload to the MQTT broker with QoS AT_LEAST_ONCE.", diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java index b103cf77fc..2ea56ce799 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java @@ -15,6 +15,8 @@ */ package org.thingsboard.rule.engine.mqtt.azure; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.handler.codec.mqtt.MqttVersion; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.AzureIotHubUtil; @@ -32,18 +34,21 @@ import org.thingsboard.rule.engine.mqtt.TbMqttNode; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; import org.thingsboard.server.common.data.plugin.ComponentClusteringMode; import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.data.util.TbPair; @Slf4j @RuleNode( type = ComponentType.EXTERNAL, name = "azure iot hub", configClazz = TbAzureIotHubNodeConfiguration.class, + version = 1, clusteringMode = ComponentClusteringMode.SINGLETON, nodeDescription = "Publish messages to the Azure IoT Hub", nodeDetails = "Will publish message payload to the Azure IoT Hub with QoS AT_LEAST_ONCE.", configDirective = "tbExternalNodeAzureIotHubConfig" ) public class TbAzureIotHubNode extends TbMqttNode { + @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { super.init(ctx); @@ -65,7 +70,6 @@ public class TbAzureIotHubNode extends TbMqttNode { } protected void prepareMqttClientConfig(MqttClientConfig config) { - config.setProtocolVersion(MqttVersion.MQTT_3_1_1); config.setUsername(AzureIotHubUtil.buildUsername(mqttNodeConfiguration.getHost(), config.getClientId())); ClientCredentials credentials = mqttNodeConfiguration.getCredentials(); if (CredentialsType.SAS == credentials.getType()) { @@ -76,4 +80,22 @@ public class TbAzureIotHubNode extends TbMqttNode { MqttClient initAzureClient(TbContext ctx) throws Exception { return initClient(ctx); } + + @Override + public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { + boolean hasChanges = false; + switch (fromVersion) { + case 0: + String protocolVersion = "protocolVersion"; + if (!oldConfiguration.has(protocolVersion)) { + hasChanges = true; + ((ObjectNode) oldConfiguration).put(protocolVersion, MqttVersion.MQTT_3_1_1.name()); + } + break; + default: + break; + } + return new TbPair<>(hasChanges, oldConfiguration); + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java index 2c48c193f0..64d839dc52 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeConfiguration.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.mqtt.azure; +import io.netty.handler.codec.mqtt.MqttVersion; import lombok.Data; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; @@ -30,6 +31,7 @@ public class TbAzureIotHubNodeConfiguration extends TbMqttNodeConfiguration { configuration.setConnectTimeoutSec(10); configuration.setCleanSession(true); configuration.setSsl(true); + configuration.setProtocolVersion(MqttVersion.MQTT_3_1_1); configuration.setCredentials(new AzureIotHubSasCredentials()); return configuration; } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/AbstractRuleNodeUpgradeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/AbstractRuleNodeUpgradeTest.java index 6554c7da01..60cb339bcc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/AbstractRuleNodeUpgradeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/AbstractRuleNodeUpgradeTest.java @@ -49,4 +49,5 @@ public abstract class AbstractRuleNodeUpgradeTest { ObjectNode upgradedConfig = (ObjectNode) upgradeResult.getSecond(); assertThat(upgradedConfig).isEqualTo(expectedConfig); } + } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeTest.java index 441d75b2d4..433d5d4673 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNodeTest.java @@ -19,6 +19,7 @@ import io.netty.handler.codec.mqtt.MqttVersion; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.provider.Arguments; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; @@ -26,11 +27,15 @@ import org.thingsboard.common.util.AzureIotHubUtil; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; +import org.thingsboard.rule.engine.AbstractRuleNodeUpgradeTest; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.credentials.CertPemCredentials; import org.thingsboard.rule.engine.mqtt.TbMqttNodeConfiguration; +import java.util.stream.Stream; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.ArgumentMatchers.any; @@ -38,7 +43,7 @@ import static org.mockito.BDDMockito.spy; import static org.mockito.BDDMockito.willReturn; @ExtendWith(MockitoExtension.class) -public class TbAzureIotHubNodeTest { +public class TbAzureIotHubNodeTest extends AbstractRuleNodeUpgradeTest { private TbAzureIotHubNode azureIotHubNode; private TbAzureIotHubNodeConfiguration azureIotHubNodeConfig; @@ -66,6 +71,7 @@ public class TbAzureIotHubNodeTest { assertThat(azureIotHubNodeConfig.isCleanSession()).isTrue(); assertThat(azureIotHubNodeConfig.isSsl()).isTrue(); assertThat(azureIotHubNodeConfig.isParseToPlainText()).isFalse(); + assertThat(azureIotHubNodeConfig.getProtocolVersion()).isEqualTo(MqttVersion.MQTT_3_1_1); assertThat(azureIotHubNodeConfig.getCredentials()).isInstanceOf(AzureIotHubSasCredentials.class); } @@ -82,7 +88,6 @@ public class TbAzureIotHubNodeTest { MqttClientConfig mqttClientConfig = new MqttClientConfig(); azureIotHubNode.prepareMqttClientConfig(mqttClientConfig); - assertThat(mqttClientConfig.getProtocolVersion()).isEqualTo(MqttVersion.MQTT_3_1_1); assertThat(mqttClientConfig.getUsername()).isEqualTo(AzureIotHubUtil.buildUsername(azureIotHubNodeConfig.getHost(), mqttClientConfig.getClientId())); assertThat(mqttClientConfig.getPassword()).isEqualTo(AzureIotHubUtil.buildSasToken(azureIotHubNodeConfig.getHost(), credentials.getSasKey())); } @@ -105,4 +110,24 @@ public class TbAzureIotHubNodeTest { assertThat(mqttNodeConfiguration.isCleanSession()).isTrue(); } + private static Stream givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() { + return Stream.of( + // default config for version 0 + Arguments.of(0, + "{\"topicPattern\":\"devices//messages/events/\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"sas\",\"sasKey\":\"sasKey\",\"caCert\":null,\"caCertFileName\":null}}}", + true, + "{\"topicPattern\":\"devices//messages/events/\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"sas\",\"sasKey\":\"sasKey\",\"caCert\":null,\"caCertFileName\":null}, \"protocolVersion\":\"MQTT_3_1_1\"}\"}"), + // default config for version 1 with upgrade from version 0 + Arguments.of(1, + "{\"topicPattern\":\"devices//messages/events/\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"sas\",\"sasKey\":\"sasKey\",\"caCert\":null,\"caCertFileName\":null}, \"protocolVersion\":\"MQTT_3_1_1\"}\"}", + false, + "{\"topicPattern\":\"devices//messages/events/\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"sas\",\"sasKey\":\"sasKey\",\"caCert\":null,\"caCertFileName\":null}, \"protocolVersion\":\"MQTT_3_1_1\"}\"}") + ); + } + + @Override + protected TbNode getTestNode() { + return azureIotHubNode; + } + } From 59bba4508db8346b22bda5c4bc1297c8fadc3630 Mon Sep 17 00:00:00 2001 From: Artem Babak Date: Tue, 13 May 2025 09:35:00 +0300 Subject: [PATCH 10/12] Minor update mqtt-version-select Co-authored-by: Vladyslav Prykhodko --- .../shared/components/mqtt-version-select.component.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts index 277995cba0..5c427fb536 100644 --- a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts @@ -45,14 +45,9 @@ export class MqttVersionSelectComponent implements ControlValueAccessor { mqttVersionTranslation = MqttVersionTranslation; modelValue: MqttVersion; - private requiredValue: boolean; - get required(): boolean { - return this.requiredValue; - } @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } + @coerceBoolean() + required = false; private propagateChange = (v: any) => { }; From 2a35824d3c345c13f4230add7aa873f7fea1bdf4 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Tue, 13 May 2025 09:50:05 +0300 Subject: [PATCH 11/12] fix mqtt version import --- .../src/app/shared/components/mqtt-version-select.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts index 5c427fb536..6bde856a7b 100644 --- a/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts +++ b/ui-ngx/src/app/shared/components/mqtt-version-select.component.ts @@ -16,7 +16,7 @@ import { Component, forwardRef, Input } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { coerceBoolean } from '@shared/decorators/coercion'; import { SubscriptSizing, MatFormFieldAppearance } from '@angular/material/form-field'; import { MqttVersionTranslation, MqttVersion } from '@shared/models/mqtt.models'; From e2e638f51ddbb1531ab3752e4d9f5eebef6f80fe Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Tue, 13 May 2025 11:24:11 +0300 Subject: [PATCH 12/12] Change update version to 3.1 for MqttNode --- .../java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java | 2 +- .../org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 2cd26e667d..694fed1bf8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -207,7 +207,7 @@ public class TbMqttNode extends TbAbstractExternalNode { String protocolVersion = "protocolVersion"; if (!oldConfiguration.has(protocolVersion)) { hasChanges = true; - ((ObjectNode) oldConfiguration).put(protocolVersion, MqttVersion.MQTT_3_1_1.name()); + ((ObjectNode) oldConfiguration).put(protocolVersion, MqttVersion.MQTT_3_1.name()); } break; default: diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java index 55ce8bf53e..b67aef00f0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java @@ -407,17 +407,17 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { Arguments.of(0, "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"}}", true, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}"), + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1\"}"), // default config for version 1 with upgrade from version 0 Arguments.of(1, "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}", true, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}"), + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1\"}"), // default config for version 2 with upgrade from version 1 Arguments.of(2, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}", + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1\"}", false, - "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1_1\"}") + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false, \"protocolVersion\":\"MQTT_3_1\"}") ); }