From 188ffb112bd727ac6705af6002193e2266eb2e40 Mon Sep 17 00:00:00 2001
From: Kevin BEAUGRAND <9513635+kbeaugrand@users.noreply.github.com>
Date: Tue, 27 Sep 2022 12:54:33 +0200
Subject: [PATCH] Fix #1289 - Add ClassType to device twin configuration for
loraWAN (#1290)
---
... for ClassType in device model.Designer.cs | 351 ++++++++++++++++++
...d support for ClassType in device model.cs | 30 ++
.../PortalDbContextModelSnapshot.cs | 3 +
.../Mappers/LoRaDeviceModelMapperTests.cs | 2 +-
.../Server/Mappers/LoRaDeviceModelMapper.cs | 2 +
.../Entities/DeviceModel.cs | 2 +
6 files changed, 389 insertions(+), 1 deletion(-)
create mode 100644 src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.Designer.cs
create mode 100644 src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.cs
diff --git a/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.Designer.cs b/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.Designer.cs
new file mode 100644
index 000000000..209f723dc
--- /dev/null
+++ b/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.Designer.cs
@@ -0,0 +1,351 @@
+//
+using System;
+using AzureIoTHub.Portal.Infrastructure;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace AzureIoTHub.Portal.Infrastructure.Migrations
+{
+ [DbContext(typeof(PortalDbContext))]
+ [Migration("20220927114351_Add support for ClassType in device model")]
+ partial class AddsupportforClassTypeindevicemodel
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "6.0.9")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.Device", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("DeviceModelId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsConnected")
+ .HasColumnType("boolean");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("StatusUpdatedTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Tags")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Version")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("Devices");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModel", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ABPRelaxMode")
+ .HasColumnType("boolean");
+
+ b.Property("AppEUI")
+ .HasColumnType("text");
+
+ b.Property("ClassType")
+ .HasColumnType("integer");
+
+ b.Property("Deduplication")
+ .HasColumnType("integer");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Downlink")
+ .HasColumnType("boolean");
+
+ b.Property("IsBuiltin")
+ .HasColumnType("boolean");
+
+ b.Property("KeepAliveTimeout")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PreferredWindow")
+ .HasColumnType("integer");
+
+ b.Property("RXDelay")
+ .HasColumnType("integer");
+
+ b.Property("SensorDecoder")
+ .HasColumnType("text");
+
+ b.Property("SupportLoRaFeatures")
+ .HasColumnType("boolean");
+
+ b.Property("UseOTAA")
+ .HasColumnType("boolean");
+
+ b.HasKey("Id");
+
+ b.ToTable("DeviceModels");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModelCommand", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("Confirmed")
+ .HasColumnType("boolean");
+
+ b.Property("DeviceModelId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Frame")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsBuiltin")
+ .HasColumnType("boolean");
+
+ b.Property("Port")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("DeviceModelCommands");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceModelProperty", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsWritable")
+ .HasColumnType("boolean");
+
+ b.Property("ModelId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Order")
+ .HasColumnType("integer");
+
+ b.Property("PropertyType")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("DeviceModelProperties");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.DeviceTag", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("Label")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Required")
+ .HasColumnType("boolean");
+
+ b.Property("Searchable")
+ .HasColumnType("boolean");
+
+ b.HasKey("Id");
+
+ b.ToTable("DeviceTags");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModel", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("EdgeDeviceModels");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.EdgeDeviceModelCommand", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("EdgeDeviceModelId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModuleName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("EdgeDeviceModelCommands");
+ });
+
+ modelBuilder.Entity("AzureIoTHub.Portal.Domain.Entities.LorawanDevice", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ABPRelaxMode")
+ .HasColumnType("boolean");
+
+ b.Property("AlreadyLoggedInOnce")
+ .HasColumnType("boolean");
+
+ b.Property("AppEUI")
+ .HasColumnType("text");
+
+ b.Property("AppKey")
+ .HasColumnType("text");
+
+ b.Property("AppSKey")
+ .HasColumnType("text");
+
+ b.Property("ClassType")
+ .HasColumnType("integer");
+
+ b.Property("DataRate")
+ .HasColumnType("text");
+
+ b.Property("Deduplication")
+ .HasColumnType("integer");
+
+ b.Property("DevAddr")
+ .HasColumnType("text");
+
+ b.Property("DeviceModelId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Downlink")
+ .HasColumnType("boolean");
+
+ b.Property("FCntDownStart")
+ .HasColumnType("integer");
+
+ b.Property("FCntResetCounter")
+ .HasColumnType("integer");
+
+ b.Property("FCntUpStart")
+ .HasColumnType("integer");
+
+ b.Property("GatewayID")
+ .HasColumnType("text");
+
+ b.Property("IsConnected")
+ .HasColumnType("boolean");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("KeepAliveTimeout")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("NbRep")
+ .HasColumnType("text");
+
+ b.Property("NwkSKey")
+ .HasColumnType("text");
+
+ b.Property("PreferredWindow")
+ .HasColumnType("integer");
+
+ b.Property("RX1DROffset")
+ .HasColumnType("integer");
+
+ b.Property("RX2DataRate")
+ .HasColumnType("integer");
+
+ b.Property("RXDelay")
+ .HasColumnType("integer");
+
+ b.Property("ReportedRX1DROffset")
+ .HasColumnType("text");
+
+ b.Property("ReportedRX2DataRate")
+ .HasColumnType("text");
+
+ b.Property("ReportedRXDelay")
+ .HasColumnType("text");
+
+ b.Property("SensorDecoder")
+ .HasColumnType("text");
+
+ b.Property("StatusUpdatedTime")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Supports32BitFCnt")
+ .HasColumnType("boolean");
+
+ b.Property("Tags")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TxPower")
+ .HasColumnType("text");
+
+ b.Property("UseOTAA")
+ .HasColumnType("boolean");
+
+ b.Property("Version")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("LorawanDevices");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.cs b/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.cs
new file mode 100644
index 000000000..b0606425a
--- /dev/null
+++ b/src/AzureIoTHub.Portal.Infrastructure/Migrations/20220927114351_Add support for ClassType in device model.cs
@@ -0,0 +1,30 @@
+// Copyright (c) CGI France. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#nullable disable
+
+namespace AzureIoTHub.Portal.Infrastructure.Migrations
+{
+ using AzureIoTHub.Portal.Models.v10.LoRaWAN;
+ using Microsoft.EntityFrameworkCore.Migrations;
+
+ public partial class AddsupportforClassTypeindevicemodel : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ _ = migrationBuilder.AddColumn(
+ name: "ClassType",
+ table: "DeviceModels",
+ type: "integer",
+ nullable: false,
+ defaultValue: ClassType.A);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ _ = migrationBuilder.DropColumn(
+ name: "ClassType",
+ table: "DeviceModels");
+ }
+ }
+}
diff --git a/src/AzureIoTHub.Portal.Infrastructure/Migrations/PortalDbContextModelSnapshot.cs b/src/AzureIoTHub.Portal.Infrastructure/Migrations/PortalDbContextModelSnapshot.cs
index b80b1060f..ca2eac845 100644
--- a/src/AzureIoTHub.Portal.Infrastructure/Migrations/PortalDbContextModelSnapshot.cs
+++ b/src/AzureIoTHub.Portal.Infrastructure/Migrations/PortalDbContextModelSnapshot.cs
@@ -67,6 +67,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("AppEUI")
.HasColumnType("text");
+ b.Property("ClassType")
+ .HasColumnType("integer");
+
b.Property("Deduplication")
.HasColumnType("integer");
diff --git a/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/LoRaDeviceModelMapperTests.cs b/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/LoRaDeviceModelMapperTests.cs
index f993fad54..c33ce626d 100644
--- a/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/LoRaDeviceModelMapperTests.cs
+++ b/src/AzureIoTHub.Portal.Tests.Unit/Server/Mappers/LoRaDeviceModelMapperTests.cs
@@ -123,7 +123,7 @@ public void UpdateTableEntityStateUnderTestExpectedBehavior(bool isBuiltin)
var result = loRaDeviceModelMapper.BuildDeviceModelDesiredProperties(model);
// Assert
- _ = result.Keys.Count.Should().Be(13);
+ _ = result.Keys.Count.Should().Be(14);
this.mockRepository.VerifyAll();
}
diff --git a/src/AzureIoTHub.Portal/Server/Mappers/LoRaDeviceModelMapper.cs b/src/AzureIoTHub.Portal/Server/Mappers/LoRaDeviceModelMapper.cs
index 664611916..8e3201b24 100644
--- a/src/AzureIoTHub.Portal/Server/Mappers/LoRaDeviceModelMapper.cs
+++ b/src/AzureIoTHub.Portal/Server/Mappers/LoRaDeviceModelMapper.cs
@@ -47,6 +47,7 @@ public LoRaDeviceModelDto CreateDeviceModel(TableEntity entity)
Description = entity[nameof(LoRaDeviceModelDto.Description)]?.ToString(),
SensorDecoder = entity[nameof(LoRaDeviceModelDto.SensorDecoder)]?.ToString(),
UseOTAA = bool.Parse(entity[nameof(LoRaDeviceModelDto.UseOTAA)]?.ToString() ?? "true"),
+ ClassType = Enum.TryParse(entity[nameof(LoRaDeviceModelDto.ClassType)]?.ToString(), out var classType) ? classType : ClassType.A,
PreferredWindow = int.TryParse(entity[nameof(LoRaDeviceModelDto.PreferredWindow)]?.ToString(), out var intResult) ? intResult : 1,
Supports32BitFCnt = bool.TryParse(entity[nameof(LoRaDeviceModelDto.Supports32BitFCnt)]?.ToString(), out var boolResult) ? boolResult : null,
ABPRelaxMode = bool.TryParse(entity[nameof(LoRaDeviceModelDto.ABPRelaxMode)]?.ToString(), out boolResult) ? boolResult : null,
@@ -79,6 +80,7 @@ public Dictionary BuildDeviceModelDesiredProperties(LoRaDeviceMo
AddOptionalProperties(nameof(LoRaDeviceModelDto.RX1DROffset), modelDto.RX1DROffset, desiredProperties);
AddOptionalProperties(nameof(LoRaDeviceModelDto.RX2DataRate), modelDto.RX2DataRate, desiredProperties);
AddOptionalProperties(nameof(LoRaDeviceModelDto.RXDelay), modelDto.RXDelay, desiredProperties);
+ AddOptionalProperties(nameof(LoRaDeviceModelDto.ClassType), modelDto.ClassType.ToString(), desiredProperties);
return desiredProperties;
}
diff --git a/src/AzureIoTHubPortal.Domain/Entities/DeviceModel.cs b/src/AzureIoTHubPortal.Domain/Entities/DeviceModel.cs
index add66fa1a..8a14cbcef 100644
--- a/src/AzureIoTHubPortal.Domain/Entities/DeviceModel.cs
+++ b/src/AzureIoTHubPortal.Domain/Entities/DeviceModel.cs
@@ -22,6 +22,8 @@ public class DeviceModel : EntityBase
public DeduplicationMode? Deduplication { get; set; }
+ public ClassType ClassType { get; set; }
+
public bool? ABPRelaxMode { get; set; }
public bool? Downlink { get; set; }