Skip to content

Commit fece68c

Browse files
committed
Implement basic and advanced shutters support
1 parent 54b9b5b commit fece68c

14 files changed

+798
-113
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ The following Legrand and BTicino products are partially or fully supported by O
7676
| MyHome Up | | 03598 | F454 | |
7777
| MyHome Up | | 03651 | F418U2 | |
7878
| MyHome Up | | 03847 | F411U1 | |
79-
| MyHome Up | | 03848 | F411U2 | Shutter mode is not yet supported |
79+
| MyHome Up | | 03848 | F411U2 | |
80+
| MyHome Up | Céliane | 67561 | | |
8081
| | | | | |
8182
| MyHome Play | Céliane | 67223 | | |
8283
| MyHome Play | | 88328 | 3578 | |

src/OpenNetty.Mqtt/OpenNettyMqttAttributes.cs

+10
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ public static class OpenNettyMqttAttributes
4141
/// </summary>
4242
public const string Scenario = "scenario";
4343

44+
/// <summary>
45+
/// Shutter position.
46+
/// </summary>
47+
public const string ShutterPosition = "shutter_position";
48+
49+
/// <summary>
50+
/// Shutter state.
51+
/// </summary>
52+
public const string ShutterState = "shutter_state";
53+
4454
/// <summary>
4555
/// Smart meter indexes.
4656
/// </summary>

src/OpenNetty.Mqtt/OpenNettyMqttHostedService.cs

+29
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,24 @@ await _events.ProgressiveScenarioReported
173173
.Retry()
174174
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
175175

