From f8626ecdad4dc3e1c5eb421ce63e9ab5252ed991 Mon Sep 17 00:00:00 2001 From: jdomnitz <380352+jdomnitz@users.noreply.github.com> Date: Wed, 1 Jan 2025 00:41:16 -0500 Subject: [PATCH] Implement cluster inheritance, map fields and handle poor cluster definition consistency --- Generator/ClusterGenerator.cs | 111 +- Generator/Clusters/ColorControl.xml | 1028 +++++++++++++++ Generator/Clusters/Groups.xml | 197 +++ .../Label-Cluster-FixedLabelCluster.xml | 77 ++ .../Clusters/Label-Cluster-LabelCluster.xml | 88 ++ .../Label-Cluster-UserLabelCluster.xml | 78 ++ Generator/Clusters/LevelControl.xml | 319 +++++ ...s-BridgedDeviceBasicInformationCluster.xml | 162 +++ Generator/GeneratorUtil.cs | 10 + Generator/Schema/Cluster.cs | 39 +- .../Application/ColorControlCluster.cs | 1150 +++++++++++++++++ .../Application/LevelControlCluster.cs | 453 +++++++ .../Clusters/Application/On-OffCluster.cs | 7 + MatterDotNet/Clusters/ClusterBase.cs | 27 + MatterDotNet/Clusters/UnknownCluster.cs | 2 +- .../Clusters/Utility/AccessControlCluster.cs | 7 + .../AdministratorCommissioningCluster.cs | 7 + .../Utility/BasicInformationCluster.cs | 7 + .../BridgedDeviceBasicInformationCluster.cs | 41 + .../Clusters/Utility/DescriptorCluster.cs | 7 + .../Clusters/Utility/FixedLabelCluster.cs | 51 + .../Utility/GeneralCommissioningCluster.cs | 7 + .../Utility/GeneralDiagnosticsCluster.cs | 7 + .../Utility/GroupKeyManagementCluster.cs | 7 + .../Clusters/Utility/GroupsCluster.cs | 275 ++++ .../Clusters/Utility/IdentifyCluster.cs | 7 + MatterDotNet/Clusters/Utility/LabelCluster.cs | 63 + .../NodeOperationalCredentialsCluster.cs | 10 +- .../Clusters/Utility/UserLabelCluster.cs | 58 + 29 files changed, 4254 insertions(+), 48 deletions(-) create mode 100644 Generator/Clusters/ColorControl.xml create mode 100644 Generator/Clusters/Groups.xml create mode 100644 Generator/Clusters/Label-Cluster-FixedLabelCluster.xml create mode 100644 Generator/Clusters/Label-Cluster-LabelCluster.xml create mode 100644 Generator/Clusters/Label-Cluster-UserLabelCluster.xml create mode 100644 Generator/Clusters/LevelControl.xml create mode 100644 Generator/Clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml create mode 100644 MatterDotNet/Clusters/Application/ColorControlCluster.cs create mode 100644 MatterDotNet/Clusters/Application/LevelControlCluster.cs create mode 100644 MatterDotNet/Clusters/Utility/BridgedDeviceBasicInformationCluster.cs create mode 100644 MatterDotNet/Clusters/Utility/FixedLabelCluster.cs create mode 100644 MatterDotNet/Clusters/Utility/GroupsCluster.cs create mode 100644 MatterDotNet/Clusters/Utility/LabelCluster.cs create mode 100644 MatterDotNet/Clusters/Utility/UserLabelCluster.cs diff --git a/Generator/ClusterGenerator.cs b/Generator/ClusterGenerator.cs index 33a2834..64a1a5e 100644 --- a/Generator/ClusterGenerator.cs +++ b/Generator/ClusterGenerator.cs @@ -36,7 +36,8 @@ public static void Generate() Cluster? cluster = deserializer.Deserialize(File.OpenRead(clusterxml)) as Cluster; if (cluster == null) throw new IOException("Failed to parse cluster " + clusterxml); - clusterBase.WriteLine($" case {cluster.name.Replace(" ", "").Replace('/', '_')}.CLUSTER_ID:\n return new {cluster.name.Replace(" ", "").Replace('/', '_')}(endPoint);"); + if (!string.IsNullOrEmpty(cluster.clusterIds.clusterId.id)) + clusterBase.WriteLine($" case {cluster.name.Replace(" ", "").Replace('/', '_')}.CLUSTER_ID:\n return new {cluster.name.Replace(" ", "").Replace('/', '_')}(endPoint);"); WriteClass(cluster); } } @@ -71,24 +72,30 @@ private static void WriteClass(Cluster cluster) private static void WriteClass(Cluster cluster, TextWriter writer) { includes.Add("MatterDotNet.Protocol.Parsers"); - includes.Add("MatterDotNet.Protocol.Payloads"); includes.Add("MatterDotNet.Protocol.Sessions"); writer.WriteLine(); writer.WriteLine($"namespace MatterDotNet.Clusters.{GeneratorUtil.SanitizeName(cluster.classification.role) ?? "Misc"}\n{{"); writer.WriteLine(" /// "); writer.WriteLine($" /// {cluster.name}"); writer.WriteLine(" /// "); - writer.WriteLine($" [ClusterRevision(CLUSTER_ID, {cluster.revision})]"); - writer.WriteLine(" public class " + cluster.name.Replace(" ", "").Replace('/', '_') + " : ClusterBase"); + if (!string.IsNullOrEmpty(cluster.clusterIds.clusterId.id)) + writer.WriteLine($" [ClusterRevision(CLUSTER_ID, {cluster.revision})]"); + writer.WriteLine(" public class " + GeneratorUtil.SanitizeClassName(cluster.name) + (string.IsNullOrEmpty(cluster.classification.baseCluster) ? " : ClusterBase" : $" : {GeneratorUtil.SanitizeClassName(cluster.classification.baseCluster)}Cluster")); writer.WriteLine(" {"); - writer.WriteLine(" internal const uint CLUSTER_ID = " + cluster.clusterIds.clusterId.id + ";"); + if (!string.IsNullOrEmpty(cluster.clusterIds.clusterId.id)) + writer.WriteLine(" internal const uint CLUSTER_ID = " + cluster.clusterIds.clusterId.id + ";"); writer.WriteLine(); writer.WriteLine(" /// "); writer.WriteLine($" /// {cluster.name}"); writer.WriteLine(" /// "); - writer.WriteLine(" public " + cluster.name.Replace(" ", "").Replace('/', '_') + "(ushort endPoint) : base(CLUSTER_ID, endPoint) { }"); + if (string.IsNullOrEmpty(cluster.clusterIds.clusterId.id)) + writer.WriteLine(" public " + GeneratorUtil.SanitizeClassName(cluster.name) + "(uint cluster, ushort endPoint) : base(cluster, endPoint) { }"); + else + writer.WriteLine(" public " + GeneratorUtil.SanitizeClassName(cluster.name) + "(ushort endPoint) : base(CLUSTER_ID, endPoint) { }"); + if (string.IsNullOrEmpty(cluster.classification.baseCluster) && !string.IsNullOrEmpty(cluster.clusterIds.clusterId.id)) + writer.WriteLine($" /// \n protected {GeneratorUtil.SanitizeClassName(cluster.name)}(uint cluster, ushort endPoint) : base(cluster, endPoint) {{ }}"); writer.WriteLine(); - if (cluster.dataTypes.@enum != null || (cluster.features != null && cluster.features.Length > 0)) + if (cluster.dataTypes?.@enum != null || (cluster.features != null && cluster.features.Length > 0)) { writer.WriteLine(" #region Enums"); bool firstEnum=true; @@ -97,7 +104,7 @@ private static void WriteClass(Cluster cluster, TextWriter writer) firstEnum = false; WriteFeatures(cluster.features, writer); } - if (cluster.dataTypes.@enum != null) + if (cluster.dataTypes?.@enum != null) { foreach (clusterDataTypesEnum enumType in cluster.dataTypes.@enum) { @@ -110,7 +117,7 @@ private static void WriteClass(Cluster cluster, TextWriter writer) WriteEnum(enumType, writer); } } - if (cluster.dataTypes.bitmap != null) + if (cluster.dataTypes?.bitmap != null) { foreach (clusterDataTypesBitfield bitmapType in cluster.dataTypes.bitmap) { @@ -126,9 +133,10 @@ private static void WriteClass(Cluster cluster, TextWriter writer) writer.WriteLine(" #endregion Enums"); writer.WriteLine(); } - if (cluster.dataTypes.@struct != null) + if (cluster.dataTypes?.@struct != null) { includes.Add("System.Diagnostics.CodeAnalysis"); + includes.Add("MatterDotNet.Protocol.Payloads"); writer.WriteLine(" #region Records"); bool firstRecord = true; foreach (clusterDataTypesStruct structType in cluster.dataTypes.@struct) @@ -154,6 +162,7 @@ private static void WriteClass(Cluster cluster, TextWriter writer) { if (command.field == null) continue; + includes.Add("MatterDotNet.Protocol.Payloads"); if (firstPayload) firstPayload = false; else @@ -187,6 +196,7 @@ private static void WriteClass(Cluster cluster, TextWriter writer) } writer.WriteLine(" #endregion Attributes"); } + writer.WriteLine($"\n /// \n public override string ToString() {{\n return \"{cluster.name}\";\n }}"); writer.WriteLine(" }"); writer.Write("}"); writer.Flush(); @@ -221,7 +231,7 @@ private static void WriteStruct(clusterCommand command, bool toServer, TextWrite if (field.type.EndsWith("Enum")) writer.WriteLine(" = " + field.type + "." + field.@default + ";"); else - writer.WriteLine(" = " + SanitizeDefault(field.@default, "") + ";"); + writer.WriteLine(" = " + SanitizeDefault(field.@default, field.type) + ";"); } else writer.WriteLine(); @@ -234,8 +244,8 @@ private static void WriteStruct(clusterCommand command, bool toServer, TextWrite { if (field.type == null || field.disallowConform != null) //Reserved/removed fields continue; - int? from = null; - int? to = null; + long? from = null; + long? to = null; if (field.constraint != null) { switch (field.constraint.type) @@ -243,19 +253,21 @@ private static void WriteStruct(clusterCommand command, bool toServer, TextWrite case "min": case "minCount": case "minLength": - if (int.TryParse(field.constraint.value, out int fromVal)) + if (long.TryParse(field.constraint.value, out long fromVal)) from = fromVal; break; case "max": case "maxCount": case "maxLength": - if (int.TryParse(field.constraint.value, out int toVal)) + if (long.TryParse(field.constraint.value, out long toVal)) to = toVal; break; case "between": case "lengthBetween": - to = field.constraint.to; - from = field.constraint.from; + if (long.TryParse(field.constraint.to, out long parsedTo)) + to = parsedTo; + if (long.TryParse(field.constraint.from, out long parsedFrom)) + from = parsedFrom; break; case "desc": break; @@ -271,7 +283,7 @@ private static void WriteStruct(clusterCommand command, bool toServer, TextWrite writer.WriteLine(" }"); } - private static void WriteStructType(bool optional, bool nullable, string type, string? entryType, int id, int? from, int? to, string name, Cluster cluster, TextWriter writer) + private static void WriteStructType(bool optional, bool nullable, string type, string? entryType, int id, long? from, long? to, string name, Cluster cluster, TextWriter writer) { string totalIndent = " "; if (optional) @@ -356,6 +368,7 @@ private static void WriteStructType(bool optional, bool nullable, string type, s break; case "uint8": case "enum8": + case "map8": case "tag": case "namespace": case "fabric-idx": @@ -371,6 +384,7 @@ private static void WriteStructType(bool optional, bool nullable, string type, s writer.WriteLine(");"); return; case "uint16": + case "map16": case "enum16": case "group-id": case "endpoint-no": @@ -389,6 +403,7 @@ private static void WriteStructType(bool optional, bool nullable, string type, s return; case "uint24": case "uint32": + case "map32": case "epoch-s": case "cluster-id": case "attrib-id": @@ -441,6 +456,7 @@ private static void WriteStructType(bool optional, bool nullable, string type, s case "uint48": case "uint56": case "uint64": + case "map64": case "epoch-us": case "fabric-id": case "node-id": @@ -506,7 +522,7 @@ private static void WriteStructType(bool optional, bool nullable, string type, s writer.WriteLine(");"); } - private static void WriteFieldReader(bool optional, bool nullable, string type, string? entryType, string id, int? from, int? to, string name, string structName, Cluster cluster, TextWriter writer) + private static void WriteFieldReader(bool optional, bool nullable, string type, string? entryType, string id, long? from, long? to, string name, string structName, Cluster cluster, TextWriter writer) { string totalIndent = " "; if (id != "-1" && type != "list" && id != "i") @@ -558,6 +574,7 @@ private static void WriteFieldReader(bool optional, bool nullable, string type, break; case "uint8": case "enum8": + case "map8": case "tag": case "namespace": case "fabric-idx": @@ -566,6 +583,7 @@ private static void WriteFieldReader(bool optional, bool nullable, string type, break; case "uint16": case "enum16": + case "map16": case "group-id": case "endpoint-no": case "vendor-id": @@ -575,6 +593,7 @@ private static void WriteFieldReader(bool optional, bool nullable, string type, break; case "uint24": case "uint32": + case "map32": case "epoch-s": case "cluster-id": case "attrib-id": @@ -589,6 +608,7 @@ private static void WriteFieldReader(bool optional, bool nullable, string type, case "uint48": case "uint56": case "uint64": + case "map64": case "epoch-us": case "fabric-id": case "node-id": @@ -913,8 +933,15 @@ private static void WriteStruct(clusterDataTypesStruct structType, Cluster clust writer.WriteLine($" internal {GeneratorUtil.SanitizeName(structType.name)}(object[] fields) {{"); writer.WriteLine(" FieldReader reader = new FieldReader(fields);"); foreach (clusterDataTypesStructField field in structType.field) - WriteFieldReader(field.mandatoryConform == null, field.quality?.nullable == true, field.type, field.entry?.type, field.id.ToString(), field.constraint?.fromSpecified == true ? field.constraint.from : null, field.constraint?.toSpecified == true ? field.constraint.to : null, field.name, structType.name, cluster, writer); - + { + long? to = null; + long? from = null; + if (field.constraint?.toSpecified == true && long.TryParse(field.constraint.to, out long toVal)) + to = toVal; + if (field.constraint?.fromSpecified == true && long.TryParse(field.constraint.from, out long fromVal)) + from = fromVal; + WriteFieldReader(field.mandatoryConform == null, field.quality?.nullable == true, field.type, field.entry?.type, field.id.ToString(), from, to, field.name, structType.name, cluster, writer); + } writer.WriteLine(" }"); foreach (clusterDataTypesStructField field in structType.field) { @@ -938,7 +965,7 @@ private static void WriteStruct(clusterDataTypesStruct structType, Cluster clust if (HasEnum(cluster, field.type) || HasBitmap(cluster, field.type)) writer.WriteLine(" = " + field.type + "." + field.@default + ";"); else - writer.WriteLine(" = " + SanitizeDefault(field.@default!, "") + ";"); + writer.WriteLine(" = " + SanitizeDefault(field.@default!, field.type) + ";"); } else writer.WriteLine(); @@ -947,8 +974,8 @@ private static void WriteStruct(clusterDataTypesStruct structType, Cluster clust writer.WriteLine(" writer.StartStructure(structNumber);"); foreach (clusterDataTypesStructField field in structType.field) { - int? from = null; - int? to = null; + long? from = null; + long? to = null; if (field.constraint != null) { switch (field.constraint.type) @@ -956,19 +983,21 @@ private static void WriteStruct(clusterDataTypesStruct structType, Cluster clust case "min": case "minCount": case "minLength": - if (int.TryParse(field.constraint.value, out int fromVal)) + if (long.TryParse(field.constraint.value, out long fromVal)) from = fromVal; break; case "max": case "maxCount": case "maxLength": - if (int.TryParse(field.constraint.value, out int toVal)) + if (long.TryParse(field.constraint.value, out long toVal)) to = toVal; break; case "between": case "lengthBetween": - to = field.constraint.to; - from = field.constraint.from; + if (long.TryParse(field.constraint.from, out long parsedFrom)) + from = parsedFrom; + if (long.TryParse(field.constraint.to, out long parsedTo)) + to = parsedTo; break; case "desc": break; @@ -1029,7 +1058,7 @@ private static void WriteFeatures(clusterFeature[] features, TextWriter writer) foreach (clusterFeature item in features) { writer.WriteLine(" /// \n /// " + item.summary.Replace("[[ref_", "") + "\n /// "); - writer.WriteLine(" " + item.name + " = " + (1 << item.bit) + ","); + writer.WriteLine(" " + GeneratorUtil.SanitizeName(item.name) + " = " + (1 << item.bit) + ","); } writer.WriteLine(" }"); } @@ -1041,7 +1070,7 @@ private static void WriteAttribute(Cluster cluster, clusterAttribute attribute, hasDefault = false; if (hasDefault && HasBitmap(cluster, attribute.type) && !HasBitmapValue(cluster, attribute.type, attribute.@default!)) hasDefault = false; - if (attribute.access.read) + if (attribute?.access?.read == true) { writer.WriteLine($" /// \n /// Get the {GeneratorUtil.FieldNameToComment(attribute.name)} attribute\n /// "); writer.Write(" public async Task<"); @@ -1063,7 +1092,13 @@ private static void WriteAttribute(Cluster cluster, clusterAttribute attribute, writer.WriteLine($" FieldReader reader = new FieldReader((IList)(await GetAttribute(session, {Convert.ToUInt16(attribute.id, 16)}))!);"); writer.WriteLine(" for (int i = 0; i < reader.Count; i++)"); writer.Write(" list.Add("); - WriteFieldReader(false, false, attribute.entry!.type, null, "i", attribute.constraint?.from, attribute.constraint?.to, "", "", cluster, writer); + long? from = null; + long? to = null; + if (attribute.constraint?.fromSpecified == true && long.TryParse(attribute.constraint.from, out long fromVal)) + from = fromVal; + if (attribute.constraint?.toSpecified == true && long.TryParse(attribute.constraint.to, out long toVal)) + to = toVal; + WriteFieldReader(false, false, attribute.entry!.type, null, "i", from, to, "", "", cluster, writer); writer.Write(" return list"); hasDefault = false; } @@ -1085,7 +1120,7 @@ private static void WriteAttribute(Cluster cluster, clusterAttribute attribute, if (attribute.quality?.nullable == true) writer.Write(", true"); writer.Write(')'); - if (!HasEnum(cluster, attribute.type) && (attribute.quality?.nullable != true && !hasDefault)) + if (!HasEnum(cluster, attribute.type) && !HasBitmap(cluster, attribute.type) && (attribute.quality?.nullable != true && !hasDefault)) writer.Write(")!"); } @@ -1100,7 +1135,7 @@ private static void WriteAttribute(Cluster cluster, clusterAttribute attribute, writer.WriteLine(";"); writer.WriteLine(" }"); } - if (attribute.access.write) + if (attribute?.access?.write == true) { if (attribute.access.read) writer.WriteLine(); @@ -1134,6 +1169,7 @@ private static void WriteType(string type, string? entryType, TextWriter writer) { case "uint8": case "enum8": + case "map8": case "tag": case "namespace": case "fabric-idx": @@ -1141,6 +1177,7 @@ private static void WriteType(string type, string? entryType, TextWriter writer) writer.Write("byte"); break; case "uint16": + case "map16": case "enum16": case "group-id": case "endpoint-no": @@ -1154,6 +1191,7 @@ private static void WriteType(string type, string? entryType, TextWriter writer) break; case "uint24": case "uint32": + case "map32": case "epoch-s": case "cluster-id": case "attrib-id": @@ -1176,6 +1214,7 @@ private static void WriteType(string type, string? entryType, TextWriter writer) case "uint48": case "uint56": case "uint64": + case "map64": case "epoch-us": case "fabric-id": case "node-id": @@ -1263,8 +1302,12 @@ private static string SanitizeDefault(string value, string? type = null, string? sw.Write("()"); return sb.ToString(); } + else if (type?.Equals("string", StringComparison.InvariantCultureIgnoreCase) == true) + return "\"\""; return "[]"; } + if (value.StartsWith("0x")) + return value.Split(' ')[0]; if (value.StartsWith('"')) return value; else @@ -1277,6 +1320,8 @@ private static bool DefaultValid(string value) return false; if (value.Equals("desc", StringComparison.InvariantCultureIgnoreCase)) return false; + if (value == "-") + return false; return true; } } diff --git a/Generator/Clusters/ColorControl.xml b/Generator/Clusters/ColorControl.xml new file mode 100644 index 0000000..e145ee6 --- /dev/null +++ b/Generator/Clusters/ColorControl.xml @@ -0,0 +1,1028 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/Groups.xml b/Generator/Clusters/Groups.xml new file mode 100644 index 0000000..02b08c4 --- /dev/null +++ b/Generator/Clusters/Groups.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/Label-Cluster-FixedLabelCluster.xml b/Generator/Clusters/Label-Cluster-FixedLabelCluster.xml new file mode 100644 index 0000000..4198b53 --- /dev/null +++ b/Generator/Clusters/Label-Cluster-FixedLabelCluster.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/Label-Cluster-LabelCluster.xml b/Generator/Clusters/Label-Cluster-LabelCluster.xml new file mode 100644 index 0000000..b0b8b54 --- /dev/null +++ b/Generator/Clusters/Label-Cluster-LabelCluster.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/Label-Cluster-UserLabelCluster.xml b/Generator/Clusters/Label-Cluster-UserLabelCluster.xml new file mode 100644 index 0000000..8b3f1fd --- /dev/null +++ b/Generator/Clusters/Label-Cluster-UserLabelCluster.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/LevelControl.xml b/Generator/Clusters/LevelControl.xml new file mode 100644 index 0000000..7bd3738 --- /dev/null +++ b/Generator/Clusters/LevelControl.xml @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/Clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml b/Generator/Clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml new file mode 100644 index 0000000..4d13a8f --- /dev/null +++ b/Generator/Clusters/bridge-clusters-BridgedDeviceBasicInformationCluster.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Generator/GeneratorUtil.cs b/Generator/GeneratorUtil.cs index 33d09c5..3bc2cf2 100644 --- a/Generator/GeneratorUtil.cs +++ b/Generator/GeneratorUtil.cs @@ -26,6 +26,11 @@ public static string SanitizeName(string name) { if (c == ' ' || c == '-') cap = true; + else if (c == '/') + { + cap = true; + ret.Append('_'); + } else if (cap) { ret.Append(char.ToUpper(c)); @@ -37,6 +42,11 @@ public static string SanitizeName(string name) return ret.ToString(); } + public static string SanitizeClassName(string name) + { + return name.Replace(" ", "").Replace('/', '_').Replace("-", ""); + } + public static string FieldNameToComment(string name) { if (name.EndsWith("struct", StringComparison.InvariantCultureIgnoreCase)) diff --git a/Generator/Schema/Cluster.cs b/Generator/Schema/Cluster.cs index 32e03f2..30c4e57 100644 --- a/Generator/Schema/Cluster.cs +++ b/Generator/Schema/Cluster.cs @@ -310,6 +310,7 @@ public string name [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class clusterClassification { + private string baseClusterField; private string hierarchyField; @@ -319,6 +320,20 @@ public partial class clusterClassification private string scopeField; + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string baseCluster + { + get + { + return this.baseClusterField; + } + set + { + this.baseClusterField = value; + } + } + /// [System.Xml.Serialization.XmlAttributeAttribute()] public string hierarchy @@ -1036,8 +1051,8 @@ public bool nullable [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class clusterDataTypesStructFieldConstraint { - private int toField; - private int fromField; + private string toField; + private string fromField; private bool fromFieldSpecified; private bool toFieldSpecified; @@ -1049,7 +1064,7 @@ public partial class clusterDataTypesStructFieldConstraint /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int from + public string from { get { @@ -1077,7 +1092,7 @@ public bool fromSpecified /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int to + public string to { get { @@ -1647,11 +1662,11 @@ public partial class clusterAttributeConstraint private string valueField; - private int fromField; + private string fromField; private bool fromFieldSpecified; - private int toField; + private string toField; private bool toFieldSpecified; @@ -1685,7 +1700,7 @@ public string value /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int from + public string from { get { @@ -1713,7 +1728,7 @@ public bool fromSpecified /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int to + public string to { get { @@ -2153,11 +2168,11 @@ public partial class clusterCommandFieldConstraint private string valueField; - private int fromField; + private string fromField; private bool fromFieldSpecified; - private int toField; + private string toField; private bool toFieldSpecified; @@ -2191,7 +2206,7 @@ public string value /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int from + public string from { get { @@ -2219,7 +2234,7 @@ public bool fromSpecified /// [System.Xml.Serialization.XmlAttributeAttribute()] - public int to + public string to { get { diff --git a/MatterDotNet/Clusters/Application/ColorControlCluster.cs b/MatterDotNet/Clusters/Application/ColorControlCluster.cs new file mode 100644 index 0000000..8ffc565 --- /dev/null +++ b/MatterDotNet/Clusters/Application/ColorControlCluster.cs @@ -0,0 +1,1150 @@ +// MatterDotNet Copyright (C) 2025 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// WARNING: This file was auto-generated. Do not edit. + +using MatterDotNet.Messages.InteractionModel; +using MatterDotNet.Protocol.Parsers; +using MatterDotNet.Protocol.Payloads; +using MatterDotNet.Protocol.Sessions; +using MatterDotNet.Protocol.Subprotocols; + +namespace MatterDotNet.Clusters.Application +{ + /// + /// Color Control Cluster + /// + [ClusterRevision(CLUSTER_ID, 6)] + public class ColorControlCluster : ClusterBase + { + internal const uint CLUSTER_ID = 0x0300; + + /// + /// Color Control Cluster + /// + public ColorControlCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected ColorControlCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } + + #region Enums + /// + /// Supported Features + /// + [Flags] + public enum Feature { + /// + /// Supports color specification via hue/saturation. + /// + HueSaturation = 1, + /// + /// Enhanced hue is supported. + /// + Enhanced = 2, + /// + /// Color loop is supported. + /// + Color = 4, + /// + /// Supports color specification via XY. + /// + XY = 8, + /// + /// Supports specification of color temperature. + /// + Color2 = 16, + } + #endregion Enums + + #region Payloads + private record MoveToHuePayload : TLVPayload { + public required byte Hue { get; set; } + public required byte Direction { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, Hue, 254); + writer.WriteByte(1, Direction); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveHuePayload : TLVPayload { + public required byte MoveMode { get; set; } + public required byte Rate { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, MoveMode); + writer.WriteByte(1, Rate); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record StepHuePayload : TLVPayload { + public required byte StepMode { get; set; } + public required byte StepSize { get; set; } + public required byte TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, StepMode); + writer.WriteByte(1, StepSize); + writer.WriteByte(2, TransitionTime); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveToSaturationPayload : TLVPayload { + public required byte Saturation { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, Saturation, 254); + writer.WriteUShort(1, TransitionTime, 65534); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveSaturationPayload : TLVPayload { + public required byte MoveMode { get; set; } + public required byte Rate { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, MoveMode); + writer.WriteByte(1, Rate); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record StepSaturationPayload : TLVPayload { + public required byte StepMode { get; set; } + public required byte StepSize { get; set; } + public required byte TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, StepMode); + writer.WriteByte(1, StepSize); + writer.WriteByte(2, TransitionTime); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveToHueAndSaturationPayload : TLVPayload { + public required byte Hue { get; set; } + public required byte Saturation { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, Hue, 254); + writer.WriteByte(1, Saturation, 254); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveToColorPayload : TLVPayload { + public required ushort ColorX { get; set; } + public required ushort ColorY { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, ColorX); + writer.WriteUShort(1, ColorY); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveColorPayload : TLVPayload { + public required short RateX { get; set; } + public required short RateY { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteShort(0, RateX); + writer.WriteShort(1, RateY); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record StepColorPayload : TLVPayload { + public required short StepX { get; set; } + public required short StepY { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteShort(0, StepX); + writer.WriteShort(1, StepY); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveToColorTemperaturePayload : TLVPayload { + public required ushort ColorTemperatureMireds { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, ColorTemperatureMireds); + writer.WriteUShort(1, TransitionTime, 65534); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record EnhancedMoveToHuePayload : TLVPayload { + public required ushort EnhancedHue { get; set; } + public required byte Direction { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, EnhancedHue); + writer.WriteByte(1, Direction); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record EnhancedMoveHuePayload : TLVPayload { + public required byte MoveMode { get; set; } + public required ushort Rate { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, MoveMode); + writer.WriteUShort(1, Rate); + writer.WriteByte(2, OptionsMask); + writer.WriteByte(3, OptionsOverride); + writer.EndContainer(); + } + } + + private record EnhancedStepHuePayload : TLVPayload { + public required byte StepMode { get; set; } + public required ushort StepSize { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, StepMode); + writer.WriteUShort(1, StepSize); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record EnhancedMoveToHueAndSaturationPayload : TLVPayload { + public required ushort EnhancedHue { get; set; } + public required byte Saturation { get; set; } + public required ushort TransitionTime { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, EnhancedHue); + writer.WriteByte(1, Saturation, 254); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteByte(3, OptionsMask); + writer.WriteByte(4, OptionsOverride); + writer.EndContainer(); + } + } + + private record ColorLoopSetPayload : TLVPayload { + public required byte UpdateFlags { get; set; } + public required byte Action { get; set; } + public required byte Direction { get; set; } + public required ushort Time { get; set; } + public required ushort StartHue { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, UpdateFlags); + writer.WriteByte(1, Action); + writer.WriteByte(2, Direction); + writer.WriteUShort(3, Time); + writer.WriteUShort(4, StartHue); + writer.WriteByte(5, OptionsMask); + writer.WriteByte(6, OptionsOverride); + writer.EndContainer(); + } + } + + private record StopMoveStepPayload : TLVPayload { + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, OptionsMask); + writer.WriteByte(1, OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveColorTemperaturePayload : TLVPayload { + public required byte MoveMode { get; set; } + public required ushort Rate { get; set; } + public required ushort ColorTemperatureMinimumMireds { get; set; } + public required ushort ColorTemperatureMaximumMireds { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, MoveMode); + writer.WriteUShort(1, Rate); + writer.WriteUShort(2, ColorTemperatureMinimumMireds); + writer.WriteUShort(3, ColorTemperatureMaximumMireds); + writer.WriteByte(4, OptionsMask); + writer.WriteByte(5, OptionsOverride); + writer.EndContainer(); + } + } + + private record StepColorTemperaturePayload : TLVPayload { + public required byte StepMode { get; set; } + public required ushort StepSize { get; set; } + public required ushort TransitionTime { get; set; } + public required ushort ColorTemperatureMinimumMireds { get; set; } + public required ushort ColorTemperatureMaximumMireds { get; set; } + public required byte OptionsMask { get; set; } = 0; + public required byte OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, StepMode); + writer.WriteUShort(1, StepSize); + writer.WriteUShort(2, TransitionTime, 65534); + writer.WriteUShort(3, ColorTemperatureMinimumMireds); + writer.WriteUShort(4, ColorTemperatureMaximumMireds); + writer.WriteByte(5, OptionsMask); + writer.WriteByte(6, OptionsOverride); + writer.EndContainer(); + } + } + #endregion Payloads + + #region Commands + /// + /// Move To Hue + /// + public async Task MoveToHue(SecureSession session, byte Hue, byte Direction, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + MoveToHuePayload requestFields = new MoveToHuePayload() { + Hue = Hue, + Direction = Direction, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x00, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move Hue + /// + public async Task MoveHue(SecureSession session, byte MoveMode, byte Rate, byte OptionsMask, byte OptionsOverride) { + MoveHuePayload requestFields = new MoveHuePayload() { + MoveMode = MoveMode, + Rate = Rate, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x01, requestFields); + return ValidateResponse(resp); + } + + /// + /// Step Hue + /// + public async Task StepHue(SecureSession session, byte StepMode, byte StepSize, byte TransitionTime, byte OptionsMask, byte OptionsOverride) { + StepHuePayload requestFields = new StepHuePayload() { + StepMode = StepMode, + StepSize = StepSize, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x02, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move To Saturation + /// + public async Task MoveToSaturation(SecureSession session, byte Saturation, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + MoveToSaturationPayload requestFields = new MoveToSaturationPayload() { + Saturation = Saturation, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x03, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move Saturation + /// + public async Task MoveSaturation(SecureSession session, byte MoveMode, byte Rate, byte OptionsMask, byte OptionsOverride) { + MoveSaturationPayload requestFields = new MoveSaturationPayload() { + MoveMode = MoveMode, + Rate = Rate, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x04, requestFields); + return ValidateResponse(resp); + } + + /// + /// Step Saturation + /// + public async Task StepSaturation(SecureSession session, byte StepMode, byte StepSize, byte TransitionTime, byte OptionsMask, byte OptionsOverride) { + StepSaturationPayload requestFields = new StepSaturationPayload() { + StepMode = StepMode, + StepSize = StepSize, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x05, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move To Hue And Saturation + /// + public async Task MoveToHueAndSaturation(SecureSession session, byte Hue, byte Saturation, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + MoveToHueAndSaturationPayload requestFields = new MoveToHueAndSaturationPayload() { + Hue = Hue, + Saturation = Saturation, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x06, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move To Color + /// + public async Task MoveToColor(SecureSession session, ushort ColorX, ushort ColorY, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + MoveToColorPayload requestFields = new MoveToColorPayload() { + ColorX = ColorX, + ColorY = ColorY, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x07, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move Color + /// + public async Task MoveColor(SecureSession session, short RateX, short RateY, byte OptionsMask, byte OptionsOverride) { + MoveColorPayload requestFields = new MoveColorPayload() { + RateX = RateX, + RateY = RateY, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x08, requestFields); + return ValidateResponse(resp); + } + + /// + /// Step Color + /// + public async Task StepColor(SecureSession session, short StepX, short StepY, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + StepColorPayload requestFields = new StepColorPayload() { + StepX = StepX, + StepY = StepY, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x09, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move To Color Temperature + /// + public async Task MoveToColorTemperature(SecureSession session, ushort ColorTemperatureMireds, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + MoveToColorTemperaturePayload requestFields = new MoveToColorTemperaturePayload() { + ColorTemperatureMireds = ColorTemperatureMireds, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x0A, requestFields); + return ValidateResponse(resp); + } + + /// + /// Enhanced Move To Hue + /// + public async Task EnhancedMoveToHue(SecureSession session, ushort EnhancedHue, byte Direction, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + EnhancedMoveToHuePayload requestFields = new EnhancedMoveToHuePayload() { + EnhancedHue = EnhancedHue, + Direction = Direction, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x40, requestFields); + return ValidateResponse(resp); + } + + /// + /// Enhanced Move Hue + /// + public async Task EnhancedMoveHue(SecureSession session, byte MoveMode, ushort Rate, byte OptionsMask, byte OptionsOverride) { + EnhancedMoveHuePayload requestFields = new EnhancedMoveHuePayload() { + MoveMode = MoveMode, + Rate = Rate, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x41, requestFields); + return ValidateResponse(resp); + } + + /// + /// Enhanced Step Hue + /// + public async Task EnhancedStepHue(SecureSession session, byte StepMode, ushort StepSize, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + EnhancedStepHuePayload requestFields = new EnhancedStepHuePayload() { + StepMode = StepMode, + StepSize = StepSize, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x42, requestFields); + return ValidateResponse(resp); + } + + /// + /// Enhanced Move To Hue And Saturation + /// + public async Task EnhancedMoveToHueAndSaturation(SecureSession session, ushort EnhancedHue, byte Saturation, ushort TransitionTime, byte OptionsMask, byte OptionsOverride) { + EnhancedMoveToHueAndSaturationPayload requestFields = new EnhancedMoveToHueAndSaturationPayload() { + EnhancedHue = EnhancedHue, + Saturation = Saturation, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x43, requestFields); + return ValidateResponse(resp); + } + + /// + /// Color Loop Set + /// + public async Task ColorLoopSet(SecureSession session, byte UpdateFlags, byte Action, byte Direction, ushort Time, ushort StartHue, byte OptionsMask, byte OptionsOverride) { + ColorLoopSetPayload requestFields = new ColorLoopSetPayload() { + UpdateFlags = UpdateFlags, + Action = Action, + Direction = Direction, + Time = Time, + StartHue = StartHue, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x44, requestFields); + return ValidateResponse(resp); + } + + /// + /// Stop Move Step + /// + public async Task StopMoveStep(SecureSession session, byte OptionsMask, byte OptionsOverride) { + StopMoveStepPayload requestFields = new StopMoveStepPayload() { + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x47, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move Color Temperature + /// + public async Task MoveColorTemperature(SecureSession session, byte MoveMode, ushort Rate, ushort ColorTemperatureMinimumMireds, ushort ColorTemperatureMaximumMireds, byte OptionsMask, byte OptionsOverride) { + MoveColorTemperaturePayload requestFields = new MoveColorTemperaturePayload() { + MoveMode = MoveMode, + Rate = Rate, + ColorTemperatureMinimumMireds = ColorTemperatureMinimumMireds, + ColorTemperatureMaximumMireds = ColorTemperatureMaximumMireds, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x4B, requestFields); + return ValidateResponse(resp); + } + + /// + /// Step Color Temperature + /// + public async Task StepColorTemperature(SecureSession session, byte StepMode, ushort StepSize, ushort TransitionTime, ushort ColorTemperatureMinimumMireds, ushort ColorTemperatureMaximumMireds, byte OptionsMask, byte OptionsOverride) { + StepColorTemperaturePayload requestFields = new StepColorTemperaturePayload() { + StepMode = StepMode, + StepSize = StepSize, + TransitionTime = TransitionTime, + ColorTemperatureMinimumMireds = ColorTemperatureMinimumMireds, + ColorTemperatureMaximumMireds = ColorTemperatureMaximumMireds, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x4C, requestFields); + return ValidateResponse(resp); + } + #endregion Commands + + #region Attributes + /// + /// Features supported by this cluster + /// + /// + /// + public async Task GetSupportedFeatures(SecureSession session) + { + return (Feature)(byte)(await GetAttribute(session, 0xFFFC))!; + } + + /// + /// Returns true when the feature is supported by the cluster + /// + /// + /// + /// + public async Task Supports(SecureSession session, Feature feature) + { + return ((feature & await GetSupportedFeatures(session)) != 0); + } + + /// + /// Get the Current Hue attribute + /// + public async Task GetCurrentHue(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 0) ?? 0; + } + + /// + /// Get the Current Saturation attribute + /// + public async Task GetCurrentSaturation(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 1) ?? 0; + } + + /// + /// Get the Remaining Time attribute + /// + public async Task GetRemainingTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 2) ?? 0; + } + + /// + /// Get the CurrentX attribute + /// + public async Task GetCurrentX(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 3) ?? 0x616B; + } + + /// + /// Get the CurrentY attribute + /// + public async Task GetCurrentY(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 4) ?? 0x607D; + } + + /// + /// Get the Drift Compensation attribute + /// + public async Task GetDriftCompensation(SecureSession session) { + return (byte)(dynamic?)(await GetAttribute(session, 5))!; + } + + /// + /// Get the Compensation Text attribute + /// + public async Task GetCompensationText(SecureSession session) { + return (string)(dynamic?)(await GetAttribute(session, 6))!; + } + + /// + /// Get the Color Temperature Mireds attribute + /// + public async Task GetColorTemperatureMireds(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 7) ?? 0x00FA; + } + + /// + /// Get the Color Mode attribute + /// + public async Task GetColorMode(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 8) ?? 1; + } + + /// + /// Get the Options attribute + /// + public async Task GetOptions(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 15) ?? 0; + } + + /// + /// Set the Options attribute + /// + public async Task SetOptions (SecureSession session, byte? value = 0) { + await SetAttribute(session, 15, value); + } + + /// + /// Get the Number Of Primaries attribute + /// + public async Task GetNumberOfPrimaries(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 16, true); + } + + /// + /// Get the Primary1X attribute + /// + public async Task GetPrimary1X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 17))!; + } + + /// + /// Get the Primary1Y attribute + /// + public async Task GetPrimary1Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 18))!; + } + + /// + /// Get the Primary1 Intensity attribute + /// + public async Task GetPrimary1Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 19, true); + } + + /// + /// Get the Primary2X attribute + /// + public async Task GetPrimary2X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 21))!; + } + + /// + /// Get the Primary2Y attribute + /// + public async Task GetPrimary2Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 22))!; + } + + /// + /// Get the Primary2 Intensity attribute + /// + public async Task GetPrimary2Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 23, true); + } + + /// + /// Get the Primary3X attribute + /// + public async Task GetPrimary3X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 25))!; + } + + /// + /// Get the Primary3Y attribute + /// + public async Task GetPrimary3Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 26))!; + } + + /// + /// Get the Primary3 Intensity attribute + /// + public async Task GetPrimary3Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 27, true); + } + + /// + /// Get the Primary4X attribute + /// + public async Task GetPrimary4X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 32))!; + } + + /// + /// Get the Primary4Y attribute + /// + public async Task GetPrimary4Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 33))!; + } + + /// + /// Get the Primary4 Intensity attribute + /// + public async Task GetPrimary4Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 34, true); + } + + /// + /// Get the Primary5X attribute + /// + public async Task GetPrimary5X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 36))!; + } + + /// + /// Get the Primary5Y attribute + /// + public async Task GetPrimary5Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 37))!; + } + + /// + /// Get the Primary5 Intensity attribute + /// + public async Task GetPrimary5Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 38, true); + } + + /// + /// Get the Primary6X attribute + /// + public async Task GetPrimary6X(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 40))!; + } + + /// + /// Get the Primary6Y attribute + /// + public async Task GetPrimary6Y(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 41))!; + } + + /// + /// Get the Primary6 Intensity attribute + /// + public async Task GetPrimary6Intensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 42, true); + } + + /// + /// Get the White PointX attribute + /// + public async Task GetWhitePointX(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 48))!; + } + + /// + /// Set the White PointX attribute + /// + public async Task SetWhitePointX (SecureSession session, ushort value) { + await SetAttribute(session, 48, value); + } + + /// + /// Get the White PointY attribute + /// + public async Task GetWhitePointY(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 49))!; + } + + /// + /// Set the White PointY attribute + /// + public async Task SetWhitePointY (SecureSession session, ushort value) { + await SetAttribute(session, 49, value); + } + + /// + /// Get the Color Point RX attribute + /// + public async Task GetColorPointRX(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 50))!; + } + + /// + /// Set the Color Point RX attribute + /// + public async Task SetColorPointRX (SecureSession session, ushort value) { + await SetAttribute(session, 50, value); + } + + /// + /// Get the Color Point RY attribute + /// + public async Task GetColorPointRY(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 51))!; + } + + /// + /// Set the Color Point RY attribute + /// + public async Task SetColorPointRY (SecureSession session, ushort value) { + await SetAttribute(session, 51, value); + } + + /// + /// Get the Color Point R Intensity attribute + /// + public async Task GetColorPointRIntensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 52, true); + } + + /// + /// Set the Color Point R Intensity attribute + /// + public async Task SetColorPointRIntensity (SecureSession session, byte? value) { + await SetAttribute(session, 52, value, true); + } + + /// + /// Get the Color Point GX attribute + /// + public async Task GetColorPointGX(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 54))!; + } + + /// + /// Set the Color Point GX attribute + /// + public async Task SetColorPointGX (SecureSession session, ushort value) { + await SetAttribute(session, 54, value); + } + + /// + /// Get the Color Point GY attribute + /// + public async Task GetColorPointGY(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 55))!; + } + + /// + /// Set the Color Point GY attribute + /// + public async Task SetColorPointGY (SecureSession session, ushort value) { + await SetAttribute(session, 55, value); + } + + /// + /// Get the Color Point G Intensity attribute + /// + public async Task GetColorPointGIntensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 56, true); + } + + /// + /// Set the Color Point G Intensity attribute + /// + public async Task SetColorPointGIntensity (SecureSession session, byte? value) { + await SetAttribute(session, 56, value, true); + } + + /// + /// Get the Color Point BX attribute + /// + public async Task GetColorPointBX(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 58))!; + } + + /// + /// Set the Color Point BX attribute + /// + public async Task SetColorPointBX (SecureSession session, ushort value) { + await SetAttribute(session, 58, value); + } + + /// + /// Get the Color Point BY attribute + /// + public async Task GetColorPointBY(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 59))!; + } + + /// + /// Set the Color Point BY attribute + /// + public async Task SetColorPointBY (SecureSession session, ushort value) { + await SetAttribute(session, 59, value); + } + + /// + /// Get the Color Point B Intensity attribute + /// + public async Task GetColorPointBIntensity(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 60, true); + } + + /// + /// Set the Color Point B Intensity attribute + /// + public async Task SetColorPointBIntensity (SecureSession session, byte? value) { + await SetAttribute(session, 60, value, true); + } + + /// + /// Get the Enhanced Current Hue attribute + /// + public async Task GetEnhancedCurrentHue(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16384) ?? 0; + } + + /// + /// Get the Enhanced Color Mode attribute + /// + public async Task GetEnhancedColorMode(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 16385) ?? 1; + } + + /// + /// Get the Color Loop Active attribute + /// + public async Task GetColorLoopActive(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 16386) ?? 0; + } + + /// + /// Get the Color Loop Direction attribute + /// + public async Task GetColorLoopDirection(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 16387) ?? 0; + } + + /// + /// Get the Color Loop Time attribute + /// + public async Task GetColorLoopTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16388) ?? 0x0019; + } + + /// + /// Get the Color Loop Start Enhanced Hue attribute + /// + public async Task GetColorLoopStartEnhancedHue(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16389) ?? 0x2300; + } + + /// + /// Get the Color Loop Stored Enhanced Hue attribute + /// + public async Task GetColorLoopStoredEnhancedHue(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16390) ?? 0; + } + + /// + /// Get the Color Capabilities attribute + /// + public async Task GetColorCapabilities(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16394) ?? 0; + } + + /// + /// Get the Color Temp Physical Min Mireds attribute + /// + public async Task GetColorTempPhysicalMinMireds(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16395) ?? 0; + } + + /// + /// Get the Color Temp Physical Max Mireds attribute + /// + public async Task GetColorTempPhysicalMaxMireds(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16396) ?? 0xFEFF; + } + + /// + /// Get the Couple Color Temp To Level Min Mireds attribute + /// + public async Task GetCoupleColorTempToLevelMinMireds(SecureSession session) { + return (ushort)(dynamic?)(await GetAttribute(session, 16397))!; + } + + /// + /// Get the Start Up Color Temperature Mireds attribute + /// + public async Task GetStartUpColorTemperatureMireds(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16400, true); + } + + /// + /// Set the Start Up Color Temperature Mireds attribute + /// + public async Task SetStartUpColorTemperatureMireds (SecureSession session, ushort? value) { + await SetAttribute(session, 16400, value, true); + } + #endregion Attributes + + /// + public override string ToString() { + return "Color Control Cluster"; + } + } +} \ No newline at end of file diff --git a/MatterDotNet/Clusters/Application/LevelControlCluster.cs b/MatterDotNet/Clusters/Application/LevelControlCluster.cs new file mode 100644 index 0000000..ccf97f1 --- /dev/null +++ b/MatterDotNet/Clusters/Application/LevelControlCluster.cs @@ -0,0 +1,453 @@ +// MatterDotNet Copyright (C) 2025 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// WARNING: This file was auto-generated. Do not edit. + +using MatterDotNet.Messages.InteractionModel; +using MatterDotNet.Protocol.Parsers; +using MatterDotNet.Protocol.Payloads; +using MatterDotNet.Protocol.Sessions; +using MatterDotNet.Protocol.Subprotocols; + +namespace MatterDotNet.Clusters.Application +{ + /// + /// Level Control Cluster + /// + [ClusterRevision(CLUSTER_ID, 5)] + public class LevelControlCluster : ClusterBase + { + internal const uint CLUSTER_ID = 0x0008; + + /// + /// Level Control Cluster + /// + public LevelControlCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected LevelControlCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } + + #region Enums + /// + /// Supported Features + /// + [Flags] + public enum Feature { + /// + /// Dependency with the On/Off cluster + /// + OnOff = 1, + /// + /// Behavior that supports lighting applications + /// + Lighting = 2, + /// + /// Supports frequency attributes and behavior. The Pulse Width Modulation cluster was created for frequency control. + /// + Frequency = 4, + } + + /// + /// Move Mode + /// + public enum MoveModeEnum { + /// + /// Increase the level + /// + Up = 0, + /// + /// Decrease the level + /// + Down = 1, + } + + /// + /// Step Mode + /// + public enum StepModeEnum { + /// + /// Step upwards + /// + Up = 0, + /// + /// Step downwards + /// + Down = 1, + } + + /// + /// Options Bitmap + /// + [Flags] + public enum OptionsBitmap { + /// + /// Dependency on On/Off cluster + /// + ExecuteIfOff = 1, + /// + /// Dependency on Color Control cluster + /// + CoupleColorTempToLevel = 2, + } + #endregion Enums + + #region Payloads + private record MoveToLevelPayload : TLVPayload { + public required byte Level { get; set; } + public required ushort? TransitionTime { get; set; } + public required OptionsBitmap OptionsMask { get; set; } = 0; + public required OptionsBitmap OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteByte(0, Level, 254); + writer.WriteUShort(1, TransitionTime); + writer.WriteUShort(2, (ushort)OptionsMask); + writer.WriteUShort(3, (ushort)OptionsOverride); + writer.EndContainer(); + } + } + + private record MovePayload : TLVPayload { + public required MoveModeEnum MoveMode { get; set; } + public required byte? Rate { get; set; } + public required OptionsBitmap OptionsMask { get; set; } = 0; + public required OptionsBitmap OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, (ushort)MoveMode); + writer.WriteByte(1, Rate); + writer.WriteUShort(2, (ushort)OptionsMask); + writer.WriteUShort(3, (ushort)OptionsOverride); + writer.EndContainer(); + } + } + + private record StepPayload : TLVPayload { + public required StepModeEnum StepMode { get; set; } + public required byte StepSize { get; set; } + public required ushort? TransitionTime { get; set; } + public required OptionsBitmap OptionsMask { get; set; } = 0; + public required OptionsBitmap OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, (ushort)StepMode); + writer.WriteByte(1, StepSize); + writer.WriteUShort(2, TransitionTime); + writer.WriteUShort(3, (ushort)OptionsMask); + writer.WriteUShort(4, (ushort)OptionsOverride); + writer.EndContainer(); + } + } + + private record StopPayload : TLVPayload { + public required OptionsBitmap OptionsMask { get; set; } = 0; + public required OptionsBitmap OptionsOverride { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, (ushort)OptionsMask); + writer.WriteUShort(1, (ushort)OptionsOverride); + writer.EndContainer(); + } + } + + private record MoveToClosestFrequencyPayload : TLVPayload { + public required ushort Frequency { get; set; } = 0; + internal override void Serialize(TLVWriter writer, long structNumber = -1) { + writer.StartStructure(structNumber); + writer.WriteUShort(0, Frequency); + writer.EndContainer(); + } + } + #endregion Payloads + + #region Commands + /// + /// Move To Level + /// + public async Task MoveToLevel(SecureSession session, byte Level, ushort TransitionTime, OptionsBitmap OptionsMask, OptionsBitmap OptionsOverride) { + MoveToLevelPayload requestFields = new MoveToLevelPayload() { + Level = Level, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x00, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move + /// + public async Task Move(SecureSession session, MoveModeEnum MoveMode, byte Rate, OptionsBitmap OptionsMask, OptionsBitmap OptionsOverride) { + MovePayload requestFields = new MovePayload() { + MoveMode = MoveMode, + Rate = Rate, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x01, requestFields); + return ValidateResponse(resp); + } + + /// + /// Step + /// + public async Task Step(SecureSession session, StepModeEnum StepMode, byte StepSize, ushort TransitionTime, OptionsBitmap OptionsMask, OptionsBitmap OptionsOverride) { + StepPayload requestFields = new StepPayload() { + StepMode = StepMode, + StepSize = StepSize, + TransitionTime = TransitionTime, + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x02, requestFields); + return ValidateResponse(resp); + } + + /// + /// Stop + /// + public async Task Stop(SecureSession session, OptionsBitmap OptionsMask, OptionsBitmap OptionsOverride) { + StopPayload requestFields = new StopPayload() { + OptionsMask = OptionsMask, + OptionsOverride = OptionsOverride, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x03, requestFields); + return ValidateResponse(resp); + } + + /// + /// Move To Level With On Off + /// + public async Task MoveToLevelWithOnOff(SecureSession session) { + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x04); + return ValidateResponse(resp); + } + + /// + /// Move With On Off + /// + public async Task MoveWithOnOff(SecureSession session) { + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x05); + return ValidateResponse(resp); + } + + /// + /// Step With On Off + /// + public async Task StepWithOnOff(SecureSession session) { + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x06); + return ValidateResponse(resp); + } + + /// + /// Stop With On Off + /// + public async Task StopWithOnOff(SecureSession session) { + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x07); + return ValidateResponse(resp); + } + + /// + /// Move To Closest Frequency + /// + public async Task MoveToClosestFrequency(SecureSession session, ushort Frequency) { + MoveToClosestFrequencyPayload requestFields = new MoveToClosestFrequencyPayload() { + Frequency = Frequency, + }; + InvokeResponseIB resp = await InteractionManager.ExecCommand(session, endPoint, CLUSTER_ID, 0x08, requestFields); + return ValidateResponse(resp); + } + #endregion Commands + + #region Attributes + /// + /// Features supported by this cluster + /// + /// + /// + public async Task GetSupportedFeatures(SecureSession session) + { + return (Feature)(byte)(await GetAttribute(session, 0xFFFC))!; + } + + /// + /// Returns true when the feature is supported by the cluster + /// + /// + /// + /// + public async Task Supports(SecureSession session, Feature feature) + { + return ((feature & await GetSupportedFeatures(session)) != 0); + } + + /// + /// Get the Current Level attribute + /// + public async Task GetCurrentLevel(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 0, true) ?? null; + } + + /// + /// Get the Remaining Time attribute + /// + public async Task GetRemainingTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 1) ?? 0; + } + + /// + /// Get the Min Level attribute + /// + public async Task GetMinLevel(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 2) ?? 1; + } + + /// + /// Get the Min Level attribute + /// + public async Task GetMinLevel2(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 2) ?? 0; + } + + /// + /// Get the Max Level attribute + /// + public async Task GetMaxLevel(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 3) ?? 254; + } + + /// + /// Get the Current Frequency attribute + /// + public async Task GetCurrentFrequency(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 4) ?? 0; + } + + /// + /// Get the Min Frequency attribute + /// + public async Task GetMinFrequency(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 5) ?? 0; + } + + /// + /// Get the Max Frequency attribute + /// + public async Task GetMaxFrequency(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 6) ?? 0; + } + + /// + /// Get the Options attribute + /// + public async Task GetOptions(SecureSession session) { + return (OptionsBitmap)await GetEnumAttribute(session, 15); + } + + /// + /// Set the Options attribute + /// + public async Task SetOptions (SecureSession session, OptionsBitmap value) { + await SetAttribute(session, 15, value); + } + + /// + /// Get the On Off Transition Time attribute + /// + public async Task GetOnOffTransitionTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 16) ?? 0; + } + + /// + /// Set the On Off Transition Time attribute + /// + public async Task SetOnOffTransitionTime (SecureSession session, ushort? value = 0) { + await SetAttribute(session, 16, value); + } + + /// + /// Get the On Level attribute + /// + public async Task GetOnLevel(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 17, true) ?? null; + } + + /// + /// Set the On Level attribute + /// + public async Task SetOnLevel (SecureSession session, byte? value = null) { + await SetAttribute(session, 17, value, true); + } + + /// + /// Get the On Transition Time attribute + /// + public async Task GetOnTransitionTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 18, true) ?? null; + } + + /// + /// Set the On Transition Time attribute + /// + public async Task SetOnTransitionTime (SecureSession session, ushort? value = null) { + await SetAttribute(session, 18, value, true); + } + + /// + /// Get the Off Transition Time attribute + /// + public async Task GetOffTransitionTime(SecureSession session) { + return (ushort?)(dynamic?)await GetAttribute(session, 19, true) ?? null; + } + + /// + /// Set the Off Transition Time attribute + /// + public async Task SetOffTransitionTime (SecureSession session, ushort? value = null) { + await SetAttribute(session, 19, value, true); + } + + /// + /// Get the Default Move Rate attribute + /// + public async Task GetDefaultMoveRate(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 20, true); + } + + /// + /// Set the Default Move Rate attribute + /// + public async Task SetDefaultMoveRate (SecureSession session, byte? value) { + await SetAttribute(session, 20, value, true); + } + + /// + /// Get the Start Up Current Level attribute + /// + public async Task GetStartUpCurrentLevel(SecureSession session) { + return (byte?)(dynamic?)await GetAttribute(session, 16384, true); + } + + /// + /// Set the Start Up Current Level attribute + /// + public async Task SetStartUpCurrentLevel (SecureSession session, byte? value) { + await SetAttribute(session, 16384, value, true); + } + #endregion Attributes + + /// + public override string ToString() { + return "Level Control Cluster"; + } + } +} \ No newline at end of file diff --git a/MatterDotNet/Clusters/Application/On-OffCluster.cs b/MatterDotNet/Clusters/Application/On-OffCluster.cs index e2761f2..5df4f82 100644 --- a/MatterDotNet/Clusters/Application/On-OffCluster.cs +++ b/MatterDotNet/Clusters/Application/On-OffCluster.cs @@ -32,6 +32,8 @@ public class On_OffCluster : ClusterBase /// On/Off Cluster /// public On_OffCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected On_OffCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } #region Enums /// @@ -288,5 +290,10 @@ public async Task SetStartUpOnOff (SecureSession session, StartUpOnOffEnum? valu await SetAttribute(session, 16387, value, true); } #endregion Attributes + + /// + public override string ToString() { + return "On/Off Cluster"; + } } } \ No newline at end of file diff --git a/MatterDotNet/Clusters/ClusterBase.cs b/MatterDotNet/Clusters/ClusterBase.cs index 10f42b9..ddb95da 100644 --- a/MatterDotNet/Clusters/ClusterBase.cs +++ b/MatterDotNet/Clusters/ClusterBase.cs @@ -220,6 +220,21 @@ private bool ValidateStatus(IMStatusCode status) } } + /// + /// Returns the human readable name for the cluster + /// + /// + public override string ToString() + { + return this.GetType().Name; + } + + /// + /// Create a cluster for the given cluster ID and end point + /// + /// + /// + /// public static ClusterBase Create(uint clusterId, ushort endPoint) { switch (clusterId) @@ -230,6 +245,10 @@ public static ClusterBase Create(uint clusterId, ushort endPoint) return new AdministratorCommissioningCluster(endPoint); case BasicInformationCluster.CLUSTER_ID: return new BasicInformationCluster(endPoint); + case BridgedDeviceBasicInformationCluster.CLUSTER_ID: + return new BridgedDeviceBasicInformationCluster(endPoint); + case ColorControlCluster.CLUSTER_ID: + return new ColorControlCluster(endPoint); case DescriptorCluster.CLUSTER_ID: return new DescriptorCluster(endPoint); case GeneralDiagnosticsCluster.CLUSTER_ID: @@ -238,8 +257,16 @@ public static ClusterBase Create(uint clusterId, ushort endPoint) return new GeneralCommissioningCluster(endPoint); case GroupKeyManagementCluster.CLUSTER_ID: return new GroupKeyManagementCluster(endPoint); + case GroupsCluster.CLUSTER_ID: + return new GroupsCluster(endPoint); case IdentifyCluster.CLUSTER_ID: return new IdentifyCluster(endPoint); + case FixedLabelCluster.CLUSTER_ID: + return new FixedLabelCluster(endPoint); + case UserLabelCluster.CLUSTER_ID: + return new UserLabelCluster(endPoint); + case LevelControlCluster.CLUSTER_ID: + return new LevelControlCluster(endPoint); case On_OffCluster.CLUSTER_ID: return new On_OffCluster(endPoint); case NodeOperationalCredentialsCluster.CLUSTER_ID: diff --git a/MatterDotNet/Clusters/UnknownCluster.cs b/MatterDotNet/Clusters/UnknownCluster.cs index 76e5fc1..d9afe81 100644 --- a/MatterDotNet/Clusters/UnknownCluster.cs +++ b/MatterDotNet/Clusters/UnknownCluster.cs @@ -22,7 +22,7 @@ public UnknownCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) public override string ToString() { - return "Unknown Cluster: " + cluster; + return $"Unknown Cluster: 0x{cluster:X2}"; } } } diff --git a/MatterDotNet/Clusters/Utility/AccessControlCluster.cs b/MatterDotNet/Clusters/Utility/AccessControlCluster.cs index 560fcdf..ea3b96d 100644 --- a/MatterDotNet/Clusters/Utility/AccessControlCluster.cs +++ b/MatterDotNet/Clusters/Utility/AccessControlCluster.cs @@ -31,6 +31,8 @@ public class AccessControlCluster : ClusterBase /// Access Control Cluster /// public AccessControlCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected AccessControlCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } #region Enums /// @@ -250,5 +252,10 @@ public async Task GetAccessControlEntriesPerFabric(SecureSession session return (ushort?)(dynamic?)await GetAttribute(session, 4) ?? 4; } #endregion Attributes + + /// + public override string ToString() { + return "Access Control Cluster"; + } } } \ No newline at end of file diff --git a/MatterDotNet/Clusters/Utility/AdministratorCommissioningCluster.cs b/MatterDotNet/Clusters/Utility/AdministratorCommissioningCluster.cs index 988576d..76ae601 100644 --- a/MatterDotNet/Clusters/Utility/AdministratorCommissioningCluster.cs +++ b/MatterDotNet/Clusters/Utility/AdministratorCommissioningCluster.cs @@ -32,6 +32,8 @@ public class AdministratorCommissioningCluster : ClusterBase /// Administrator Commissioning Cluster /// public AdministratorCommissioningCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected AdministratorCommissioningCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } #region Enums /// @@ -171,5 +173,10 @@ public async Task GetWindowStatus(SecureSession s return (ushort?)(dynamic?)await GetAttribute(session, 2, true); } #endregion Attributes + + /// + public override string ToString() { + return "Administrator Commissioning Cluster"; + } } } \ No newline at end of file diff --git a/MatterDotNet/Clusters/Utility/BasicInformationCluster.cs b/MatterDotNet/Clusters/Utility/BasicInformationCluster.cs index 433434d..9f6fcf6 100644 --- a/MatterDotNet/Clusters/Utility/BasicInformationCluster.cs +++ b/MatterDotNet/Clusters/Utility/BasicInformationCluster.cs @@ -31,6 +31,8 @@ public class BasicInformationCluster : ClusterBase /// Basic Information Cluster /// public BasicInformationCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected BasicInformationCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } #region Enums /// @@ -379,5 +381,10 @@ public async Task GetMaxPathsPerInvoke(SecureSession session) { return (ushort?)(dynamic?)await GetAttribute(session, 22) ?? 1; } #endregion Attributes + + /// + public override string ToString() { + return "Basic Information Cluster"; + } } } \ No newline at end of file diff --git a/MatterDotNet/Clusters/Utility/BridgedDeviceBasicInformationCluster.cs b/MatterDotNet/Clusters/Utility/BridgedDeviceBasicInformationCluster.cs new file mode 100644 index 0000000..aa1e188 --- /dev/null +++ b/MatterDotNet/Clusters/Utility/BridgedDeviceBasicInformationCluster.cs @@ -0,0 +1,41 @@ +// MatterDotNet Copyright (C) 2025 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// WARNING: This file was auto-generated. Do not edit. + +using MatterDotNet.Protocol.Parsers; +using MatterDotNet.Protocol.Sessions; + +namespace MatterDotNet.Clusters.Utility +{ + /// + /// Bridged Device Basic Information Cluster + /// + [ClusterRevision(CLUSTER_ID, 3)] + public class BridgedDeviceBasicInformationCluster : BasicInformationCluster + { + internal const uint CLUSTER_ID = 0x0039; + + /// + /// Bridged Device Basic Information Cluster + /// + public BridgedDeviceBasicInformationCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + + #region Attributes + #endregion Attributes + + /// + public override string ToString() { + return "Bridged Device Basic Information Cluster"; + } + } +} \ No newline at end of file diff --git a/MatterDotNet/Clusters/Utility/DescriptorCluster.cs b/MatterDotNet/Clusters/Utility/DescriptorCluster.cs index 54e75e1..6ffb8f5 100644 --- a/MatterDotNet/Clusters/Utility/DescriptorCluster.cs +++ b/MatterDotNet/Clusters/Utility/DescriptorCluster.cs @@ -32,6 +32,8 @@ public class DescriptorCluster : ClusterBase /// Descriptor Cluster /// public DescriptorCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + /// + protected DescriptorCluster(uint cluster, ushort endPoint) : base(cluster, endPoint) { } #region Enums /// @@ -145,5 +147,10 @@ public async Task> GetTagList(SecureSession session) { return list; } #endregion Attributes + + /// + public override string ToString() { + return "Descriptor Cluster"; + } } } \ No newline at end of file diff --git a/MatterDotNet/Clusters/Utility/FixedLabelCluster.cs b/MatterDotNet/Clusters/Utility/FixedLabelCluster.cs new file mode 100644 index 0000000..0e8cae3 --- /dev/null +++ b/MatterDotNet/Clusters/Utility/FixedLabelCluster.cs @@ -0,0 +1,51 @@ +// MatterDotNet Copyright (C) 2025 +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// WARNING: This file was auto-generated. Do not edit. + +using MatterDotNet.Protocol.Parsers; +using MatterDotNet.Protocol.Sessions; + +namespace MatterDotNet.Clusters.Utility +{ + /// + /// Fixed Label Cluster + /// + [ClusterRevision(CLUSTER_ID, 1)] + public class FixedLabelCluster : LabelCluster + { + internal const uint CLUSTER_ID = 0x0040; + + /// + /// Fixed Label Cluster + /// + public FixedLabelCluster(ushort endPoint) : base(CLUSTER_ID, endPoint) { } + + #region Attributes + /// + /// Get the Label List attribute + /// + public async Task> GetLabelList(SecureSession session) { + List