Add a way to ask Matter.framework for information about device types. (#36084)

diff --git a/src/darwin/Framework/CHIP/MTRDeviceType.h b/src/darwin/Framework/CHIP/MTRDeviceType.h
new file mode 100644
index 0000000..aded23e
--- /dev/null
+++ b/src/darwin/Framework/CHIP/MTRDeviceType.h
@@ -0,0 +1,55 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#import <Matter/MTRDefines.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+MTR_NEWLY_AVAILABLE
+@interface MTRDeviceType : NSObject
+
+/**
+ * Returns an MTRDeviceType for the given ID, if the ID is known.  Returns nil
+ * for unknown IDs.
+ */
++ (nullable MTRDeviceType *)deviceTypeForID:(NSNumber *)deviceTypeID;
+
+/**
+ * The identifier of the device type (32-bit unsigned integer).
+ */
+@property (nonatomic, readonly, copy) NSNumber * id;
+
+/**
+ * Returns the name of the device type.
+ */
+@property (nonatomic, readonly, retain) NSString * name;
+
+/**
+ * Returns whether this is a utility device type.
+ */
+@property (nonatomic, readonly, assign) BOOL isUtility;
+
+- (instancetype)init NS_UNAVAILABLE;
++ (instancetype)new NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/darwin/Framework/CHIP/MTRDeviceType.mm b/src/darwin/Framework/CHIP/MTRDeviceType.mm
new file mode 100644
index 0000000..394640d
--- /dev/null
+++ b/src/darwin/Framework/CHIP/MTRDeviceType.mm
@@ -0,0 +1,59 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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 <Matter/MTRDeviceType.h>
+
+#import "MTRDeviceTypeMetadata.h"
+#import "MTRLogging_Internal.h"
+
+#include <lib/support/SafeInt.h>
+
+using namespace chip;
+
+@implementation MTRDeviceType
+
+- (nullable instancetype)initWithDeviceTypeID:(NSNumber *)id name:(NSString *)name isUtility:(BOOL)isUtility
+{
+    if (!(self = [super init])) {
+        return nil;
+    }
+
+    _id = id;
+    _name = name;
+    _isUtility = isUtility;
+    return self;
+}
+
++ (nullable MTRDeviceType *)deviceTypeForID:(NSNumber *)deviceTypeID
+{
+    if (!CanCastTo<DeviceTypeId>(deviceTypeID.unsignedLongLongValue)) {
+        MTR_LOG_ERROR("Invalid device type ID: 0x%llx", deviceTypeID.unsignedLongLongValue);
+        return nil;
+    }
+
+    auto * deviceTypeData = MTRDeviceTypeDataForID(static_cast<DeviceTypeId>(deviceTypeID.unsignedLongLongValue));
+    if (!deviceTypeData) {
+        return nil;
+    }
+
+    return [[MTRDeviceType alloc]
+        initWithDeviceTypeID:deviceTypeID
+                        name:[NSString stringWithUTF8String:deviceTypeData->name]
+                   isUtility:(deviceTypeData->deviceClass != MTRDeviceTypeClass::Simple)];
+}
+
+@end
diff --git a/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h b/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h
index d60f623..2597f60 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h
+++ b/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h
@@ -21,4 +21,23 @@
 
 #include <lib/core/DataModelTypes.h>
 
-BOOL MTRIsKnownUtilityDeviceType(chip::DeviceTypeId aDeviceTypeId);
+NS_ASSUME_NONNULL_BEGIN
+
+enum class MTRDeviceTypeClass
+{
+    Utility,
+    Simple,
+    Node, // Might not be a real class, but we have it for Root Node for now.
+};
+
+struct MTRDeviceTypeData
+{
+    chip::DeviceTypeId id;
+    MTRDeviceTypeClass deviceClass;
+    const char * name;
+};
+
+// Returns null for unknown device types.
+const MTRDeviceTypeData * _Nullable MTRDeviceTypeDataForID(chip::DeviceTypeId aDeviceTypeId);
+
+NS_ASSUME_NONNULL_END
diff --git a/src/darwin/Framework/CHIP/Matter.h b/src/darwin/Framework/CHIP/Matter.h
index 109f4a2..9f57e4f 100644
--- a/src/darwin/Framework/CHIP/Matter.h
+++ b/src/darwin/Framework/CHIP/Matter.h
@@ -48,6 +48,7 @@
 #import <Matter/MTRDeviceControllerStartupParams.h>
 #import <Matter/MTRDeviceControllerStorageDelegate.h>
 #import <Matter/MTRDeviceStorageBehaviorConfiguration.h>
+#import <Matter/MTRDeviceType.h>
 #import <Matter/MTRDeviceTypeRevision.h>
 #import <Matter/MTRDiagnosticLogsType.h>
 #import <Matter/MTRError.h>
diff --git a/src/darwin/Framework/CHIP/templates/MTRClusterConstants.zapt b/src/darwin/Framework/CHIP/templates/MTRClusterConstants.zapt
index c615754..606732b 100644
--- a/src/darwin/Framework/CHIP/templates/MTRClusterConstants.zapt
+++ b/src/darwin/Framework/CHIP/templates/MTRClusterConstants.zapt
@@ -225,3 +225,15 @@
 {{> eventIDs clusterName=label}}
 {{/zcl_clusters}}
 };
