Merge pull request #13324 from deaflynx/mqtt-protocol-version
Add MQTT version selection for rule nodes
This commit is contained in:
commit
6db26f4663
@ -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;
|
||||
@ -54,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 <b>AT_LEAST_ONCE</b>.",
|
||||
@ -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(
|
||||
@ -201,10 +203,17 @@ public class TbMqttNode extends TbAbstractExternalNode {
|
||||
hasChanges = true;
|
||||
((ObjectNode) oldConfiguration).put(parseToPlainText, false);
|
||||
}
|
||||
case 1:
|
||||
String protocolVersion = "protocolVersion";
|
||||
if (!oldConfiguration.has(protocolVersion)) {
|
||||
hasChanges = true;
|
||||
((ObjectNode) oldConfiguration).put(protocolVersion, MqttVersion.MQTT_3_1.name());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new TbPair<>(hasChanges, oldConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<TbMqttNodeConf
|
||||
private String clientId;
|
||||
private boolean appendClientIdSuffix;
|
||||
private boolean retainedMessage;
|
||||
|
||||
private boolean cleanSession;
|
||||
private boolean ssl;
|
||||
private boolean parseToPlainText;
|
||||
private MqttVersion protocolVersion;
|
||||
private ClientCredentials credentials;
|
||||
|
||||
@Override
|
||||
@ -46,6 +47,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConf
|
||||
configuration.setSsl(false);
|
||||
configuration.setRetainedMessage(false);
|
||||
configuration.setParseToPlainText(false);
|
||||
configuration.setProtocolVersion(MqttVersion.MQTT_3_1_1);
|
||||
configuration.setCredentials(new AnonymousCredentials());
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@ -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 <b>AT_LEAST_ONCE</b>.",
|
||||
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<Boolean, JsonNode> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -49,4 +49,5 @@ public abstract class AbstractRuleNodeUpgradeTest {
|
||||
ObjectNode upgradedConfig = (ObjectNode) upgradeResult.getSecond();
|
||||
assertThat(upgradedConfig).isEqualTo(expectedConfig);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
import io.netty.handler.codec.mqtt.MqttVersion;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.util.concurrent.Future;
|
||||
@ -138,6 +139,7 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest {
|
||||
assertThat(mqttNodeConfig.isCleanSession()).isTrue();
|
||||
assertThat(mqttNodeConfig.isSsl()).isFalse();
|
||||
assertThat(mqttNodeConfig.isParseToPlainText()).isFalse();
|
||||
assertThat(mqttNodeConfig.getProtocolVersion()).isEqualTo(MqttVersion.MQTT_3_1_1);
|
||||
assertThat(mqttNodeConfig.getCredentials()).isInstanceOf(AnonymousCredentials.class);
|
||||
}
|
||||
|
||||
@ -382,20 +384,42 @@ public class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest {
|
||||
then(mqttClientMock).shouldHaveNoInteractions();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void verifyProtocolVersionMapping(MqttVersion expectedVersion) throws Exception {
|
||||
mqttNodeConfig.setProtocolVersion(expectedVersion);
|
||||
|
||||
given(ctxMock.isExternalNodeForceAck()).willReturn(false);
|
||||
mockSuccessfulInit();
|
||||
mqttNode.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(mqttNodeConfig)));
|
||||
|
||||
ArgumentCaptor<MqttClientConfig> configCaptor = ArgumentCaptor.forClass(MqttClientConfig.class);
|
||||
then(mqttNode).should().prepareMqttClientConfig(configCaptor.capture());
|
||||
assertThat(expectedVersion).isEqualTo(configCaptor.getValue().getProtocolVersion());
|
||||
}
|
||||
|
||||
private static Stream<Arguments> verifyProtocolVersionMapping() {
|
||||
return Stream.of(MqttVersion.values()).map(Arguments::of);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() {
|
||||
return Stream.of(
|
||||
// default config for version 0
|
||||
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\"}"),
|
||||
// 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\"}"),
|
||||
// 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\"}",
|
||||
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\"}")
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -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<Arguments> givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() {
|
||||
return Stream.of(
|
||||
// default config for version 0
|
||||
Arguments.of(0,
|
||||
"{\"topicPattern\":\"devices/<device_id>/messages/events/\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"sas\",\"sasKey\":\"sasKey\",\"caCert\":null,\"caCertFileName\":null}}}",
|
||||
true,
|
||||
"{\"topicPattern\":\"devices/<device_id>/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/<device_id>/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/<device_id>/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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
{{ 'rule-node-config.device-id-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<tb-mqtt-version-select formControlName="protocolVersion" subscriptSizing="fixed"></tb-mqtt-version-select>
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel class="tb-mqtt-credentials-panel-group">
|
||||
<mat-expansion-panel-header>
|
||||
|
||||
@ -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]],
|
||||
|
||||
@ -72,6 +72,7 @@
|
||||
{{ 'rule-node-config.parse-to-plain-text' | translate }}
|
||||
</mat-checkbox>
|
||||
<div class="tb-hint">{{ "rule-node-config.parse-to-plain-text-hint" | translate }}</div>
|
||||
<tb-mqtt-version-select formControlName="protocolVersion"></tb-mqtt-version-select>
|
||||
<mat-checkbox formControlName="cleanSession">
|
||||
{{ 'rule-node-config.clean-session' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
@ -52,6 +52,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, []]
|
||||
});
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<mat-form-field class="flex flex-1" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
|
||||
<mat-label translate>device-profile.mqtt-protocol-version</mat-label>
|
||||
<mat-select [required]="required"
|
||||
[disabled]="disabled"
|
||||
[(ngModel)]="modelValue"
|
||||
(ngModelChange)="mqttVersionChanged()">
|
||||
@for (version of mqttVersions; track version) {
|
||||
<mat-option [value]="version">
|
||||
{{ mqttVersionTranslation.get(version) }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
@ -0,0 +1,79 @@
|
||||
///
|
||||
/// 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 { coerceBoolean } from '@shared/decorators/coercion';
|
||||
import { SubscriptSizing, MatFormFieldAppearance } from '@angular/material/form-field';
|
||||
import { MqttVersionTranslation, MqttVersion } from '@shared/models/mqtt.models';
|
||||
|
||||
@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 = Object.values(MqttVersion);
|
||||
mqttVersionTranslation = MqttVersionTranslation;
|
||||
modelValue: MqttVersion;
|
||||
|
||||
@Input()
|
||||
@coerceBoolean()
|
||||
required = false;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
29
ui-ngx/src/app/shared/models/mqtt.models.ts
Normal file
29
ui-ngx/src/app/shared/models/mqtt.models.ts
Normal file
@ -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, string>([
|
||||
[MqttVersion.MQTT_3_1, 'MQTT 3.1'],
|
||||
[MqttVersion.MQTT_3_1_1, 'MQTT 3.1.1'],
|
||||
[MqttVersion.MQTT_5, 'MQTT 5.0']
|
||||
]);
|
||||
@ -227,6 +227,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;
|
||||
@ -439,6 +440,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
||||
HexInputComponent,
|
||||
ScadaSymbolInputComponent,
|
||||
EntityKeyAutocompleteComponent,
|
||||
MqttVersionSelectComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@ -702,6 +704,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
||||
WidgetButtonComponent,
|
||||
ScadaSymbolInputComponent,
|
||||
EntityKeyAutocompleteComponent,
|
||||
MqttVersionSelectComponent,
|
||||
]
|
||||
})
|
||||
export class SharedModule { }
|
||||
|
||||
@ -1919,6 +1919,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: <b>v1/devices/me/attributes/response/$request_id</b>, <b>v1/devices/me/attributes</b>, <b>v1/devices/me/rpc/request/$request_id</b>, <b>v1/devices/me/rpc/response/$request_id</b>. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: <b>v2/a/res/$request_id</b>, <b>v2/a</b>, <b>v2/r/req/$request_id</b>, <b>v2/r/res/$request_id</b>. Where <b>$request_id</b> 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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user