From 19441602f7873957b265a710d59a2c2100efaa89 Mon Sep 17 00:00:00 2001 From: Daniel Abbatt Date: Wed, 9 Sep 2026 17:39:55 +0100 Subject: [PATCH] feat: map the Switch, Camera, Sensor and Cellular Gateway members from the 1.74.0 gap report Twenty-two members the v1.74.0 spec documents that the models lacked, the fifth per-area batch, plus eight corrections to members that could never bind: ConfigTemplateSwitchProfilePortDot3az mapped "dot3az" for "enabled", NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4 mapped "ipv4" for "address", EsimsServiceProvidersItemLogo mapped "logo" for "url", EsimsServiceProvidersAccounts.Items was a list of a type that is itself an {items, meta} wrapper, CameraLive.Zones was fixed to a single "0" zone where the API keys by zone ID, ZoneData.Person had no [DataMember] inside a [DataContract] class, SensorMetrics lacked no2/o3/pm10 so those readings threw on deserialization, and IOrganizationSwitches carried a duplicate GetOrganizationSwitchPortsTopologyDiscoveryByDeviceAsync overload wired to the usage-history path, which is removed. SwitchCameraSensorCellularMemberTests covers the new members and the corrections. --- CHANGELOG.md | 33 ++++++ .../SwitchCameraSensorCellularMemberTests.cs | 110 ++++++++++++++++++ .../Data/AlternateManagementInterface.cs | 7 ++ Meraki.Api/Data/CameraLive.cs | 5 +- Meraki.Api/Data/CameraRoleAppliedOnDevice.cs | 14 +++ Meraki.Api/Data/CameraRoleAppliedOnNetwork.cs | 14 +++ Meraki.Api/Data/CameraRoleAppliedOrgWide.cs | 21 ++++ Meraki.Api/Data/ConfigOverrides.cs | 7 ++ .../Data/ConfigTemplateSwitchProfilePort.cs | 7 ++ .../ConfigTemplateSwitchProfilePortDot3az.cs | 4 +- .../Data/EsimsServiceProvidersAccounts.cs | 4 +- .../Data/EsimsServiceProvidersAccountsItem.cs | 1 + .../Data/EsimsServiceProvidersItemLogo.cs | 4 +- ...CellularGatewayEsimsInventoryItemDevice.cs | 7 ++ ...chDhcpV4ServersSeenLastPacketSourceIpv4.cs | 4 +- Meraki.Api/Data/SensorMetrics.cs | 18 +++ Meraki.Api/Data/SensorReadingHistoric.cs | 21 ++++ Meraki.Api/Data/SensorReadingLatestReading.cs | 21 ++++ Meraki.Api/Data/StackDevice.cs | 7 ++ Meraki.Api/Data/SwitchPort.cs | 7 ++ ...PortsUsageHistoryByDeviceByIntervalItem.cs | 6 + Meraki.Api/Data/ZoneData.cs | 6 +- Meraki.Api/Data/Zones.cs | 1 + .../Organizations/IOrganizationSwitches.cs | 43 ------- 24 files changed, 317 insertions(+), 55 deletions(-) create mode 100644 Meraki.Api.Test/Data/SwitchCameraSensorCellularMemberTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f486efd3..c06220030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## 1.74.17 + +- **Twenty-two Switch, Camera, Sensor and Cellular Gateway response members the v1.74.0 spec + documents are now mapped**, the fifth per-area batch from the gap report: + `AlternateManagementInterface.UseOobMgmt`, `ConfigOverrides.VoiceVlan`, `SwitchPort.StpPortFastTrunk` + and `ConfigTemplateSwitchProfilePort.StpPortFastTrunk`, `StackDevice.ProductType`, + `SwitchPortsUsageHistoryByDeviceByIntervalItem.Serial`; `PermissionLevel` and `PermissionScope` on + `CameraRoleAppliedOnDevice`, `CameraRoleAppliedOnNetwork` and `CameraRoleAppliedOrgWide` (plus `Tag` + on the last); `No2`, `O3` and `Pm10` on `SensorReadingHistoric` and `SensorReadingLatestReading` + (reusing `SensorMetricConcentration`); `NetworkCellularGatewayEsimsInventoryItemDevice.Status`. + +- **Six members that could never bind are corrected** (breaking in the type-system sense only): + - `ConfigTemplateSwitchProfilePortDot3az.Dot3az` was mapped to `dot3az`; the API sends `enabled`. + Now `Enabled`, matching `SwitchPortDot3az`. + - `NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4.Ipv4` was mapped to `ipv4`; the API sends + `address`. Now `Address`. + - `EsimsServiceProvidersItemLogo.Logo` was mapped to `logo`; the API sends `url`. Now `Url`. + - `EsimsServiceProvidersAccounts.Items` was a list of `EsimsServiceProvidersAccountsItem`, which is + itself an `{items, meta}` wrapper, so no account ever bound. It is now + `List`; the old item type is `[Obsolete]`. + - `CameraLive.Zones` was a `Zones` class with a single fixed `"0"` member; the API keys zones by + zone ID. It is now `Dictionary`, and `Zones` is `[Obsolete]`. + - `ZoneData.Person` had no `[DataMember]` inside a `[DataContract]` class, so Newtonsoft ignored it. + + - `SensorMetrics` lacked `No2`, `O3` and `Pm10`, so a reading whose `metric` was one of them threw + on deserialization rather than binding; the three values are added. + - `IOrganizationSwitches` had a second `GetOrganizationSwitchPortsTopologyDiscoveryByDeviceAsync` + overload, taking the usage-history filter parameters, whose `[Get]` path was the **usage-history** + endpoint and whose return type was the topology model, so it could never have returned anything + usable. It is removed; the single-parameter overload with the correct path remains. + + Regression tests are in `Meraki.Api.Test.Data.SwitchCameraSensorCellularMemberTests`. + ## 1.74.15 - **Nineteen Wireless response members the v1.74.0 spec documents are now mapped**, the fourth diff --git a/Meraki.Api.Test/Data/SwitchCameraSensorCellularMemberTests.cs b/Meraki.Api.Test/Data/SwitchCameraSensorCellularMemberTests.cs new file mode 100644 index 000000000..a27008d2f --- /dev/null +++ b/Meraki.Api.Test/Data/SwitchCameraSensorCellularMemberTests.cs @@ -0,0 +1,110 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Meraki.Api.Test.Data; + +/// +/// Regression tests for Switch, Camera, Sensor and Cellular Gateway response members the v1.74.0 +/// OpenAPI spec documents that the models lacked. Each payload has the shape the spec documents, and +/// is deserialized with the settings uses so an +/// unmapped field fails the test rather than being dropped. +/// +public class SwitchCameraSensorCellularMemberTests +{ + private static readonly JsonSerializerSettings ThrowOnMissingMember = new() + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Error, + Converters = [new StringEnumConverter()] + }; + + private static T Deserialize(string json) + { + var result = JsonConvert.DeserializeObject(json, ThrowOnMissingMember); + _ = result.Should().NotBeNull(); + return result!; + } + + // GET /devices/{serial}/switch/ports/{portId} and the config template equivalent + [Fact] + public void Deserialize_SwitchPorts_MapStpPortFastTrunkAndDot3azEnabled() + { + _ = Deserialize("""{ "portId": "1", "name": "Uplink", "stpPortFastTrunk": true }""").StpPortFastTrunk.Should().BeTrue(); + + var templatePort = Deserialize("""{ "portId": "1", "name": "Uplink", "stpPortFastTrunk": false, "dot3az": { "enabled": true } }"""); + + _ = templatePort.StpPortFastTrunk.Should().BeFalse(); + _ = templatePort.Dot3az!.Enabled.Should().BeTrue(); + } + + // GET /networks/{networkId}/switch/dhcp/v4/servers/seen - source.ipv4 is {address}, not a string. + [Fact] + public void Deserialize_DhcpV4ServersSeenSourceIpv4_MapsAddress() + { + var ipv4 = Deserialize("""{ "address": "10.0.0.1" }"""); + + _ = ipv4.Address.Should().Be("10.0.0.1"); + } + + // Switch scalars. + [Fact] + public void Deserialize_SwitchScalars_Bind() + { + _ = Deserialize("""{ "enabled": true, "vlanId": 100, "protocols": [], "switches": [], "useOobMgmt": true }""").UseOobMgmt.Should().BeTrue(); + _ = Deserialize("""{ "type": "access", "allowedVlans": "all", "vlan": 10, "voiceVlan": 20 }""").VoiceVlan.Should().Be(20); + _ = Deserialize("""{ "serial": "Q2XX-ABCD-1234", "name": "sw1", "productType": "switch" }""").ProductType.Should().Be("switch"); + } + + // appliedOrgWide[] from POST /organizations/{organizationId}/camera/roles + [Fact] + public void Deserialize_CameraRoleAppliedOrgWide_MapsPermissionFields() + { + var applied = Deserialize("""{ "tag": "cameras", "permissionScopeId": "1", "permissionScope": "Camera viewer", "permissionLevel": "view" }"""); + + _ = applied.PermissionLevel.Should().Be("view"); + _ = applied.PermissionScope.Should().Be("Camera viewer"); + _ = applied.Tag.Should().Be("cameras"); + } + + // GET /devices/{serial}/camera/analytics/live - zones are keyed by zone ID, and ZoneData.Person + // previously had no [DataMember] so was ignored inside a [DataContract] class. + [Fact] + public void Deserialize_CameraLive_MapsZonesByIdWithPersonCount() + { + var live = Deserialize("""{ "ts": "2026-09-09T10:00:00Z", "zones": { "0": { "person": 2 }, "1234": { "person": 0 } } }"""); + + _ = live.Zones.Should().HaveCount(2); + _ = live.Zones["0"].Person.Should().Be(2); + } + + // GET /organizations/{organizationId}/sensor/readings/latest - the newer air-quality metrics. + [Fact] + public void Deserialize_SensorReadingLatestReading_MapsNo2O3Pm10() + { + var reading = Deserialize("""{ "ts": "2026-09-09T10:00:00Z", "metric": "pm10", "no2": { "concentration": 12 }, "o3": { "concentration": 30 }, "pm10": { "concentration": 8 } }"""); + + _ = reading.Pm10!.Concentration.Should().Be(8); + _ = reading.No2!.Concentration.Should().Be(12); + } + + // GET /organizations/{organizationId}/cellularGateway/esims/serviceProviders/accounts - Items was a + // list of a wrapper type, so no account ever bound. + [Fact] + public void Deserialize_EsimsServiceProvidersAccounts_MapsAccounts() + { + var accounts = Deserialize(""" + { "items": [ { "accountId": "1", "lastUpdatedAt": "2026-09-09T10:00:00Z", "title": "Example", "username": "user", "serviceProvider": { "name": "Example Mobile", "logo": { "url": "https://example.invalid/logo.png" } } } ], "meta": { "counts": { "items": { "total": 1, "remaining": 0 } } } } + """); + + _ = accounts.Items.Should().ContainSingle().Which.AccountId.Should().Be("1"); + _ = accounts.Meta.Counts!.Items.Total.Should().Be(1); + } + + // GET /organizations/{organizationId}/cellularGateway/esims/serviceProviders - logo is {url}. + [Fact] + public void Deserialize_EsimsServiceProvidersItemLogo_MapsUrl() + { + _ = Deserialize("""{ "url": "https://example.invalid/logo.png" }""").Url.Should().Be("https://example.invalid/logo.png"); + _ = Deserialize("""{ "model": "MG41", "name": "mg1", "serial": "Q2XX-ABCD-1234", "url": "https://example.invalid", "status": "online" }""").Status.Should().Be("online"); + } +} diff --git a/Meraki.Api/Data/AlternateManagementInterface.cs b/Meraki.Api/Data/AlternateManagementInterface.cs index d7a43b8d2..3e03102ac 100644 --- a/Meraki.Api/Data/AlternateManagementInterface.cs +++ b/Meraki.Api/Data/AlternateManagementInterface.cs @@ -33,4 +33,11 @@ public class AlternateManagementInterface [ApiAccess(ApiAccess.ReadUpdate)] [DataMember(Name = "switches")] public List Switches { get; set; } = []; + + /// + /// Boolean value to use out-of-band management interface when configured + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "useOobMgmt")] + public bool? UseOobMgmt { get; set; } } diff --git a/Meraki.Api/Data/CameraLive.cs b/Meraki.Api/Data/CameraLive.cs index c6bb4aead..87808da0a 100644 --- a/Meraki.Api/Data/CameraLive.cs +++ b/Meraki.Api/Data/CameraLive.cs @@ -13,8 +13,9 @@ public class CameraLive public string Ts { get; set; } = string.Empty; /// - /// Zones + /// The zones state, keyed by zone ID /// + [ApiAccess(ApiAccess.Read)] [DataMember(Name = "zones")] - public Zones Zones { get; set; } = new(); + public Dictionary Zones { get; set; } = []; } diff --git a/Meraki.Api/Data/CameraRoleAppliedOnDevice.cs b/Meraki.Api/Data/CameraRoleAppliedOnDevice.cs index f0514e405..0989a3a98 100644 --- a/Meraki.Api/Data/CameraRoleAppliedOnDevice.cs +++ b/Meraki.Api/Data/CameraRoleAppliedOnDevice.cs @@ -40,4 +40,18 @@ public class CameraRoleAppliedOnDevice [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "tag")] public string? Tag { get; set; } + + /// + /// Permission level + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionLevel")] + public string? PermissionLevel { get; set; } + + /// + /// Permission scope name + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionScope")] + public string? PermissionScope { get; set; } } diff --git a/Meraki.Api/Data/CameraRoleAppliedOnNetwork.cs b/Meraki.Api/Data/CameraRoleAppliedOnNetwork.cs index 282f927ed..aaea60b8b 100644 --- a/Meraki.Api/Data/CameraRoleAppliedOnNetwork.cs +++ b/Meraki.Api/Data/CameraRoleAppliedOnNetwork.cs @@ -26,4 +26,18 @@ public class CameraRoleAppliedOnNetwork [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "tag")] public string? Tag { get; set; } + + /// + /// Permission level + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionLevel")] + public string? PermissionLevel { get; set; } + + /// + /// Permission scope name + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionScope")] + public string? PermissionScope { get; set; } } diff --git a/Meraki.Api/Data/CameraRoleAppliedOrgWide.cs b/Meraki.Api/Data/CameraRoleAppliedOrgWide.cs index c94f97f8a..d7df493a1 100644 --- a/Meraki.Api/Data/CameraRoleAppliedOrgWide.cs +++ b/Meraki.Api/Data/CameraRoleAppliedOrgWide.cs @@ -12,4 +12,25 @@ public class CameraRoleAppliedOrgWide [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "permissionScopeId")] public string? PermissionScopeId { get; set; } + + /// + /// Permission level + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionLevel")] + public string? PermissionLevel { get; set; } + + /// + /// Permission scope name + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "permissionScope")] + public string? PermissionScope { get; set; } + + /// + /// Organization tag + /// + [ApiAccess(ApiAccess.ReadWrite)] + [DataMember(Name = "tag")] + public string? Tag { get; set; } } diff --git a/Meraki.Api/Data/ConfigOverrides.cs b/Meraki.Api/Data/ConfigOverrides.cs index b755367bf..b7331bd04 100644 --- a/Meraki.Api/Data/ConfigOverrides.cs +++ b/Meraki.Api/Data/ConfigOverrides.cs @@ -26,4 +26,11 @@ public class ConfigOverrides [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "vlan")] public int? Vlan { get; set; } + + /// + /// The voice VLAN of the port. Only applicable to access ports. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "voiceVlan")] + public int? VoiceVlan { get; set; } } diff --git a/Meraki.Api/Data/ConfigTemplateSwitchProfilePort.cs b/Meraki.Api/Data/ConfigTemplateSwitchProfilePort.cs index 6c8f6f656..4c2f9a663 100644 --- a/Meraki.Api/Data/ConfigTemplateSwitchProfilePort.cs +++ b/Meraki.Api/Data/ConfigTemplateSwitchProfilePort.cs @@ -247,4 +247,11 @@ public class ConfigTemplateSwitchProfilePort : NamedItem [ApiAccess(ApiAccess.Read)] [DataMember(Name = "stackwiseVirtual")] public SwitchPortStackwiseVirtual? StackwiseVirtual { get; set; } + + /// + /// The state of STP PortFast Trunk on the switch template port. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "stpPortFastTrunk")] + public bool? StpPortFastTrunk { get; set; } } diff --git a/Meraki.Api/Data/ConfigTemplateSwitchProfilePortDot3az.cs b/Meraki.Api/Data/ConfigTemplateSwitchProfilePortDot3az.cs index fb6e77c8c..5b4e9de0c 100644 --- a/Meraki.Api/Data/ConfigTemplateSwitchProfilePortDot3az.cs +++ b/Meraki.Api/Data/ConfigTemplateSwitchProfilePortDot3az.cs @@ -10,6 +10,6 @@ public class ConfigTemplateSwitchProfilePortDot3az /// The Energy Efficient Ethernet status of the switch template port. /// [ApiAccess(ApiAccess.ReadUpdate)] - [DataMember(Name = "dot3az")] - public bool? Dot3az { get; set; } + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } } \ No newline at end of file diff --git a/Meraki.Api/Data/EsimsServiceProvidersAccounts.cs b/Meraki.Api/Data/EsimsServiceProvidersAccounts.cs index cf19d2231..9f83563ba 100644 --- a/Meraki.Api/Data/EsimsServiceProvidersAccounts.cs +++ b/Meraki.Api/Data/EsimsServiceProvidersAccounts.cs @@ -5,11 +5,11 @@ namespace Meraki.Api.Data; /// [DataContract] public class EsimsServiceProvidersAccounts - : ItemsResponseWithMeta + : ItemsResponseWithMeta { /// /// List of Cellular Service Provider Accounts /// [ApiAccess(ApiAccess.ReadWrite)] - public override List Items { get; set; } = []; + public override List Items { get; set; } = []; } diff --git a/Meraki.Api/Data/EsimsServiceProvidersAccountsItem.cs b/Meraki.Api/Data/EsimsServiceProvidersAccountsItem.cs index 5290053d7..771a63c86 100644 --- a/Meraki.Api/Data/EsimsServiceProvidersAccountsItem.cs +++ b/Meraki.Api/Data/EsimsServiceProvidersAccountsItem.cs @@ -3,6 +3,7 @@ namespace Meraki.Api.Data; /// /// Esims Service Providers Accounts /// +[Obsolete("Was the item type of EsimsServiceProvidersAccounts but is itself an {items, meta} wrapper, so no account ever bound. EsimsServiceProvidersAccounts.Items is now List. This type will be removed in a later release.")] [DataContract] public class EsimsServiceProvidersAccountsItem : ItemsResponseWithMeta diff --git a/Meraki.Api/Data/EsimsServiceProvidersItemLogo.cs b/Meraki.Api/Data/EsimsServiceProvidersItemLogo.cs index 749be5c0f..51807fe81 100644 --- a/Meraki.Api/Data/EsimsServiceProvidersItemLogo.cs +++ b/Meraki.Api/Data/EsimsServiceProvidersItemLogo.cs @@ -10,6 +10,6 @@ public class EsimsServiceProvidersItemLogo /// URL of service provider's logo. /// [ApiAccess(ApiAccess.Read)] - [DataMember(Name = "logo")] - public string? Logo { get; set; } + [DataMember(Name = "url")] + public string? Url { get; set; } } diff --git a/Meraki.Api/Data/NetworkCellularGatewayEsimsInventoryItemDevice.cs b/Meraki.Api/Data/NetworkCellularGatewayEsimsInventoryItemDevice.cs index 17a37ed50..97fd573a2 100644 --- a/Meraki.Api/Data/NetworkCellularGatewayEsimsInventoryItemDevice.cs +++ b/Meraki.Api/Data/NetworkCellularGatewayEsimsInventoryItemDevice.cs @@ -34,4 +34,11 @@ public class NetworkCellularGatewayEsimsInventoryItemDevice [ApiAccess(ApiAccess.Read)] [DataMember(Name = "url")] public string Url { get; set; } = string.Empty; + + /// + /// Device status + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "status")] + public string? Status { get; set; } } diff --git a/Meraki.Api/Data/NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4.cs b/Meraki.Api/Data/NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4.cs index 19b739a06..a4044fd81 100644 --- a/Meraki.Api/Data/NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4.cs +++ b/Meraki.Api/Data/NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4.cs @@ -10,6 +10,6 @@ public class NetworksSwitchDhcpV4ServersSeenLastPacketSourceIpv4 /// Source ipv4 address of the packet. /// [ApiAccess(ApiAccess.Read)] - [DataMember(Name = "ipv4")] - public string Ipv4 { get; set; } = string.Empty; + [DataMember(Name = "address")] + public string Address { get; set; } = string.Empty; } \ No newline at end of file diff --git a/Meraki.Api/Data/SensorMetrics.cs b/Meraki.Api/Data/SensorMetrics.cs index a81a63a73..6eba408c2 100644 --- a/Meraki.Api/Data/SensorMetrics.cs +++ b/Meraki.Api/Data/SensorMetrics.cs @@ -132,4 +132,22 @@ public enum SensorMetrics /// [EnumMember(Value = "rawTemperature")] RawTemperature, + + /// + /// Nitrogen dioxide concentration + /// + [EnumMember(Value = "no2")] + No2, + + /// + /// Ozone concentration + /// + [EnumMember(Value = "o3")] + O3, + + /// + /// PM10 particulate concentration + /// + [EnumMember(Value = "pm10")] + Pm10 } diff --git a/Meraki.Api/Data/SensorReadingHistoric.cs b/Meraki.Api/Data/SensorReadingHistoric.cs index 9310707f2..2ce2e2b3e 100644 --- a/Meraki.Api/Data/SensorReadingHistoric.cs +++ b/Meraki.Api/Data/SensorReadingHistoric.cs @@ -161,4 +161,25 @@ public class SensorReadingHistoric /// [DataMember(Name = "water")] public SensorMetricWater? Water { get; set; } + + /// + /// Reading for the 'no2' metric. This will only be present if the 'metric' property equals 'no2'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "no2")] + public SensorMetricConcentration? No2 { get; set; } + + /// + /// Reading for the 'o3' metric. This will only be present if the 'metric' property equals 'o3'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "o3")] + public SensorMetricConcentration? O3 { get; set; } + + /// + /// Reading for the 'pm10' metric. This will only be present if the 'metric' property equals 'pm10'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "pm10")] + public SensorMetricConcentration? Pm10 { get; set; } } diff --git a/Meraki.Api/Data/SensorReadingLatestReading.cs b/Meraki.Api/Data/SensorReadingLatestReading.cs index 75a20347c..4f929e72a 100644 --- a/Meraki.Api/Data/SensorReadingLatestReading.cs +++ b/Meraki.Api/Data/SensorReadingLatestReading.cs @@ -144,4 +144,25 @@ public class SensorReadingLatestReading /// [DataMember(Name = "water")] public SensorMetricWater? Water { get; set; } + + /// + /// Reading for the 'no2' metric. This will only be present if the 'metric' property equals 'no2'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "no2")] + public SensorMetricConcentration? No2 { get; set; } + + /// + /// Reading for the 'o3' metric. This will only be present if the 'metric' property equals 'o3'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "o3")] + public SensorMetricConcentration? O3 { get; set; } + + /// + /// Reading for the 'pm10' metric. This will only be present if the 'metric' property equals 'pm10'. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "pm10")] + public SensorMetricConcentration? Pm10 { get; set; } } diff --git a/Meraki.Api/Data/StackDevice.cs b/Meraki.Api/Data/StackDevice.cs index efd159a25..71126f90a 100644 --- a/Meraki.Api/Data/StackDevice.cs +++ b/Meraki.Api/Data/StackDevice.cs @@ -59,4 +59,11 @@ public class StackDevice /// [DataMember(Name = "uplinks")] public List Uplinks { get; set; } = []; + + /// + /// The product type of the device + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "productType")] + public string? ProductType { get; set; } } diff --git a/Meraki.Api/Data/SwitchPort.cs b/Meraki.Api/Data/SwitchPort.cs index 8846993fd..39b8de215 100644 --- a/Meraki.Api/Data/SwitchPort.cs +++ b/Meraki.Api/Data/SwitchPort.cs @@ -267,4 +267,11 @@ public class SwitchPort : NamedItem [ApiAccess(ApiAccess.Read)] [DataMember(Name = "stackwiseVirtual")] public SwitchPortStackwiseVirtual? StackwiseVirtual { get; set; } + + /// + /// The state of STP PortFast Trunk on the switch port. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "stpPortFastTrunk")] + public bool? StpPortFastTrunk { get; set; } } diff --git a/Meraki.Api/Data/SwitchPortsUsageHistoryByDeviceByIntervalItem.cs b/Meraki.Api/Data/SwitchPortsUsageHistoryByDeviceByIntervalItem.cs index e4b1c506f..b2075589b 100644 --- a/Meraki.Api/Data/SwitchPortsUsageHistoryByDeviceByIntervalItem.cs +++ b/Meraki.Api/Data/SwitchPortsUsageHistoryByDeviceByIntervalItem.cs @@ -41,4 +41,10 @@ public class SwitchPortsUsageHistoryByDeviceByIntervalItem [DataMember(Name = "ports")] public List Ports { get; set; } = []; + /// + /// The serial number of the switch. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "serial")] + public string? Serial { get; set; } } diff --git a/Meraki.Api/Data/ZoneData.cs b/Meraki.Api/Data/ZoneData.cs index 7458dad73..3257f2683 100644 --- a/Meraki.Api/Data/ZoneData.cs +++ b/Meraki.Api/Data/ZoneData.cs @@ -7,7 +7,9 @@ public class ZoneData { /// - /// Person + /// The number of people detected in the zone /// - public int Person { get; set; } + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "person")] + public int? Person { get; set; } } diff --git a/Meraki.Api/Data/Zones.cs b/Meraki.Api/Data/Zones.cs index 4b85b5961..94a2140fd 100644 --- a/Meraki.Api/Data/Zones.cs +++ b/Meraki.Api/Data/Zones.cs @@ -3,6 +3,7 @@ /// /// Zones /// +[Obsolete("Camera analytics zones are keyed by zone ID, not fixed to \"0\". CameraLive.Zones is now Dictionary. This type will be removed in a later release.")] [DataContract] public class Zones { diff --git a/Meraki.Api/Interfaces/General/Organizations/IOrganizationSwitches.cs b/Meraki.Api/Interfaces/General/Organizations/IOrganizationSwitches.cs index 6f1828d4f..823173209 100644 --- a/Meraki.Api/Interfaces/General/Organizations/IOrganizationSwitches.cs +++ b/Meraki.Api/Interfaces/General/Organizations/IOrganizationSwitches.cs @@ -434,49 +434,6 @@ Task GetOrganizationSwitchPortsUsageH CancellationToken cancellationToken = default ); - /// - /// List most recently seen LLDP/CDP discovery and topology information per switch port in an organization. - /// - /// Thrown when fails to make API call - /// The OrganizationID - /// The beginning of the timespan for the data. The maximum lookback period is 31 days from today. - /// - /// The timespan for which the information will be fetched. If specifying timespan, do not specify parameter t0. The value must be in seconds and be less than or equal to 31 days. The default is 1 day. - /// - /// The number of entries per page returned. Acceptable range is 3 - 20. Default is 10. - /// A token used by the server to indicate the start of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. - /// A token used by the server to indicate the end of the page. Often this is a timestamp or an ID but it is not limited to those. This parameter should not be defined by client applications. The link for the first, last, prev, or next page in the HTTP Link header should define it. - /// Optional parameter to filter results by switches where the configuration has been updated after the given timestamp - /// Optional parameter to filter switchports belonging to switches by MAC address. All returned switches will have a MAC address that contains the search term or is an exact match. - /// Optional parameter to filter items to switches that have one of the provided MAC addresses. - /// Optional parameter to filter items to switches with names that contain the search term or are an exact match. - /// Optional parameter to filter items to switches in one of the provided networks. - /// Optional parameter to filter items to switches that contain switchports belonging to one of the specified port profiles. - /// Optional parameter to filter switchports belonging to switches by serial number. All returned switches will have a serial number that contains the search term or is an exact match. - /// Optional parameter to filter switchports belonging to switches with one or more serial numbers. All switchports returned belong to serial numbers of switches that are an exact match. - /// - [ApiOperationId("getOrganizationSwitchPortsTopologyDiscoveryByDevice")] - [Get("/organizations/{organizationId}/switch/ports/usage/history/byDevice/byInterval")] - Task GetOrganizationSwitchPortsTopologyDiscoveryByDeviceAsync( - string organizationId, - string? t0, - string? t1, - int? timespan, - int? interval, - int? perPage, - string? startingAfter, - string? endingBefore, - string? configurationUpdatedAfter, - string? mac, - [AliasAs("macs[]")] List? macs, - string? name, - [AliasAs("networkIds[]")] List? networkIds, - [AliasAs("portProfileIds[]")] List? portProfileIds, - string? serial, - [AliasAs("serials[]")] List? serials, - CancellationToken cancellationToken = default - ); - /// /// Return time-series digital optical monitoring (DOM) readings for ports on each DOM-enabled switch in an organization, in addition to thresholds for each relevant Small Form Factor Pluggable (SFP) module. ///