Skip to content

Commit 4b5b3c4

Browse files
Handel changed service metadata json with multiple targets entities (#858)
1 parent 7fbcc0f commit 4b5b3c4

File tree

6 files changed

+82
-15
lines changed

6 files changed

+82
-15
lines changed

src/HassModel/NetDaemon.HassModel.CodeGenerator/CodeGeneration/ExtensionMethodsGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static IEnumerable<MemberDeclarationSyntax> Generate(IEnumerable<HassServ
5050
private static IEnumerable<MemberDeclarationSyntax> GenerateExtensionMethodsForService(string domain, HassService service, ILookup<string, string> entityClassNameByDomain)
5151
{
5252
// There can be multiple Target Domains, so generate methods for each
53-
var targetEntityDomains = service.Target?.Entity?.Domain ?? Array.Empty<string>();
53+
var targetEntityDomains = service.Target?.Entity.SelectMany(e => e.Domain) ?? Array.Empty<string>();
5454

5555
return targetEntityDomains.SelectMany(targetEntityDomain => GenerateExtensionMethodsForService(domain, service, targetEntityDomain, entityClassNameByDomain));
5656
}

src/HassModel/NetDaemon.HassModel.CodeGenerator/MetaData/ServicesMetaData/Selectors.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,7 @@ internal record NumberSelector : Selector
5050

5151
internal record TargetSelector : Selector
5252
{
53-
public AreaSelector? Area { get; init; }
54-
55-
public DeviceSelector? Device { get; init; }
56-
57-
public EntitySelector? Entity { get; init; }
53+
[JsonConverter(typeof(SingleObjectAsArrayConverter<EntitySelector>))]
54+
public EntitySelector[] Entity { get; init; } = Array.Empty<EntitySelector>();
5855
}
5956

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace NetDaemon.HassModel.CodeGenerator.Model;
4+
5+
/// <summary>
6+
/// Converts either a single object or an array to an array
7+
/// </summary>
8+
class SingleObjectAsArrayConverter<T> : JsonConverter<T[]>
9+
{
10+
public override T[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
11+
{
12+
if (reader.TokenType == JsonTokenType.StartObject)
13+
{
14+
return new [] { JsonSerializer.Deserialize<T>(ref reader, options)! };
15+
}
16+
17+
return JsonSerializer.Deserialize<T[]>(ref reader, options);
18+
}
19+
20+
public override void Write(Utf8JsonWriter writer, T[] value, JsonSerializerOptions options)
21+
=> throw new NotSupportedException();
22+
}

src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/CodeGeneratorTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public void TestNumberExtensionMethodGeneration()
197197
new() {
198198
Service = "set_value",
199199
Target = new TargetSelector {
200-
Entity = new() { Domain = new [] {"number"} }
200+
Entity = new[] { new EntitySelector { Domain = new[] { "number" } } }
201201
},
202202
Fields = new HassServiceField[] {
203203
new() { Field = "value", Selector = new NumberSelector(), },

src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServiceMetaDataParserTest.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void TestSomeBasicServicesCanBeParsed()
4040
var res = ServiceMetaDataParser.Parse(element);
4141
res.Should().HaveCount(1);
4242
res.First().Domain.Should().Be("homeassistant");
43-
res.First().Services.ElementAt(1).Target!.Entity!.Domain.Should().BeEmpty();
43+
res.First().Services.ElementAt(1).Target!.Entity.SelectMany(e=>e.Domain).Should().BeEmpty();
4444
}
4545

4646
[Fact]
@@ -112,6 +112,38 @@ public void TestMultiDomainTargetWithRequiredFieldAsString()
112112
result.First().Services.First().Fields!.First().Required.Should().BeTrue();
113113
}
114114

115+
[Fact]
116+
public void DeserializeTargetEntityArray()
117+
{
118+
var sample = """
119+
{
120+
"testdomain": {
121+
"purge_entities":{
122+
"name":"Purge Entities",
123+
"fields":{
124+
},
125+
"target":{
126+
"entity":[
127+
{
128+
"domain":"targetdomain1"
129+
},
130+
{
131+
"domain":["targetdomain2", "targetdomain3"]
132+
}
133+
134+
]
135+
}
136+
}
137+
}
138+
}
139+
""";
140+
var result = Parse(sample);
141+
result.First().Services.First().Target!.Entity.Should().HaveCount(2);
142+
result.First().Services.First().Target!.Entity[0].Domain.Should().Equal("targetdomain1");
143+
result.First().Services.First().Target!.Entity[1].Domain.Should().Equal("targetdomain2", "targetdomain3");
144+
145+
}
146+
115147
private static IReadOnlyCollection<HassServiceDomain> Parse(string sample)
116148
{
117149
var element = JsonDocument.Parse(sample).RootElement;

src/HassModel/NetDaemon.HassModel.Tests/CodeGenerator/ServicesGeneratorTest.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,22 @@ public void TestServicesGeneration()
2121
Services = new HassService[] {
2222
new() {
2323
Service = "turn_off",
24-
Target = new TargetSelector { Entity = new() { Domain = new [] {"light"} } }
24+
Target = new TargetSelector
25+
{
26+
Entity = new[] { new EntitySelector { Domain = new[] { "light" } } }
27+
}
28+
2529
},
2630
new() {
2731
Service = "turn_on",
2832
Fields = new HassServiceField[] {
2933
new() { Field = "transition", Selector = new NumberSelector(), },
3034
new() { Field = "brightness", Selector = new NumberSelector { Step = 0.2f }, }
3135
},
32-
Target = new TargetSelector { Entity = new() { Domain = new [] {"light" } } }
36+
Target = new TargetSelector
37+
{
38+
Entity = new[] { new EntitySelector { Domain = new[] { "light" } } }
39+
}
3340
}
3441
}
3542
}
@@ -82,12 +89,18 @@ public void TestServiceWithoutAnyTargetEntity_ExtensionMethodSkipped()
8289
Domain = "smart_things",
8390
Services = new HassService[] {
8491
new() {
85-
Service = "dig",
86-
Target = new TargetSelector { Entity = new() { Domain = new [] {"humidifiers"} } },
92+
Service = "dig",
93+
Target = new TargetSelector
94+
{
95+
Entity = new[] { new EntitySelector { Domain = new[] { "humidifiers" } } }
96+
},
8797
},
8898
new() {
8999
Service = "orbit",
90-
Target = new TargetSelector { Entity = new() { Domain = new [] {"orbiter" }} },
100+
Target = new TargetSelector
101+
{
102+
Entity = new[] { new EntitySelector { Domain = new[] { "orbiter" } } }
103+
},
91104
}
92105
},
93106
}
@@ -134,7 +147,10 @@ public void TestServiceWithoutAnyMethods_ClassSkipped()
134147
Services = new HassService[] {
135148
new() {
136149
Service = "push_button",
137-
Target = new TargetSelector { Entity = new() { Domain = new [] {"uselessbox" }} },
150+
Target = new TargetSelector
151+
{
152+
Entity = new[] { new EntitySelector { Domain = new[] { "uselessbox" } } }
153+
},
138154
},
139155
},
140156
}
@@ -178,7 +194,7 @@ public void TestServiceWithKeyWordFieldName_ParamEscaped()
178194
new() {
179195
Service = "set_value",
180196
Target = new TargetSelector {
181-
Entity = new() { Domain = new [] {"light"} }
197+
Entity = new[] { new EntitySelector { Domain = new[] { "light" } } }
182198
},
183199
Fields = new HassServiceField[] {
184200
new() { Field = "class", Selector = new NumberSelector(), },

0 commit comments

Comments
 (0)