-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSmartLightingMcpQueryService.cs
More file actions
172 lines (156 loc) · 9.45 KB
/
SmartLightingMcpQueryService.cs
File metadata and controls
172 lines (156 loc) · 9.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
namespace CasCap.Services;
/// <summary>
/// MCP wrapper that exposes all lighting operations as MCP tools — KNX ceiling/wall lights
/// (via <see cref="IKnxQueryService"/>), smart bulbs (via <see cref="IWizQueryService"/>)
/// and smart-plug-controlled lights (via <see cref="IShellyQueryService"/>).
/// </summary>
/// <remarks>
/// All three dependencies are nullable because this service is registered when any of
/// Wiz, KNX, or Shelly is enabled, but the other features may not be present in the
/// current deployment.
/// </remarks>
[McpServerToolType]
public partial class SmartLightingMcpQueryService(
IKnxQueryService? knxQuerySvc = null,
IWizQueryService? wizQuerySvc = null,
IShellyQueryService? shellyQuerySvc = null)
{
//TODO: I dont like these group addresses hardcoded here, need to change this
const string DoorLightGroupName = "EG-LI-Entrance(FrontDoor)-Outdoor-DL";
const string OfficeLightGroupName = "DG-LI-Office-DL-South";
const string DeskLampDeviceName = "DG-SD-Office(DeskLamp)";
/// <inheritdoc cref="IKnxQueryService.SetLightState"/>
[McpServerTool]
[Description("Changes a single light — switch on/off, dim or set colour. Requires KNX feature.")]
public Task<KnxStateChangeResponse> ChangeHouseLightState(
[Description("GroupName (LI category) plus exactly one of: IsOn, DimValue (0–100) or HexColour (6-char hex).")]
KnxLightStateChangeRequest request,
[Description("When true, validates without sending commands.")]
bool dryRun = false,
CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.SetLightState(request, dryRun, cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <inheritdoc cref="IKnxQueryService.TurnAllLightsOff"/>
[McpServerTool]
[Description("Turns off every light that is currently on in the house. Requires KNX feature.")]
public Task<string[]> SwitchOffAllHouseLights(CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.TurnAllLightsOff(cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <summary>Turns on the exterior light at the front door.</summary>
[McpServerTool]
[Description("Turns on the exterior light at the front door.")]
public Task<KnxStateChangeResponse> TurnOnHouseDoorLight(CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.SetLightState(new KnxLightStateChangeRequest { GroupName = DoorLightGroupName, IsOn = true }, cancellationToken: cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <summary>Turns off the exterior light at the front door.</summary>
[McpServerTool]
[Description("Turns off the exterior light at the front door.")]
public Task<KnxStateChangeResponse> TurnOffHouseDoorLight(CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.SetLightState(new KnxLightStateChangeRequest { GroupName = DoorLightGroupName, IsOn = false }, cancellationToken: cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <summary>Turns on all lights in the DG Office.</summary>
[McpServerTool]
[Description("Turns on all lights in the top-floor (DG) office.")]
public Task<KnxStateChangeResponse> TurnOnHouseOfficeLights(CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.SetLightState(new KnxLightStateChangeRequest { GroupName = OfficeLightGroupName, IsOn = true }, cancellationToken: cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <summary>Turns off all lights in the DG Office.</summary>
[McpServerTool]
[Description("Turns off all lights in the top-floor (DG) office.")]
public Task<KnxStateChangeResponse> TurnOffHouseOfficeLights(CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.SetLightState(new KnxLightStateChangeRequest { GroupName = OfficeLightGroupName, IsOn = false }, cancellationToken: cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <inheritdoc cref="IKnxQueryService.ListLights"/>
[McpServerTool]
[Description("Lists all lights with full detail — switch, dim, colour and lux, optionally filtered by room.")]
public Task<List<KnxLight>> GetHouseSmartLights(
[Description("Room filter (e.g. Kitchen, Office, LivingRoom).")]
string? room = null,
CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.ListLights(room, cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <inheritdoc cref="IKnxQueryService.GetLight"/>
[McpServerTool]
[Description("Gets one light by group name — switch, dim, colour and lux.")]
public Task<KnxLight?> GetHouseLightState(
[Description("e.g. DG-LI-Office-DL-South.")]
string groupName,
CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.GetLight(groupName, cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <inheritdoc cref="IKnxQueryService.GetAllLighting(string?, string?, CancellationToken)"/>
[McpServerTool]
[Description("Quick on/off overview of all lights, filterable by floor and orientation.")]
public Task<Dictionary<string, State?>> GetHouseLightStates(
[Description("Values: KG (basement), EG (ground), OG (upper), DG (top).")]
string? floor = null,
[Description("Values: North, East, South, West.")]
string? orientation = null,
CancellationToken cancellationToken = default)
=> knxQuerySvc is not null
? knxQuerySvc.GetAllLighting(floor, orientation, cancellationToken)
: throw new InvalidOperationException("KNX feature is not enabled.");
/// <inheritdoc cref="IWizQueryService.GetDiscoveredBulbs"/>
[McpServerTool]
[Description("Lists all smart bulbs currently discovered on the local network with their state and configuration. Requires Wiz feature.")]
public IReadOnlyDictionary<string, WizBulb> GetSmartLights()
=> wizQuerySvc is not null
? wizQuerySvc.GetDiscoveredBulbs()
: throw new InvalidOperationException("Wiz feature is not enabled.");
/// <inheritdoc cref="IWizQueryService.GetPilot"/>
[McpServerTool]
[Description("Current state of one smart bulb — on/off, brightness, colour, colour temperature and active scene.")]
public Task<WizPilotState?> GetSmartLightState(
[Description("Device name, MAC address, or IP address of the target bulb.")]
string bulbIdentifier,
CancellationToken cancellationToken = default)
=> wizQuerySvc is not null
? wizQuerySvc.GetPilot(bulbIdentifier, cancellationToken)
: throw new InvalidOperationException("Wiz feature is not enabled.");
/// <inheritdoc cref="IWizQueryService.SetPilot"/>
[McpServerTool]
[Description("Adjusts brightness, colour, temperature or scene of one smart bulb.")]
public Task<bool> AdjustSmartLightOutput(
[Description("Device name, MAC address, or IP address of the target bulb.")]
string bulbIdentifier,
[Description("Desired state: include dimming (10–100), temp (2200–6500 K), r/g/b (0–255), sceneId, or any combination.")]
WizSetPilotRequest request,
CancellationToken cancellationToken = default)
=> wizQuerySvc is not null
? wizQuerySvc.SetPilot(bulbIdentifier, request, cancellationToken)
: throw new InvalidOperationException("Wiz feature is not enabled.");
/// <inheritdoc cref="IWizQueryService.SetPowerState"/>
[McpServerTool]
[Description("Turns a single smart bulb on or off.")]
public Task<bool> SetSmartLightPower(
[Description("Device name, MAC address, or IP address of the target bulb.")]
string bulbIdentifier,
[Description("True to turn on, false to turn off.")]
bool on,
CancellationToken cancellationToken = default)
=> wizQuerySvc is not null
? wizQuerySvc.SetPowerState(bulbIdentifier, on, cancellationToken)
: throw new InvalidOperationException("Wiz feature is not enabled.");
/// <summary>Turns on the desk lamp in the top-floor (DG) office via Shelly smart plug.</summary>
[McpServerTool]
[Description("Turns on the desk lamp in the top-floor (DG) office.")]
public Task<ShellyRelayControlResponse?> TurnOnOfficeDeskLamp()
=> shellyQuerySvc is not null
? shellyQuerySvc.SetRelayState(DeskLampDeviceName, turnOn: true)
: throw new InvalidOperationException("Shelly feature is not enabled.");
/// <summary>Turns off the desk lamp in the top-floor (DG) office via Shelly smart plug.</summary>
[McpServerTool]
[Description("Turns off the desk lamp in the top-floor (DG) office.")]
public Task<ShellyRelayControlResponse?> TurnOffOfficeDeskLamp()
=> shellyQuerySvc is not null
? shellyQuerySvc.SetRelayState(DeskLampDeviceName, turnOn: false)
: throw new InvalidOperationException("Shelly feature is not enabled.");
}