176+
await _events.ShutterPositionReported
177+
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
178+
.Do(arguments => ReportStringAsync(arguments.Endpoint, OpenNettyMqttAttributes.ShutterPosition,
179+
arguments.Position.ToString(CultureInfo.InvariantCulture)))
180+
.Retry()
181+
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
182+
183+
await _events.ShutterStateReported
184+
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
185+
.Do(arguments => ReportStringAsync(arguments.Endpoint, OpenNettyMqttAttributes.ShutterState, arguments.State switch
186+
{
187+
OpenNettyModels.Automation.ShutterState.Stopped => "stopped",
188+
OpenNettyModels.Automation.ShutterState.Up => "open",
189+
_ => "closed"
190+
}))
191+
.Retry()
192+
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
193+
176194
await _events.SmartMeterIndexesReported
177195
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
178196
.Do(arguments => ReportJsonAsync(arguments.Endpoint, OpenNettyMqttAttributes.SmartMeterIndexes, new JsonObject()
@@ -213,6 +231,17 @@ await _events.SmartMeterRateTypeReported
213231
.Retry()
214232
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
215233

234+
await _events.StopUpDownScenarioReported
235+
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
236+
.Do(arguments => ReportStringAsync(arguments.Endpoint, OpenNettyMqttAttributes.Scenario, arguments.State switch
237+
{
238+
OpenNettyModels.Automation.ShutterState.Stopped => "STOP",
239+
OpenNettyModels.Automation.ShutterState.Up => "OPEN",
240+
_ => "CLOSE"
241+
}))
242+
.Retry()
243+
.SubscribeAsync(static arguments => ValueTask.CompletedTask),
244+
216245
await _events.SwitchStateReported
217246
.Where(static arguments => !string.IsNullOrEmpty(arguments.Endpoint.Name))
218247
.Do(arguments => ReportStringAsync(arguments.Endpoint, OpenNettyMqttAttributes.SwitchState,

src/OpenNetty.Mqtt/OpenNettyMqttWorker.cs

+51-5
Original file line numberDiff line numberDiff line change
@@ -251,32 +251,78 @@ await _controller.SetPilotWireSetpointModeAsync(endpoint,
251251
}
252252
break;
253253

254-
case OpenNettyMqttAttributes.SmartMeterPowerCutMode or OpenNettyMqttAttributes.SmartMeterRateType
255-
when operation is OpenNettyMqttOperation.Get:
256-
_ = await _controller.GetSmartMeterInformationAsync(endpoint);
257-
break;
258-
259254
case OpenNettyMqttAttributes.Scenario when operation is OpenNettyMqttOperation.Set:
260255
switch (message.ConvertPayloadToString()?.ToLowerInvariant())
261256
{
262257
case "action" when endpoint.HasCapability(OpenNettyCapabilities.BasicScenario):
263258
await _controller.DispatchBasicScenarioAsync(endpoint);
264259
break;
265260

261+
case "down" when endpoint.HasCapability(OpenNettyCapabilities.StopUpDownScenario):
262+
await _controller.DispatchStopUpDownScenarioAsync(endpoint, OpenNettyModels.Automation.ShutterState.Down);
263+
break;
264+
266265
case "on" when endpoint.HasCapability(OpenNettyCapabilities.OnOffScenario):
267266
await _controller.DispatchOnOffScenarioAsync(endpoint, OpenNettyModels.Lighting.SwitchState.On);
268267
break;
269268

270269
case "off" when endpoint.HasCapability(OpenNettyCapabilities.OnOffScenario):
271270
await _controller.DispatchOnOffScenarioAsync(endpoint, OpenNettyModels.Lighting.SwitchState.Off);
272271
break;
272+
273+
case "stop" when endpoint.HasCapability(OpenNettyCapabilities.StopUpDownScenario):
274+
await _controller.DispatchStopUpDownScenarioAsync(endpoint, OpenNettyModels.Automation.ShutterState.Stopped);
275+
break;
276+
277+
case "up" when endpoint.HasCapability(OpenNettyCapabilities.StopUpDownScenario):
278+
await _controller.DispatchStopUpDownScenarioAsync(endpoint, OpenNettyModels.Automation.ShutterState.Up);
279+
break;
273280
}
274281
break;
275282

276283
case OpenNettyMqttAttributes.SmartMeterIndexes when operation is OpenNettyMqttOperation.Get:
277284
_ = await _controller.GetSmartMeterIndexesAsync(endpoint);
278285
break;
279286

287+
case OpenNettyMqttAttributes.SmartMeterPowerCutMode or OpenNettyMqttAttributes.SmartMeterRateType
288+
when operation is OpenNettyMqttOperation.Get:
289+
_ = await _controller.GetSmartMeterInformationAsync(endpoint);
290+
break;
291+
292+
case OpenNettyMqttAttributes.ShutterPosition when operation is OpenNettyMqttOperation.Get:
293+
_ = await _controller.GetShutterPositionAsync(endpoint);
294+
break;
295+
296+
case OpenNettyMqttAttributes.ShutterPosition when operation is OpenNettyMqttOperation.Set:
297+
if (!ushort.TryParse(message.PayloadSegment, CultureInfo.InvariantCulture, out var position))
298+
{
299+
throw new InvalidDataException(SR.GetResourceString(SR.ID0075));
300+
}
301+
302+
await _controller.SetShutterPositionAsync(endpoint, position);
303+
break;
304+
305+
case OpenNettyMqttAttributes.ShutterState when operation is OpenNettyMqttOperation.Get:
306+
_ = await _controller.GetShutterStateAsync(endpoint);
307+
break;
308+
309+
case OpenNettyMqttAttributes.ShutterState when operation is OpenNettyMqttOperation.Set:
310+
switch (message.ConvertPayloadToString()?.ToLowerInvariant())
311+
{
312+
case "close":
313+
await _controller.MoveShutterUpAsync(endpoint);
314+
break;
315+
316+
case "open":
317+
await _controller.MoveShutterDownAsync(endpoint);
318+
break;
319+
320+
case "stop":
321+
await _controller.StopShutterAsync(endpoint);
322+
break;
323+
}
324+
break;
325+
280326
case OpenNettyMqttAttributes.SwitchState when operation is OpenNettyMqttOperation.Get:
281327
_ = await _controller.GetSwitchStateAsync(endpoint);
282328
break;

src/OpenNetty/IOpenNettyService.cs

-10
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ public interface IOpenNettyService
2222
/// <param name="address">The address, if applicable.</param>
2323
/// <param name="medium">The medium to use or <see langword="null"/> to use the default medium.</param>
2424
/// <param name="mode">The mode to use or <see langword="null"/> to use the default mode.</param>
25-
/// <param name="filter">
26-
/// The delegate called by the service to filter the returned dimensions.
27-
/// If set to <see langword="null"/>, only the requested dimension is returned.
28-
/// </param>
2925
/// <param name="gateway">The gateway used to send the message.</param>
3026
/// <param name="options">The transmission options to use.</param>
3127
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
@@ -39,7 +35,6 @@ public interface IOpenNettyService
3935
OpenNettyAddress? address = null,
4036
OpenNettyMedium? medium = null,
4137
OpenNettyMode? mode = null,
42-
Func<OpenNettyDimension, ValueTask<bool>>? filter = null,
4338
OpenNettyGateway? gateway = null,
4439
OpenNettyTransmissionOptions options = OpenNettyTransmissionOptions.None,
4540
CancellationToken cancellationToken = default);
@@ -106,10 +101,6 @@ ValueTask ExecuteCommandAsync(
106101
/// <param name="address">The address, if applicable.</param>
107102
/// <param name="medium">The medium to use or <see langword="null"/> to use the default medium.</param>
108103
/// <param name="mode">The mode to use or <see langword="null"/> to use the default mode.</param>
109-
/// <param name="filter">
110-
/// The delegate called by the service to filter the returned dimensions.
111-
/// If set to <see langword="null"/>, only the requested dimension is returned.
112-
/// </param>
113104
/// <param name="gateway">The gateway used to send the message.</param>
114105
/// <param name="options">The transmission options to use.</param>
115106
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
@@ -122,7 +113,6 @@ ValueTask<ImmutableArray<string>> GetDimensionAsync(OpenNettyProtocol protocol,
122113
OpenNettyAddress? address = null,
123114
OpenNettyMedium? medium = null,
124115
OpenNettyMode? mode = null,
125-
Func<OpenNettyDimension, ValueTask<bool>>? filter = null,
126116
OpenNettyGateway? gateway = null,
127117
OpenNettyTransmissionOptions options = OpenNettyTransmissionOptions.None,
128118
CancellationToken cancellationToken = default);

src/OpenNetty/OpenNettyCapabilities.cs

+25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ public static class OpenNettyCapabilities
2121
/// </summary>
2222
public static readonly OpenNettyCapability AdvancedDimmingState = new("Advanced dimming state");
2323

24+
/// <summary>
25+
/// Advanced shutter control.
26+
/// </summary>
27+
public static readonly OpenNettyCapability AdvancedShutterControl = new("Advanced shutter control");
28+
29+
/// <summary>
30+
/// Advanced shutter state.
31+
/// </summary>
32+
public static readonly OpenNettyCapability AdvancedShutterState = new("Advanced shutter state");
33+
2434
/// <summary>
2535
/// Basic dimming control.
2636
/// </summary>
@@ -36,6 +46,16 @@ public static class OpenNettyCapabilities
3646
/// </summary>
3747
public static readonly OpenNettyCapability BasicScenario = new("Basic scenario");
3848

49+
/// <summary>
50+
/// Basic shutter control.
51+
/// </summary>
52+
public static readonly OpenNettyCapability BasicShutterControl = new("Basic shutter control");
53+
54+
/// <summary>
55+
/// Basic shutter state.
56+
/// </summary>
57+
public static readonly OpenNettyCapability BasicShutterState = new("Basic shutter state");
58+
3959
/// <summary>
4060
/// Battery.
4161
/// </summary>
@@ -126,6 +146,11 @@ public static class OpenNettyCapabilities
126146
/// </summary>
127147
public static readonly OpenNettyCapability SmartMeterInformation = new("Smart meter information");
128148

149+
/// <summary>
150+
/// Stop/up/down scenario.
151+
/// </summary>
152+
public static readonly OpenNettyCapability StopUpDownScenario = new("Stop/up/down scenario");
153+
129154
/// <summary>
130155
/// Timed scenario.
131156
/// </summary>

src/OpenNetty/OpenNettyCommands.cs

+21
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,27 @@ public static class Lighting
8282
public static readonly OpenNettyCommand DimStop = new(OpenNettyCategories.Lighting, "38");
8383
}
8484

85+
/// <summary>
86+
/// Automation commands (WHO = 2).
87+
/// </summary>
88+
public static class Automation
89+
{
90+
/// <summary>
91+
/// Stop (WHAT = 0).
92+
/// </summary>
93+
public static readonly OpenNettyCommand Stop = new(OpenNettyCategories.Automation, "0");
94+
95+
/// <summary>
96+
/// Up (WHAT = 1).
97+
/// </summary>
98+
public static readonly OpenNettyCommand Up = new(OpenNettyCategories.Automation, "1");
99+
100+
/// <summary>
101+
/// Down (WHAT = 2).
102+
/// </summary>
103+
public static readonly OpenNettyCommand Down = new(OpenNettyCategories.Automation, "2");
104+
}
105+
85106
/// <summary>
86107
/// Temperature control commands (WHO = 4).
87108
/// </summary>

0 commit comments

Comments
 (0)