+
+#pragma mark - Device Type IDs
+
+typedef NS_ENUM(uint32_t, MTRDeviceTypeIDType) {
+  {{#zcl_device_types}}
+  {{! Only include standard device types for now.  The template syntax does not get hex numbers, apparently.
+      ZAP seems to have no is_number_less_than helper, so do is_number_greater_than with the arguments reversed. }}
+  {{#if (is_number_greater_than 65536 code)}}
+  MTRDeviceTypeIDType{{asUpperCamelCase caption preserveAcronyms=true}}ID {{availability "" deviceType=(asUpperCamelCase caption preserveAcronyms=true)}} = {{asHex code 8}},
+  {{/if}}
+  {{/zcl_device_types}}
+} MTR_NEWLY_AVAILABLE;
diff --git a/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt b/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt
index 7047fb2..16322f3 100644
--- a/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt
+++ b/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt
@@ -5,23 +5,11 @@
 using namespace chip;
 
 namespace {
-enum class DeviceTypeClass {
-  Utility,
-  Simple,
-  Node, // Might not be a real class, but we have it for Root Node for now.
-  // If new classes get added, plase audit MTRIsKnownUtilityDeviceType below.
-};
 
-struct DeviceTypeData {
-  DeviceTypeId id;
-  DeviceTypeClass deviceClass;
-  const char * name;
-};
-
-constexpr DeviceTypeData knownDeviceTypes[] = {
+constexpr MTRDeviceTypeData knownDeviceTypes[] = {
   {{#zcl_device_types}}
   {{#if class}}
-  { {{asHex code 8}}, DeviceTypeClass::{{class}}, "{{caption}}" },
+  { {{asHex code 8}}, MTRDeviceTypeClass::{{class}}, "{{caption}}" },
   {{/if}}
   {{/zcl_device_types}}
 };
@@ -34,12 +22,12 @@
 
 } // anonymous namespace
 
-BOOL MTRIsKnownUtilityDeviceType(DeviceTypeId aDeviceTypeId)
+const MTRDeviceTypeData * _Nullable MTRDeviceTypeDataForID(chip::DeviceTypeId aDeviceTypeId)
 {
     for (auto & deviceType : knownDeviceTypes) {
         if (deviceType.id == aDeviceTypeId) {
-            return deviceType.deviceClass != DeviceTypeClass::Simple;
+            return &deviceType;
         }
     }
-    return NO;
+    return nullptr;
 }
diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml
index fdf5c00..c8beeca 100644
--- a/src/darwin/Framework/CHIP/templates/availability.yaml
+++ b/src/darwin/Framework/CHIP/templates/availability.yaml
@@ -9742,6 +9742,73 @@
                   - UpdateDirection
                   - UpdateTime
                   - UpdateStartHue
+      device types:
+          - AirQualitySensor
+          - AirPurifier
+          - Aggregator
+          - BasicVideoPlayer
+          - BridgedNode
+          - CastingVideoClient
+          - CastingVideoPlayer
+          - ColorDimmerSwitch
+          - ColorTemperatureLight
+          - ContactSensor
+          - ContentApp
+          - ControlBridge
+          - CookSurface
+          - Cooktop
+          - DeviceEnergyManagement
+          - DimmableLight
+          - DimmablePlugInUnit
+          - DimmerSwitch
+          - Dishwasher
+          - DoorLock
+          - DoorLockController
+          - ElectricalSensor
+          - EVSE
+          - ExtendedColorLight
+          - ExtractorHood
+          - Fan
+          - FlowSensor
+          - GenericSwitch
+          - HeatingCoolingUnit
+          - HumiditySensor
+          - LaundryDryer
+          - LaundryWasher
+          - LightSensor
+          - MicrowaveOven
+          - ModeSelect
+          - NetworkInfrastructureManager
+          - OccupancySensor
+          - OnOffLight
+          - OnOffLightSwitch
+          - OnOffPlugInUnit
+          - OnOffSensor
+          - OTAProvider
+          - OTARequestor
+          - Oven
+          - PressureSensor
+          - PowerSource
+          - Pump
+          - PumpController
+          - RainSensor
+          - Refrigerator
+          - RoboticVacuumCleaner
+          - RoomAirConditioner
+          - RootNode
+          - SecondaryNetworkInterface
+          - SmokeCOAlarm
+          - Speaker
+          - TemperatureControlledCabinet
+          - TemperatureSensor
+          - Thermostat
+          - ThreadBorderRouter
+          - VideoRemoteControl
+          - WaterFreezeDetector
+          - WaterLeakDetector
+          - WaterValve
+          - WindowCovering
+          - WindowCoveringController
   provisional:
       clusters:
           # Targeting 1.4
@@ -9754,8 +9821,11 @@
           - WaterHeaterMode
           - WiFiNetworkManagement
           # Targeting Camera enablement
+          - CameraAVStreamManagement
           - Chime
           - WebRTCTransportProvider
+          - WebRTCTransportRequestor
+          - ZoneManagement
       attributes:
           AccessControl:
               # Targeting 1.4
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h
index 9decbec..76d6ab3 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h
@@ -7688,3 +7688,74 @@
     MTREventIDTypeClusterSampleMEIEventPingCountEventID MTR_PROVISIONALLY_AVAILABLE = 0x00000000,
 
 };
+
+#pragma mark - Device Type IDs
+
+typedef NS_ENUM(uint32_t, MTRDeviceTypeIDType) {
+    MTRDeviceTypeIDTypeDoorLockID MTR_NEWLY_AVAILABLE = 0x0000000A,
+    MTRDeviceTypeIDTypeDoorLockControllerID MTR_NEWLY_AVAILABLE = 0x0000000B,
+    MTRDeviceTypeIDTypeAggregatorID MTR_NEWLY_AVAILABLE = 0x0000000E,
+    MTRDeviceTypeIDTypeGenericSwitchID MTR_NEWLY_AVAILABLE = 0x0000000F,
+    MTRDeviceTypeIDTypePowerSourceID MTR_NEWLY_AVAILABLE = 0x00000011,
+    MTRDeviceTypeIDTypeOTARequestorID MTR_NEWLY_AVAILABLE = 0x00000012,
+    MTRDeviceTypeIDTypeBridgedNodeID MTR_NEWLY_AVAILABLE = 0x00000013,
+    MTRDeviceTypeIDTypeOTAProviderID MTR_NEWLY_AVAILABLE = 0x00000014,
+    MTRDeviceTypeIDTypeContactSensorID MTR_NEWLY_AVAILABLE = 0x00000015,
+    MTRDeviceTypeIDTypeRootNodeID MTR_NEWLY_AVAILABLE = 0x00000016,
+    MTRDeviceTypeIDTypeSecondaryNetworkInterfaceID MTR_NEWLY_AVAILABLE = 0x00000019,
+    MTRDeviceTypeIDTypeSpeakerID MTR_NEWLY_AVAILABLE = 0x00000022,
+    MTRDeviceTypeIDTypeCastingVideoPlayerID MTR_NEWLY_AVAILABLE = 0x00000023,
+    MTRDeviceTypeIDTypeContentAppID MTR_NEWLY_AVAILABLE = 0x00000024,
+    MTRDeviceTypeIDTypeModeSelectID MTR_NEWLY_AVAILABLE = 0x00000027,
+    MTRDeviceTypeIDTypeBasicVideoPlayerID MTR_NEWLY_AVAILABLE = 0x00000028,
+    MTRDeviceTypeIDTypeCastingVideoClientID MTR_NEWLY_AVAILABLE = 0x00000029,
+    MTRDeviceTypeIDTypeVideoRemoteControlID MTR_NEWLY_AVAILABLE = 0x0000002A,
+    MTRDeviceTypeIDTypeFanID MTR_NEWLY_AVAILABLE = 0x0000002B,
+    MTRDeviceTypeIDTypeAirQualitySensorID MTR_NEWLY_AVAILABLE = 0x0000002C,
+    MTRDeviceTypeIDTypeAirPurifierID MTR_NEWLY_AVAILABLE = 0x0000002D,
+    MTRDeviceTypeIDTypeWaterFreezeDetectorID MTR_NEWLY_AVAILABLE = 0x00000041,
+    MTRDeviceTypeIDTypeWaterValveID MTR_NEWLY_AVAILABLE = 0x00000042,
+    MTRDeviceTypeIDTypeWaterLeakDetectorID MTR_NEWLY_AVAILABLE = 0x00000043,
+    MTRDeviceTypeIDTypeRainSensorID MTR_NEWLY_AVAILABLE = 0x00000044,
+    MTRDeviceTypeIDTypeRefrigeratorID MTR_NEWLY_AVAILABLE = 0x00000070,
+    MTRDeviceTypeIDTypeTemperatureControlledCabinetID MTR_NEWLY_AVAILABLE = 0x00000071,
+    MTRDeviceTypeIDTypeRoomAirConditionerID MTR_NEWLY_AVAILABLE = 0x00000072,
+    MTRDeviceTypeIDTypeLaundryWasherID MTR_NEWLY_AVAILABLE = 0x00000073,
+    MTRDeviceTypeIDTypeRoboticVacuumCleanerID MTR_NEWLY_AVAILABLE = 0x00000074,
+    MTRDeviceTypeIDTypeDishwasherID MTR_NEWLY_AVAILABLE = 0x00000075,
+    MTRDeviceTypeIDTypeSmokeCOAlarmID MTR_NEWLY_AVAILABLE = 0x00000076,
+    MTRDeviceTypeIDTypeCookSurfaceID MTR_NEWLY_AVAILABLE = 0x00000077,
+    MTRDeviceTypeIDTypeCooktopID MTR_NEWLY_AVAILABLE = 0x00000078,
+    MTRDeviceTypeIDTypeMicrowaveOvenID MTR_NEWLY_AVAILABLE = 0x00000079,
+    MTRDeviceTypeIDTypeExtractorHoodID MTR_NEWLY_AVAILABLE = 0x0000007A,
+    MTRDeviceTypeIDTypeOvenID MTR_NEWLY_AVAILABLE = 0x0000007B,
+    MTRDeviceTypeIDTypeLaundryDryerID MTR_NEWLY_AVAILABLE = 0x0000007C,
+    MTRDeviceTypeIDTypeNetworkInfrastructureManagerID MTR_NEWLY_AVAILABLE = 0x00000090,
+    MTRDeviceTypeIDTypeThreadBorderRouterID MTR_NEWLY_AVAILABLE = 0x00000091,
+    MTRDeviceTypeIDTypeOnOffLightID MTR_NEWLY_AVAILABLE = 0x00000100,
+    MTRDeviceTypeIDTypeDimmableLightID MTR_NEWLY_AVAILABLE = 0x00000101,
+    MTRDeviceTypeIDTypeOnOffLightSwitchID MTR_NEWLY_AVAILABLE = 0x00000103,
+    MTRDeviceTypeIDTypeDimmerSwitchID MTR_NEWLY_AVAILABLE = 0x00000104,
+    MTRDeviceTypeIDTypeColorDimmerSwitchID MTR_NEWLY_AVAILABLE = 0x00000105,
+    MTRDeviceTypeIDTypeLightSensorID MTR_NEWLY_AVAILABLE = 0x00000106,
+    MTRDeviceTypeIDTypeOccupancySensorID MTR_NEWLY_AVAILABLE = 0x00000107,
+    MTRDeviceTypeIDTypeOnOffPlugInUnitID MTR_NEWLY_AVAILABLE = 0x0000010A,
+    MTRDeviceTypeIDTypeDimmablePlugInUnitID MTR_NEWLY_AVAILABLE = 0x0000010B,
+    MTRDeviceTypeIDTypeColorTemperatureLightID MTR_NEWLY_AVAILABLE = 0x0000010C,
+    MTRDeviceTypeIDTypeExtendedColorLightID MTR_NEWLY_AVAILABLE = 0x0000010D,
+    MTRDeviceTypeIDTypeWindowCoveringID MTR_NEWLY_AVAILABLE = 0x00000202,
+    MTRDeviceTypeIDTypeWindowCoveringControllerID MTR_NEWLY_AVAILABLE = 0x00000203,
+    MTRDeviceTypeIDTypeHeatingCoolingUnitID MTR_NEWLY_AVAILABLE = 0x00000300,
+    MTRDeviceTypeIDTypeThermostatID MTR_NEWLY_AVAILABLE = 0x00000301,
+    MTRDeviceTypeIDTypeTemperatureSensorID MTR_NEWLY_AVAILABLE = 0x00000302,
+    MTRDeviceTypeIDTypePumpID MTR_NEWLY_AVAILABLE = 0x00000303,
+    MTRDeviceTypeIDTypePumpControllerID MTR_NEWLY_AVAILABLE = 0x00000304,
+    MTRDeviceTypeIDTypePressureSensorID MTR_NEWLY_AVAILABLE = 0x00000305,
+    MTRDeviceTypeIDTypeFlowSensorID MTR_NEWLY_AVAILABLE = 0x00000306,
+    MTRDeviceTypeIDTypeHumiditySensorID MTR_NEWLY_AVAILABLE = 0x00000307,
+    MTRDeviceTypeIDTypeEVSEID MTR_NEWLY_AVAILABLE = 0x0000050C,
+    MTRDeviceTypeIDTypeDeviceEnergyManagementID MTR_NEWLY_AVAILABLE = 0x0000050D,
+    MTRDeviceTypeIDTypeElectricalSensorID MTR_NEWLY_AVAILABLE = 0x00000510,
+    MTRDeviceTypeIDTypeControlBridgeID MTR_NEWLY_AVAILABLE = 0x00000840,
+    MTRDeviceTypeIDTypeOnOffSensorID MTR_NEWLY_AVAILABLE = 0x00000850,
+} MTR_NEWLY_AVAILABLE;
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm
index cadfa6a..f0530c4 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm
@@ -20,86 +20,74 @@
 using namespace chip;
 
 namespace {
-enum class DeviceTypeClass {
-    Utility,
-    Simple,
-    Node, // Might not be a real class, but we have it for Root Node for now.
-    // If new classes get added, plase audit MTRIsKnownUtilityDeviceType below.
-};
 
-struct DeviceTypeData {
-    DeviceTypeId id;
-    DeviceTypeClass deviceClass;
-    const char * name;
-};
-
-constexpr DeviceTypeData knownDeviceTypes[] = {
-    { 0x0000000A, DeviceTypeClass::Simple, "Door Lock" },
-    { 0x0000000B, DeviceTypeClass::Simple, "Door Lock Controller" },
-    { 0x0000000E, DeviceTypeClass::Simple, "Aggregator" },
-    { 0x0000000F, DeviceTypeClass::Simple, "Generic Switch" },
-    { 0x00000011, DeviceTypeClass::Utility, "Power Source" },
-    { 0x00000012, DeviceTypeClass::Utility, "OTA Requestor" },
-    { 0x00000013, DeviceTypeClass::Utility, "Bridged Node" },
-    { 0x00000014, DeviceTypeClass::Utility, "OTA Provider" },
-    { 0x00000015, DeviceTypeClass::Simple, "Contact Sensor" },
-    { 0x00000016, DeviceTypeClass::Node, "Root Node" },
-    { 0x00000019, DeviceTypeClass::Utility, "Secondary Network Interface" },
-    { 0x00000022, DeviceTypeClass::Simple, "Speaker" },
-    { 0x00000023, DeviceTypeClass::Simple, "Casting Video Player" },
-    { 0x00000024, DeviceTypeClass::Simple, "Content App" },
-    { 0x00000027, DeviceTypeClass::Simple, "Mode Select" },
-    { 0x00000028, DeviceTypeClass::Simple, "Basic Video Player" },
-    { 0x00000029, DeviceTypeClass::Simple, "Casting Video Client" },
-    { 0x0000002A, DeviceTypeClass::Simple, "Video Remote Control" },
-    { 0x0000002B, DeviceTypeClass::Simple, "Fan" },
-    { 0x0000002C, DeviceTypeClass::Simple, "Air Quality Sensor" },
-    { 0x0000002D, DeviceTypeClass::Simple, "Air Purifier" },
-    { 0x00000041, DeviceTypeClass::Simple, "Water Freeze Detector" },
-    { 0x00000042, DeviceTypeClass::Simple, "Water Valve" },
-    { 0x00000043, DeviceTypeClass::Simple, "Water Leak Detector" },
-    { 0x00000044, DeviceTypeClass::Simple, "Rain Sensor" },
-    { 0x00000070, DeviceTypeClass::Simple, "Refrigerator" },
-    { 0x00000071, DeviceTypeClass::Simple, "Temperature Controlled Cabinet" },
-    { 0x00000072, DeviceTypeClass::Simple, "Room Air Conditioner" },
-    { 0x00000073, DeviceTypeClass::Simple, "Laundry Washer" },
-    { 0x00000074, DeviceTypeClass::Simple, "Robotic Vacuum Cleaner" },
-    { 0x00000075, DeviceTypeClass::Simple, "Dishwasher" },
-    { 0x00000076, DeviceTypeClass::Simple, "Smoke CO Alarm" },
-    { 0x00000077, DeviceTypeClass::Simple, "Cook Surface" },
-    { 0x00000078, DeviceTypeClass::Simple, "Cooktop" },
-    { 0x00000079, DeviceTypeClass::Simple, "Microwave Oven" },
-    { 0x0000007A, DeviceTypeClass::Simple, "Extractor Hood" },
-    { 0x0000007B, DeviceTypeClass::Simple, "Oven" },
-    { 0x0000007C, DeviceTypeClass::Simple, "Laundry Dryer" },
-    { 0x00000090, DeviceTypeClass::Simple, "Network Infrastructure Manager" },
-    { 0x00000091, DeviceTypeClass::Simple, "Thread Border Router" },
-    { 0x00000100, DeviceTypeClass::Simple, "On/Off Light" },
-    { 0x00000101, DeviceTypeClass::Simple, "Dimmable Light" },
-    { 0x00000103, DeviceTypeClass::Simple, "On/Off Light Switch" },
-    { 0x00000104, DeviceTypeClass::Simple, "Dimmer Switch" },
-    { 0x00000105, DeviceTypeClass::Simple, "Color Dimmer Switch" },
-    { 0x00000106, DeviceTypeClass::Simple, "Light Sensor" },
-    { 0x00000107, DeviceTypeClass::Simple, "Occupancy Sensor" },
-    { 0x0000010A, DeviceTypeClass::Simple, "On/Off Plug-in Unit" },
-    { 0x0000010B, DeviceTypeClass::Simple, "Dimmable Plug-in Unit" },
-    { 0x0000010C, DeviceTypeClass::Simple, "Color Temperature Light" },
-    { 0x0000010D, DeviceTypeClass::Simple, "Extended Color Light" },
-    { 0x00000202, DeviceTypeClass::Simple, "Window Covering" },
-    { 0x00000203, DeviceTypeClass::Simple, "Window Covering Controller" },
-    { 0x00000300, DeviceTypeClass::Simple, "Heating/Cooling Unit" },
-    { 0x00000301, DeviceTypeClass::Simple, "Thermostat" },
-    { 0x00000302, DeviceTypeClass::Simple, "Temperature Sensor" },
-    { 0x00000303, DeviceTypeClass::Simple, "Pump" },
-    { 0x00000304, DeviceTypeClass::Simple, "Pump Controller" },
-    { 0x00000305, DeviceTypeClass::Simple, "Pressure Sensor" },
-    { 0x00000306, DeviceTypeClass::Simple, "Flow Sensor" },
-    { 0x00000307, DeviceTypeClass::Simple, "Humidity Sensor" },
-    { 0x0000050C, DeviceTypeClass::Simple, "EVSE" },
-    { 0x0000050D, DeviceTypeClass::Simple, "Device Energy Management" },
-    { 0x00000510, DeviceTypeClass::Utility, "Electrical Sensor" },
-    { 0x00000840, DeviceTypeClass::Simple, "Control Bridge" },
-    { 0x00000850, DeviceTypeClass::Simple, "On/Off Sensor" },
+constexpr MTRDeviceTypeData knownDeviceTypes[] = {
+    { 0x0000000A, MTRDeviceTypeClass::Simple, "Door Lock" },
+    { 0x0000000B, MTRDeviceTypeClass::Simple, "Door Lock Controller" },
+    { 0x0000000E, MTRDeviceTypeClass::Simple, "Aggregator" },
+    { 0x0000000F, MTRDeviceTypeClass::Simple, "Generic Switch" },
+    { 0x00000011, MTRDeviceTypeClass::Utility, "Power Source" },
+    { 0x00000012, MTRDeviceTypeClass::Utility, "OTA Requestor" },
+    { 0x00000013, MTRDeviceTypeClass::Utility, "Bridged Node" },
+    { 0x00000014, MTRDeviceTypeClass::Utility, "OTA Provider" },
+    { 0x00000015, MTRDeviceTypeClass::Simple, "Contact Sensor" },
+    { 0x00000016, MTRDeviceTypeClass::Node, "Root Node" },
+    { 0x00000019, MTRDeviceTypeClass::Utility, "Secondary Network Interface" },
+    { 0x00000022, MTRDeviceTypeClass::Simple, "Speaker" },
+    { 0x00000023, MTRDeviceTypeClass::Simple, "Casting Video Player" },
+    { 0x00000024, MTRDeviceTypeClass::Simple, "Content App" },
+    { 0x00000027, MTRDeviceTypeClass::Simple, "Mode Select" },
+    { 0x00000028, MTRDeviceTypeClass::Simple, "Basic Video Player" },
+    { 0x00000029, MTRDeviceTypeClass::Simple, "Casting Video Client" },
+    { 0x0000002A, MTRDeviceTypeClass::Simple, "Video Remote Control" },
+    { 0x0000002B, MTRDeviceTypeClass::Simple, "Fan" },
+    { 0x0000002C, MTRDeviceTypeClass::Simple, "Air Quality Sensor" },
+    { 0x0000002D, MTRDeviceTypeClass::Simple, "Air Purifier" },
+    { 0x00000041, MTRDeviceTypeClass::Simple, "Water Freeze Detector" },
+    { 0x00000042, MTRDeviceTypeClass::Simple, "Water Valve" },
+    { 0x00000043, MTRDeviceTypeClass::Simple, "Water Leak Detector" },
+    { 0x00000044, MTRDeviceTypeClass::Simple, "Rain Sensor" },
+    { 0x00000070, MTRDeviceTypeClass::Simple, "Refrigerator" },
+    { 0x00000071, MTRDeviceTypeClass::Simple, "Temperature Controlled Cabinet" },
+    { 0x00000072, MTRDeviceTypeClass::Simple, "Room Air Conditioner" },
+    { 0x00000073, MTRDeviceTypeClass::Simple, "Laundry Washer" },
+    { 0x00000074, MTRDeviceTypeClass::Simple, "Robotic Vacuum Cleaner" },
+    { 0x00000075, MTRDeviceTypeClass::Simple, "Dishwasher" },
+    { 0x00000076, MTRDeviceTypeClass::Simple, "Smoke CO Alarm" },
+    { 0x00000077, MTRDeviceTypeClass::Simple, "Cook Surface" },
+    { 0x00000078, MTRDeviceTypeClass::Simple, "Cooktop" },
+    { 0x00000079, MTRDeviceTypeClass::Simple, "Microwave Oven" },
+    { 0x0000007A, MTRDeviceTypeClass::Simple, "Extractor Hood" },
+    { 0x0000007B, MTRDeviceTypeClass::Simple, "Oven" },
+    { 0x0000007C, MTRDeviceTypeClass::Simple, "Laundry Dryer" },
+    { 0x00000090, MTRDeviceTypeClass::Simple, "Network Infrastructure Manager" },
+    { 0x00000091, MTRDeviceTypeClass::Simple, "Thread Border Router" },
+    { 0x00000100, MTRDeviceTypeClass::Simple, "On/Off Light" },
+    { 0x00000101, MTRDeviceTypeClass::Simple, "Dimmable Light" },
+    { 0x00000103, MTRDeviceTypeClass::Simple, "On/Off Light Switch" },
+    { 0x00000104, MTRDeviceTypeClass::Simple, "Dimmer Switch" },
+    { 0x00000105, MTRDeviceTypeClass::Simple, "Color Dimmer Switch" },
+    { 0x00000106, MTRDeviceTypeClass::Simple, "Light Sensor" },
+    { 0x00000107, MTRDeviceTypeClass::Simple, "Occupancy Sensor" },
+    { 0x0000010A, MTRDeviceTypeClass::Simple, "On/Off Plug-in Unit" },
+    { 0x0000010B, MTRDeviceTypeClass::Simple, "Dimmable Plug-in Unit" },
+    { 0x0000010C, MTRDeviceTypeClass::Simple, "Color Temperature Light" },
+    { 0x0000010D, MTRDeviceTypeClass::Simple, "Extended Color Light" },
+    { 0x00000202, MTRDeviceTypeClass::Simple, "Window Covering" },
+    { 0x00000203, MTRDeviceTypeClass::Simple, "Window Covering Controller" },
+    { 0x00000300, MTRDeviceTypeClass::Simple, "Heating/Cooling Unit" },
+    { 0x00000301, MTRDeviceTypeClass::Simple, "Thermostat" },
+    { 0x00000302, MTRDeviceTypeClass::Simple, "Temperature Sensor" },
+    { 0x00000303, MTRDeviceTypeClass::Simple, "Pump" },
+    { 0x00000304, MTRDeviceTypeClass::Simple, "Pump Controller" },
+    { 0x00000305, MTRDeviceTypeClass::Simple, "Pressure Sensor" },
+    { 0x00000306, MTRDeviceTypeClass::Simple, "Flow Sensor" },
+    { 0x00000307, MTRDeviceTypeClass::Simple, "Humidity Sensor" },
+    { 0x0000050C, MTRDeviceTypeClass::Simple, "EVSE" },
+    { 0x0000050D, MTRDeviceTypeClass::Simple, "Device Energy Management" },
+    { 0x00000510, MTRDeviceTypeClass::Utility, "Electrical Sensor" },
+    { 0x00000840, MTRDeviceTypeClass::Simple, "Control Bridge" },
+    { 0x00000850, MTRDeviceTypeClass::Simple, "On/Off Sensor" },
 };
 
 static_assert(ExtractVendorFromMEI(0xFFF10001) != 0, "Must have class defined for \"Orphan Clusters\" if it's a standard device type");
@@ -107,12 +95,12 @@
 
 } // anonymous namespace
 
-BOOL MTRIsKnownUtilityDeviceType(DeviceTypeId aDeviceTypeId)
+const MTRDeviceTypeData * _Nullable MTRDeviceTypeDataForID(chip::DeviceTypeId aDeviceTypeId)
 {
     for (auto & deviceType : knownDeviceTypes) {
         if (deviceType.id == aDeviceTypeId) {
-            return deviceType.deviceClass != DeviceTypeClass::Simple;
+            return &deviceType;
         }
     }
-    return NO;
+    return nullptr;
 }
diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m
new file mode 100644
index 0000000..7a41d42
--- /dev/null
+++ b/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m
@@ -0,0 +1,67 @@
+/**
+ *    Copyright (c) 2024 Project CHIP 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 <Matter/Matter.h>
+
+// system dependencies
+#import <XCTest/XCTest.h>
+
+@interface MTRDeviceTypeTests : XCTestCase
+
+@end
+
+@implementation MTRDeviceTypeTests
+
+- (void)testInvalidID
+{
+    __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(0x100000000)];
+    XCTAssertNil(deviceType);
+}
+
+- (void)testUnknownID
+{
+    __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(0xFFF15000)];
+    XCTAssertNil(deviceType);
+}
+
+- (void)testKnownNonUtilityID
+{
+    __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypeMicrowaveOvenID)];
+    XCTAssertNotNil(deviceType);
+    XCTAssertEqualObjects(deviceType.id, @(0x0079));
+    XCTAssertEqualObjects(deviceType.name, @"Microwave Oven");
+    XCTAssertFalse(deviceType.isUtility);
+}
+
+- (void)testKnownUtilityID
+{
+    __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypeRootNodeID)];
+    XCTAssertNotNil(deviceType);
+    XCTAssertEqualObjects(deviceType.id, @(0x0016));
+    XCTAssertEqualObjects(deviceType.name, @"Root Node");
+    XCTAssertTrue(deviceType.isUtility);
+}
+
+- (void)testRootNodeID
+{
+    __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypePowerSourceID)];
+    XCTAssertNotNil(deviceType);
+    XCTAssertEqualObjects(deviceType.id, @(0x0011));
+    XCTAssertEqualObjects(deviceType.name, @"Power Source");
+    XCTAssertTrue(deviceType.isUtility);
+}
+
+@end
diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
index e191785..ea5ef79 100644
--- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
+++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
@@ -129,6 +129,9 @@
 		3DFCB32C29678C9500332B35 /* MTRConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DFCB32B29678C9500332B35 /* MTRConversion.h */; };
 		51029DF6293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51029DF5293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm */; };
 		510470FB2A2F7DF60053EA7E /* MTRBackwardsCompatShims.mm in Sources */ = {isa = PBXBuildFile; fileRef = 510470FA2A2F7DF60053EA7E /* MTRBackwardsCompatShims.mm */; };
+		5109E9B42CB8B5DF0006884B /* MTRDeviceType.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5109E9B32CB8B5DF0006884B /* MTRDeviceType.mm */; };
+		5109E9B52CB8B5DF0006884B /* MTRDeviceType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5109E9B22CB8B5DF0006884B /* MTRDeviceType.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		5109E9B72CB8B83D0006884B /* MTRDeviceTypeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5109E9B62CB8B83D0006884B /* MTRDeviceTypeTests.m */; };
 		510A07492A685D3900A9241C /* Matter.apinotes in Headers */ = {isa = PBXBuildFile; fileRef = 510A07482A685D3900A9241C /* Matter.apinotes */; settings = {ATTRIBUTES = (Public, ); }; };
 		510CECA8297F72970064E0B3 /* MTROperationalCertificateIssuerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 510CECA6297F72470064E0B3 /* MTROperationalCertificateIssuerTests.m */; };
 		5117DD3829A931AE00FFA1AA /* MTROperationalBrowser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5117DD3629A931AD00FFA1AA /* MTROperationalBrowser.mm */; };
@@ -578,6 +581,9 @@
 		3DFCB32B29678C9500332B35 /* MTRConversion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRConversion.h; sourceTree = "<group>"; };
 		51029DF5293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROperationalCertificateIssuer.mm; sourceTree = "<group>"; };
 		510470FA2A2F7DF60053EA7E /* MTRBackwardsCompatShims.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRBackwardsCompatShims.mm; sourceTree = "<group>"; };
+		5109E9B22CB8B5DF0006884B /* MTRDeviceType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceType.h; sourceTree = "<group>"; };
+		5109E9B32CB8B5DF0006884B /* MTRDeviceType.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceType.mm; sourceTree = "<group>"; };
+		5109E9B62CB8B83D0006884B /* MTRDeviceTypeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceTypeTests.m; sourceTree = "<group>"; };
 		510A07482A685D3900A9241C /* Matter.apinotes */ = {isa = PBXFileReference; lastKnownFileType = text.apinotes; name = Matter.apinotes; path = CHIP/Matter.apinotes; sourceTree = "<group>"; };
 		510CECA6297F72470064E0B3 /* MTROperationalCertificateIssuerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTROperationalCertificateIssuerTests.m; sourceTree = "<group>"; };
 		5117DD3629A931AD00FFA1AA /* MTROperationalBrowser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROperationalBrowser.mm; sourceTree = "<group>"; };
@@ -1417,6 +1423,8 @@
 				754784662BFE6B890089C372 /* MTRDeviceStorageBehaviorConfiguration_Internal.h */,
 				754784642BFE65CB0089C372 /* MTRDeviceStorageBehaviorConfiguration.mm */,
 				51F522692AE70761000C4050 /* MTRDeviceTypeMetadata.h */,
+				5109E9B22CB8B5DF0006884B /* MTRDeviceType.h */,
+				5109E9B32CB8B5DF0006884B /* MTRDeviceType.mm */,
 				5129BCFC26A9EE3300122DDF /* MTRError.h */,
 				B2E0D7AB245B0B5C003C5B48 /* MTRError_Internal.h */,
 				B2E0D7AA245B0B5C003C5B48 /* MTRError.mm */,
@@ -1492,6 +1500,7 @@
 				51A2F1312A00402A00F03298 /* MTRDataValueParserTests.m */,
 				5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */,
 				75B326A12BCF12E900E17C4E /* MTRDeviceConnectivityMonitorTests.m */,
+				5109E9B62CB8B83D0006884B /* MTRDeviceTypeTests.m */,
 				51D9CB0A2BA37DCE0049D6DB /* MTRDSTOffsetTests.m */,
 				3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */,
 				5173A47829C0E82300F67F48 /* MTRFabricInfoTests.m */,
@@ -1801,6 +1810,7 @@
 				991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */,
 				51FE723F2ACDEF3E00437032 /* MTRCommandPayloadExtensions_Internal.h in Headers */,
 				51D0B12E2B6177FD006E3511 /* MTRAccessGrant.h in Headers */,
+				5109E9B52CB8B5DF0006884B /* MTRDeviceType.h in Headers */,
 				1E4D655029C208DD00BC3478 /* MTRCommissionableBrowserDelegate.h in Headers */,
 				7596A84828762783004DAE0E /* MTRAsyncCallbackWorkQueue.h in Headers */,
 				5A7947E527C0129F00434CF2 /* MTRDeviceController+XPC.h in Headers */,
@@ -2117,6 +2127,7 @@
 				513DDB8A2761F6F900DAA01A /* MTRAttributeTLVValueDecoder.mm in Sources */,
 				5117DD3829A931AE00FFA1AA /* MTROperationalBrowser.mm in Sources */,
 				514C79F02B62ADDA00DD6D7B /* descriptor.cpp in Sources */,
+				5109E9B42CB8B5DF0006884B /* MTRDeviceType.mm in Sources */,
 				3D843757294AD25A0070D20A /* MTRCertificateInfo.mm in Sources */,
 				5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.mm in Sources */,
 				5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.mm in Sources */,
@@ -2184,6 +2195,7 @@
 				5142E39829D377F000A206F0 /* MTROTAProviderTests.m in Sources */,
 				51E0FC102ACBBF230001E197 /* MTRSwiftDeviceTests.swift in Sources */,
 				3D4733AF2BDF1B80003DC19B /* MTRSetupPayloadTests.m in Sources */,
+				5109E9B72CB8B83D0006884B /* MTRDeviceTypeTests.m in Sources */,
 				51E24E73274E0DAC007CCF6E /* MTRErrorTestUtils.mm in Sources */,
 				519498322A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m in Sources */,
 				51A2F1322A00402A00F03298 /* MTRDataValueParserTests.m in Sources */,