|
|
@@ -0,0 +1,182 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using TeamAAS_VP.Core.Lights;
|
|
|
+using TeamAAS_VP.Interfaces;
|
|
|
+using TeamAAS_VP.Models;
|
|
|
+using TeamAAS_VP.Models.Lights;
|
|
|
+
|
|
|
+namespace TeamAAS_VP.Services
|
|
|
+{
|
|
|
+ public class LightManagerService : ILightManagerService
|
|
|
+ {
|
|
|
+ private readonly Dictionary<int, ILightController> _controllers;
|
|
|
+ private readonly Dictionary<int, ILightChannel> _globalChannels;
|
|
|
+ private readonly Dictionary<LightModel, Func<int, TeamAAS_VP.Models.Lights.LightControllerConfig, ILightController>> _controllerFactories;
|
|
|
+ private int _nextGlobalChannelId = 0;
|
|
|
+
|
|
|
+ public IReadOnlyDictionary<int, ILightController> Controllers => _controllers;
|
|
|
+ public IReadOnlyDictionary<int, ILightChannel> GlobalChannels => _globalChannels;
|
|
|
+
|
|
|
+ public event EventHandler<LightControllerEventArgs> ControllerAdded;
|
|
|
+ public event EventHandler<LightControllerEventArgs> ControllerRemoved;
|
|
|
+ public event EventHandler<LightChannelEventArgs> ChannelStatusChanged;
|
|
|
+
|
|
|
+ public LightManagerService()
|
|
|
+ {
|
|
|
+ _controllers = new Dictionary<int, ILightController>();
|
|
|
+ _globalChannels = new Dictionary<int, ILightChannel>();
|
|
|
+ _controllerFactories = new Dictionary<LightModel, Func<int, TeamAAS_VP.Models.Lights.LightControllerConfig, ILightController>>();
|
|
|
+
|
|
|
+ RegisterDefaultFactories();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RegisterDefaultFactories()
|
|
|
+ {
|
|
|
+ // 注册KCS控制器工厂
|
|
|
+ RegisterControllerFactory(LightModel.KCS_KDC_12V60W_4T, (id, config) =>
|
|
|
+ {
|
|
|
+ if (config == null) throw new ArgumentNullException(nameof(config));
|
|
|
+ var protocol = new SerialPortProtocol(config.SerialPortConfig);
|
|
|
+ return new KCSLightController(id, protocol, config.ChannelCount);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void RegisterControllerFactory(LightModel model, Func<int, TeamAAS_VP.Models.Lights.LightControllerConfig, ILightController> factory)
|
|
|
+ {
|
|
|
+ _controllerFactories[model] = factory;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<ILightController> RegisterControllerAsync(int id, TeamAAS_VP.Models.Lights.LightControllerConfig configuration)
|
|
|
+ {
|
|
|
+ if (configuration == null) throw new ArgumentNullException(nameof(configuration));
|
|
|
+
|
|
|
+ if (_controllers.ContainsKey(id))
|
|
|
+ throw new ArgumentException($"Controller with id '{id}' already exists");
|
|
|
+
|
|
|
+ if (!_controllerFactories.TryGetValue(configuration.LightModel, out var factory))
|
|
|
+ throw new ArgumentException($"No factory registered for model '{configuration.LightModel}'");
|
|
|
+
|
|
|
+ var controller = factory(id, configuration);
|
|
|
+ if (controller == null)
|
|
|
+ throw new InvalidOperationException("Factory returned null controller");
|
|
|
+
|
|
|
+ _controllers[id] = controller;
|
|
|
+
|
|
|
+ // 映射全局通道
|
|
|
+ for (int i = 0; i < controller.Channels.Count; i++)
|
|
|
+ {
|
|
|
+ var channelConfig = configuration.ChannelConfigs[i];
|
|
|
+ int globalIndex = channelConfig.GlobalIndex;
|
|
|
+
|
|
|
+ // 检查该全局ID是否已被占用
|
|
|
+ if (_globalChannels.ContainsKey(globalIndex))
|
|
|
+ {
|
|
|
+ // 自动重新分配全局ID
|
|
|
+ globalIndex = _nextGlobalChannelId++;
|
|
|
+ }
|
|
|
+ else if (globalIndex >= _nextGlobalChannelId)
|
|
|
+ {
|
|
|
+ // 更新下一个可用ID
|
|
|
+ _nextGlobalChannelId = globalIndex + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新配置中的GlobalIndex(如果需要)
|
|
|
+ if (channelConfig.GlobalIndex != globalIndex)
|
|
|
+ {
|
|
|
+ channelConfig.GlobalIndex = globalIndex;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 建立映射
|
|
|
+ _globalChannels[globalIndex] = controller.Channels[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ ControllerAdded?.Invoke(this, new LightControllerEventArgs(controller));
|
|
|
+ return controller;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> UnregisterControllerAsync(int controllerId)
|
|
|
+ {
|
|
|
+ if (!_controllers.TryGetValue(controllerId, out var controller))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // 移除全局通道映射
|
|
|
+ var channelsToRemove = _globalChannels
|
|
|
+ .Where(kvp => controller.Channels.Contains(kvp.Value))
|
|
|
+ .Select(kvp => kvp.Key)
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ foreach (var channelId in channelsToRemove)
|
|
|
+ {
|
|
|
+ _globalChannels.Remove(channelId);
|
|
|
+ }
|
|
|
+
|
|
|
+ _controllers.Remove(controllerId);
|
|
|
+ await controller.DisconnectAsync();
|
|
|
+ controller.Dispose();
|
|
|
+
|
|
|
+ ControllerRemoved?.Invoke(this, new LightControllerEventArgs(controller));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> SetGlobalChannelBrightnessAsync(int globalChannelId, int brightness)
|
|
|
+ {
|
|
|
+ if (!_globalChannels.TryGetValue(globalChannelId, out var channel))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var result = await channel.SetBrightnessAsync(brightness);
|
|
|
+ ChannelStatusChanged?.Invoke(this, new LightChannelEventArgs(channel, channel.IsOn, channel.Brightness));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> TurnOnGlobalChannelAsync(int globalChannelId)
|
|
|
+ {
|
|
|
+ if (!_globalChannels.TryGetValue(globalChannelId, out var channel))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var result = await channel.TurnOnAsync();
|
|
|
+ ChannelStatusChanged?.Invoke(this, new LightChannelEventArgs(channel, channel.IsOn, channel.Brightness));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> TurnOffGlobalChannelAsync(int globalChannelId)
|
|
|
+ {
|
|
|
+ if (!_globalChannels.TryGetValue(globalChannelId, out var channel))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ var result = await channel.TurnOffAsync();
|
|
|
+ ChannelStatusChanged?.Invoke(this, new LightChannelEventArgs(channel, channel.IsOn, channel.Brightness));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> ConnectAllAsync()
|
|
|
+ {
|
|
|
+ var tasks = _controllers.Values.Select(c => c.ConnectAsync());
|
|
|
+ var results = await Task.WhenAll(tasks);
|
|
|
+ return results.All(r => r);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<bool> DisconnectAllAsync()
|
|
|
+ {
|
|
|
+ foreach (var controller in _controllers.Values)
|
|
|
+ {
|
|
|
+ await controller.DisconnectAsync();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task SaveConfigurationAsync(string filePath)
|
|
|
+ {
|
|
|
+ // 实现配置保存
|
|
|
+ return Task.CompletedTask;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Task LoadConfigurationAsync(string filePath)
|
|
|
+ {
|
|
|
+ // 实现配置加载
|
|
|
+ return Task.CompletedTask;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|