Skip to content

Commit 2d51cba

Browse files
committed
Support the new "ring" event for doorbell scenarios
1 parent ccaffd4 commit 2d51cba

3 files changed

Lines changed: 212 additions & 47 deletions

File tree

src/OpenNetty.Mqtt/OpenNettyMqttHostedService.cs

Lines changed: 105 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,42 @@ async ValueTask<IAsyncDisposable> IOpenNettyHandler.SubscribeAsync()
6363
[
6464
await _events.ActionScenarioReported
6565
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
66-
.Do(arguments => ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
66+
.Do(async arguments =>
6767
{
68-
var node = new JsonObject
68+
// Note: if the device class is "doorbell", a standard "ring" event is also sent for action scenarios.
69+
if (arguments.Type is OpenNettyModels.ScenariosPlus.ActionScenarioType.Action &&
70+
arguments.Endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
71+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
6972
{
70-
["event_type"] = arguments.Type switch
73+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
7174
{
72-
OpenNettyModels.ScenariosPlus.ActionScenarioType.Action => "action",
73-
OpenNettyModels.ScenariosPlus.ActionScenarioType.StopAction => "stop_action",
75+
var node = new JsonObject
76+
{
77+
["event_type"] = "ring"
78+
};
7479

75-
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
76-
}
77-
};
80+
builder.WithContentType(MediaTypeNames.Application.Json);
81+
builder.WithPayload(node.ToJsonString());
82+
});
83+
}
7884

79-
builder.WithContentType(MediaTypeNames.Application.Json);
80-
builder.WithPayload(node.ToJsonString());
81-
}))
85+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
86+
{
87+
var node = new JsonObject
88+
{
89+
["event_type"] = arguments.Type switch
90+
{
91+
OpenNettyModels.ScenariosPlus.ActionScenarioType.Action => "action",
92+
OpenNettyModels.ScenariosPlus.ActionScenarioType.StopAction => "stop_action",
93+
94+
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
95+
}
96+
};
97+
98+
builder.WithContentType(MediaTypeNames.Application.Json);
99+
builder.WithPayload(node.ToJsonString());
100+
});
101+
})
82102
.Retry()
83103
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
84104

@@ -358,51 +378,95 @@ await _events.PilotWireShutdownModeReported
358378

359379
await _events.PressureScenarioReported
360380
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
361-
.Do(arguments => ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
381+
.Do(async arguments =>
362382
{
363-
var node = new JsonObject
383+
// Note: if the device class is "doorbell", a standard "ring" event is also sent for short pressure scenarios.
384+
if (arguments.Type is OpenNettyModels.Scenarios.PressureScenarioType.Pressure &&
385+
arguments.Endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
386+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
364387
{
365-
["event_type"] = arguments.Type switch
388+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
366389
{
367-
OpenNettyModels.Scenarios.PressureScenarioType.Pressure => "pressure",
368-
OpenNettyModels.Scenarios.PressureScenarioType.ReleaseAfterShortPressure => "release_after_short_pressure",
369-
OpenNettyModels.Scenarios.PressureScenarioType.ReleaseAfterExtendedPressure => "release_after_extended_pressure",
370-
OpenNettyModels.Scenarios.PressureScenarioType.ExtendedPressure => "extended_pressure",
390+
var node = new JsonObject
391+
{
392+
["event_type"] = "ring",
393+
["scenario_type"] = "evolved",
394+
["button"] = arguments.Button
395+
};
371396

372-
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
373-
},
374-
["scenario_type"] = "evolved",
375-
["button"] = arguments.Button
376-
};
397+
builder.WithContentType(MediaTypeNames.Application.Json);
398+
builder.WithPayload(node.ToJsonString());
399+
});
400+
}
377401

378-
builder.WithContentType(MediaTypeNames.Application.Json);
379-
builder.WithPayload(node.ToJsonString());
380-
}))
402+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
403+
{
404+
var node = new JsonObject
405+
{
406+
["event_type"] = arguments.Type switch
407+
{
408+
OpenNettyModels.Scenarios.PressureScenarioType.Pressure => "pressure",
409+
OpenNettyModels.Scenarios.PressureScenarioType.ReleaseAfterShortPressure => "release_after_short_pressure",
410+
OpenNettyModels.Scenarios.PressureScenarioType.ReleaseAfterExtendedPressure => "release_after_extended_pressure",
411+
OpenNettyModels.Scenarios.PressureScenarioType.ExtendedPressure => "extended_pressure",
412+
413+
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
414+
},
415+
["scenario_type"] = "evolved",
416+
["button"] = arguments.Button
417+
};
418+
419+
builder.WithContentType(MediaTypeNames.Application.Json);
420+
builder.WithPayload(node.ToJsonString());
421+
});
422+
})
381423
.Retry()
382424
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
383425

