Пишу программу для управления умным домом.
Просьба помочь с архитектурой.
В конечном итоге программа будет:
1)Получать команды из UI, от мониторить некоторые виды уведомлений в windows, возможно сигналы с умных датчиков, но это все уже будет реализовываться на уровне главного контроллера, это сейчас не важно;
2) Главный контроллер будет мониторить глобальные события вроде "пришло уведомление", "нажалась кнопка" и сообщать контроллерам устройств.
3) Отдельные контроллеры устройств будут либо отдавать устройствам в сети команды, либо игнорить ивент. Пришел Email, лампочка мигнула, пылесосу пофиг. Вопрос как переделать так, чтобы можно было добавлять новый класс устройства не вмешиваясь в основной код? Сейчас для каждого устройства создается несколько классов. Не факт, что они все нужны, и не факт, что они делают то что нужно.
Появились более конкретные вопросы.
Исходя из выше указанного требования к программе:
1) Где разместить логику поиска устройства в сети? Она однотипная, но каждый класс имеет свой вариант приветственного сообщения для SSDP.
2) Где создавать и хранить контроллеры устройств?
3) Где создавать и хранить кэш устройств? Может для всего этого статические классы написать?
Это пример моего кода с одним из устройств - (SmartBulb) умная лампочка. Просьба не указывать на не архитектурные ошибки, лишний код типа try/catch я тоже удалил.
public partial class MainWindow : Window
{
MainDevicesController DevicesController = new MainDevicesController();
private void Button_FindAllDevices_Click(object sender, RoutedEventArgs e)
{
DevicesController.SearchForDevices();
}
}
Это тот самый главный контроллер
class MainDevicesController
{
SmartBulbController BulbController = new SmartBulbController();
Hashtable Devices = null;
List<Device> Bulbs = null;
public MainDevicesController()
{
}
public bool SearchForDevices()
{
Bulbs = BulbController.FindDevices();
Devices = new Hashtable();
Devices.Add("Bulbs", Bulbs);
return true;
}
}
Этот класс должен добавлять программист, правда не в таком виде
class SmartBulbController
{
private SmartBulbDiscoverer BulbDiscoverer = new SmartBulbDiscoverer();
private List<Device> SmartBulbs = null;
private Bulb Bulb = null;
public List<Device> FindDevices()
{
return SmartBulbs = BulbDiscoverer.DiscoverAllBulbs();
}
public bool IncreaseBulbBrightness()
{
Bulb.IncreaseBrigtness();
return true;
}
public bool DecreaseBulbBrightness(){\\ну то есть дальше все в том же духе}
public bool ToggleBulbPower(){}
public bool ToggleBulbMusicMode(bool value){}
public bool ToggleAmbientLight(){}
public string[] ShowFoundDevices()
{
эта функция пробрасывает "наверх" ответы от лампочек просто для вывода в консоль
}
}
А вот этот уже не должен
class SmartBulbDiscoverer
{
private List<Device> Bulbs = null;
private UdpClient McastClient;
private IPEndPoint McastEndpoint;
public SmartBulbDiscoverer()
{
McastClient = new UdpClient(AddressFamily.InterNetwork);
McastEndpoint = new IPEndPoint(Bulb.McastAddr, Bulb.UdpPort);
}
public List<Device> DiscoverAllBulbs()
{
Bulbs = new List<Device>();
var discoveredBulb = DiscoverBulb();
Bulbs.Add(discoveredBulb);
return Bulbs;
}
public Bulb DiscoverBulb()
{
#region Trying To Join Multicast Group
McastClient.JoinMulticastGroup(Bulb.McastAddr);
#endregion
#region Sending Handshake Message
byte[] data = Encoding.UTF8.GetBytes(Bulb.InviteMessage);
McastClient.Send(data, data.Length, McastEndpoint);
#endregion
#region Trying to receive answer from the device
McastClient.Client.ReceiveTimeout = 3000;
byte[] recData = null;
recData = McastClient.Receive(ref McastEndpoint);
string answer = Encoding.UTF8.GetString(recData);
#endregion
Bulb bulb = new Bulb(answer);
return bulb;
}
}
А этот класс, мне кажется, делает слишком много, разве что сам свои объекты))
class Bulb : Device
{ // > Invite initialization properties
public static readonly string InviteMessage = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1982\r\nMAN: \"ssdp:discover\"\r\nST: wifi_bulb";
public static readonly IPAddress McastAddr = IPAddress.Parse("239.255.255.250");
public static readonly int UdpPort = 1982;
public Bulb(string answer)
{
ParseProperties(answer);
Client = new TcpClient(AddressFamily.InterNetwork);
LocalServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
MusicMode = false;
AmbientLightMode = false;
TcpEndpoint = new IPEndPoint(IPDevice, Port);
Client = new TcpClient(IPDevice.ToString(), Port);
Client.Connect(TcpEndpoint);
Stream = Client.GetStream();
Writer = new StreamWriter(Stream);
Reader = new StreamReader(Stream);
IsConnected = true;
}
// > Parsing
public void ParseProperties(string answer)
{
Answer = answer;
string[] Prop = SplitBulbMessege();
IPDevice = ParseIPAddress(Prop);
Port = ParsePort(Prop);
Properties = new BulbProperties(Prop); //Свойства сами себя инициализируют
}
private string[] SplitBulbMessege(){}
private IPAddress ParseIPAddress(string[] Prop){}
private int ParsePort(String[] Prop)
{
String iP = IPDevice.ToString() + ';';
int Port = int.Parse(Prop[4].Remove(0, iP.Length));
return Port;
}
// > Bulb toolbox
public void PowerToggle()
{
string commandJson = "{\"id\":" + Properties.Id + ",\"method
\":\"toggle\",\"params\":[]}";
Writer.WriteLine(commandJson);
Writer.Flush();
Properties.Power = !Properties.Power;
}
public bool MusicModeToggle(bool value){//тут и дальше в таком же духе}
public void TurnOn(){}
public void TurnOff(){}
public void IncreaseBrigtness(){}
public void SetColor(){}
public void AmbientLightToggle(){}
/*Лампочка умеет работать как в режиме сервера, так и клиента*/
// > Client mode tcp connection properties
public IPAddress IPDevice { get; set; }
private int Port { get; set; }
private IPEndPoint TcpEndpoint { get; set; }
private TcpClient Client { get; set; }
private NetworkStream Stream { get; set; }
private StreamWriter Writer { get; set; }
private StreamReader Reader { get; set; }
// > Server mode tcp connection properties
private string LocalIP { get; set; }
private Socket LocalServer { get; set; }
private Socket ServerModeClient { get; set; }
private NetworkStream ServerStream { get; set; }
private StreamWriter ServerClientWriter { get; set; }
private StreamReader ServerClientReader { get; set; }
private bool AmbientLightMode { get; set; }
public bool MusicMode { get; set; }
public bool IsConnected { get; set; }
public string Answer { get; set; }
// > Bulb visible properties
public BulbProperties Properties;
}
Ну и еще один странный класс. Возможный ответ от устройства программист при добавлении устройства должен обрабатывать сам, кому как не ему знать как их парсить и сохранять. Но не факт что в отдельном классе.
class BulbProperties
{
public BulbProperties(string[] Prop)
{
Id = Convert.ToInt32(Prop[6], 16);
Model = Prop[7];
FwVer = int.Parse(Prop[8]);
Power = (Prop[10] == "on") ? Power = true : Power = false;
Brightness = int.Parse(Prop[11]);
ColorMode = int.Parse(Prop[12]);
ColorTemperature = int.Parse(Prop[13]);
RGB = int.Parse(Prop[14]);
Hue = int.Parse(Prop[15]);
Saturation = int.Parse(Prop[16]);
}
public int Id { get; set; }
public string Model { get; set; }
public int FwVer { get; set; }
public bool Power { get; set; }
public int Brightness {get; set;}
public int ColorMode { get; set; }
public int ColorTemperature { get; set; }
public int RGB { get; set; }
public int Hue { get; set; }
public int Saturation { get; set; }
public string Name { get; set; }
}
Я нашел для себя решение https://docs.microsoft.com/ru-ru/archive/msdn-magazine/2014/january/wpf-build-fault-tolerant-composite-applications Здесь плагины существуют в виде отдельных процессов и бесшовно встраиваются в UI. Взаимодействие необходимой логики плагина с хостом можно прикрутить с помощью интерфейсов. Для общего стиля можно подготовить шаблоны контролов.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Задача программно сгенирировать документ Word, а именно договорДля договора есть определенные правила того что если заголовок начинается...
Такой вот вопрос, может есть тут разработчики, которые подскажут, как можно выйти с такой ситуации
Вопрос теоретический, изучаю ОРМ, Понимаю , что есть кеш первого уровня, он привязан к объекту сессииА есть кеш второго уровня, и он привязан...