384426
await _events.PressureScenarioPlusReported
385427
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
386-
.Do(arguments => ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
428+
.Do(async arguments =>
387429
{
388-
var node = new JsonObject
430+
// Note: if the device class is "doorbell", a standard "ring" event is also sent for short pressure scenarios.
431+
if (arguments.Type is OpenNettyModels.ScenariosPlus.PressureScenarioType.ShortPressure &&
432+
arguments.Endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
433+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
389434
{
390-
["event_type"] = arguments.Type switch
435+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
436+
{
437+
var node = new JsonObject
438+
{
439+
["event_type"] = "ring",
440+
["scenario_type"] = "plus",
441+
["button"] = arguments.Button
442+
};
443+
444+
builder.WithContentType(MediaTypeNames.Application.Json);
445+
builder.WithPayload(node.ToJsonString());
446+
});
447+
}
448+
449+
await ReportAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, builder =>
450+
{
451+
var node = new JsonObject
391452
{
392-
OpenNettyModels.ScenariosPlus.PressureScenarioType.ShortPressure => "short_pressure",
393-
OpenNettyModels.ScenariosPlus.PressureScenarioType.StartOfExtendedPressure => "start_of_extended_pressure",
394-
OpenNettyModels.ScenariosPlus.PressureScenarioType.ExtendedPressure => "extended_pressure",
395-
OpenNettyModels.ScenariosPlus.PressureScenarioType.EndOfExtendedPressure => "end_of_extended_pressure",
453+
["event_type"] = arguments.Type switch
454+
{
455+
OpenNettyModels.ScenariosPlus.PressureScenarioType.ShortPressure => "short_pressure",
456+
OpenNettyModels.ScenariosPlus.PressureScenarioType.StartOfExtendedPressure => "start_of_extended_pressure",
457+
OpenNettyModels.ScenariosPlus.PressureScenarioType.ExtendedPressure => "extended_pressure",
458+
OpenNettyModels.ScenariosPlus.PressureScenarioType.EndOfExtendedPressure => "end_of_extended_pressure",
396459

397-
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
398-
},
399-
["scenario_type"] = "plus",
400-
["button"] = arguments.Button
401-
};
460+
_ => throw new InvalidDataException(SR.GetResourceString(SR.ID0068))
461+
},
462+
["scenario_type"] = "plus",
463+
["button"] = arguments.Button
464+
};
402465

403-
builder.WithContentType(MediaTypeNames.Application.Json);
404-
builder.WithPayload(node.ToJsonString());
405-
}))
466+
builder.WithContentType(MediaTypeNames.Application.Json);
467+
builder.WithPayload(node.ToJsonString());
468+
});
469+
})
406470
.Retry()
407471
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
408472

src/OpenNetty.Mqtt/OpenNettyMqttWorker.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ public async Task AnnounceEndpointsAsync(IManagedMqttClient client, Cancellation
865865
else if (platform is OpenNettySettings.HomeAssistantEntityTypes.Switch)
866866
{
867867
component["device_class"] = endpoint.GetStringSetting(OpenNettySettings.HomeAssistantSwitchDeviceClass)
868-
?? OpenNettySettings.HomeAssistantDeviceClasses.Switch;
868+
?? OpenNettySettings.HomeAssistantDeviceClasses.Switches.Switch;
869869
}
870870

871871
components.Add(CreateEntityNode(component));
@@ -922,7 +922,7 @@ public async Task AnnounceEndpointsAsync(IManagedMqttClient client, Cancellation
922922
["platform"] = "cover",
923923
["unique_id"] = ComputeEntityUniqueId(endpoint, "9b138d62-bb0d-49cb-8624-1d85f9e86a6e"u8),
924924
["device_class"] = endpoint.GetStringSetting(OpenNettySettings.HomeAssistantCoverDeviceClass)
925-
?? OpenNettySettings.HomeAssistantDeviceClasses.Shutter,
925+
?? OpenNettySettings.HomeAssistantDeviceClasses.Covers.Shutter,
926926
["name"] = endpoint.GetStringSetting(OpenNettySettings.HomeAssistantCoverName) ??
927927
ComputeEntityName(
928928
name : GetLocalizedString(SR.ID8004, culture),
@@ -1011,6 +1011,12 @@ public async Task AnnounceEndpointsAsync(IManagedMqttClient client, Cancellation
10111011

10121012
if (endpoint.HasCapability(OpenNettyCapabilities.ActionScenarioEvent))
10131013
{
1014+
if (endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
1015+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
1016+
{
1017+
types.Add("ring");
1018+
}
1019+
10141020
types.Add("action");
10151021
types.Add("stop_action");
10161022
}
@@ -1028,6 +1034,12 @@ public async Task AnnounceEndpointsAsync(IManagedMqttClient client, Cancellation
10281034

10291035
if (endpoint.HasCapability(OpenNettyCapabilities.PressureScenarioEvent))
10301036
{
1037+
if (endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
1038+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
1039+
{
1040+
types.Add("ring");
1041+
}
1042+
10311043
types.Add("pressure");
10321044
types.Add("release_after_short_pressure");
10331045
types.Add("release_after_extended_pressure");
@@ -1036,6 +1048,12 @@ public async Task AnnounceEndpointsAsync(IManagedMqttClient client, Cancellation
10361048

10371049
if (endpoint.HasCapability(OpenNettyCapabilities.PressureScenarioPlusEvent))
10381050
{
1051+
if (endpoint.GetStringSetting(OpenNettySettings.HomeAssistantScenarioDeviceClass)
1052+
is OpenNettySettings.HomeAssistantDeviceClasses.Events.Doorbell)
1053+
{
1054+
types.Add("ring");
1055+
}
1056+
10391057
types.Add("short_pressure");
10401058
types.Add("start_of_extended_pressure");
10411059
types.Add("extended_pressure");

src/OpenNetty/OpenNettySettings.cs

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,97 @@ public static class FunctionTypes
228228
public static class HomeAssistantDeviceClasses
229229
{
230230
/// <summary>
231-
/// Shutter.
231+
/// Device classes for cover entities.
232232
/// </summary>
233-
public const string Shutter = "shutter";
233+
public static class Covers
234+
{
235+
/// <summary>
236+
/// Awning.
237+
/// </summary>
238+
public const string Awning = "awning";
239+
240+
/// <summary>
241+
/// Blind.
242+
/// </summary>
243+
public const string Blind = "blind";
244+
245+
/// <summary>
246+
/// Curtain.
247+
/// </summary>
248+
public const string Curtain = "curtain";
249+
250+
/// <summary>
251+
/// Damper.
252+
/// </summary>
253+
public const string Damper = "damper";
254+
255+
/// <summary>
256+
/// Door.
257+
/// </summary>
258+
public const string Door = "door";
259+
260+
/// <summary>
261+
/// Garage.
262+
/// </summary>
263+
public const string Garage = "garage";
264+
265+
/// <summary>
266+
/// Gate.
267+
/// </summary>
268+
public const string Gate = "gate";
269+
270+
/// <summary>
271+
/// Shade.
272+
/// </summary>
273+
public const string Shade = "shade";
274+
275+
/// <summary>
276+
/// Shutter.
277+
/// </summary>
278+
public const string Shutter = "shutter";
279+
280+
/// <summary>
281+
/// Window.
282+
/// </summary>
283+
public const string Window = "window";
284+
}
234285

235286
/// <summary>
236-
/// Switch.
287+
/// Device classes for event entities.
237288
/// </summary>
238-
public const string Switch = "switch";
289+
public static class Events
290+
{
291+
/// <summary>
292+
/// Button.
293+
/// </summary>
294+
public const string Button = "button";
295+
296+
/// <summary>
297+
/// Doorbell.
298+
/// </summary>
299+
public const string Doorbell = "doorbell";
300+
301+
/// <summary>
302+
/// Motion.
303+
/// </summary>
304+
public const string Motion = "motion";
305+
}
306+
307+
/// <summary>
308+
/// Device classes for switch entities.
309+
/// </summary>
310+
public static class Switches
311+
{
312+
/// <summary>
313+
/// Outlet.
314+
/// </summary>
315+
public const string Outlet = "outlet";
316+
317+
/// <summary>
318+
/// Switch.
319+
/// </summary>
320+
public const string Switch = "switch";
321+
}
239322
}
240323

241324
/// <summary>

0 commit comments

Comments
 (0)