You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1136 lines
44 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Application.Domain.Entities;
using Application.Models;
using Infrastructure.Data;
using Infrastructure.Extensions;
using Infrastructure.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace FBeeService
{
public class DeviceService : IDisposable
{
private readonly IHostingEnvironment _env;
private readonly IConfiguration _configuration;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IServiceProvider _applicationServices;
private CancellationTokenSource _tokenSource;
private readonly Dictionary<int, int> _types = new Dictionary<int, int>();
private readonly ConcurrentDictionary<string, TcpClientWrapper> Clients = new ConcurrentDictionary<string, TcpClientWrapper>();
public DeviceService(IHostingEnvironment env, IServiceProvider applicationServices, IConfiguration configuration, IHttpClientFactory httpClientFactory)
{
this._env = env;
this._applicationServices = applicationServices;
this._configuration = configuration;
this._httpClientFactory = httpClientFactory;
this._tokenSource = new CancellationTokenSource();
}
public void Start()
{
Task.Run(async () =>
{
while (!_tokenSource.IsCancellationRequested)
{
try
{
foreach (var item in this.Clients)
{
this.X9d(item.Key);
}
}
catch (Exception ex)
{
ex.PrintStack();
}
await Task.Delay(1000 * 60);
}
});
Task.Run(async () =>
{
while (!_tokenSource.IsCancellationRequested)
{
try
{
Refresh();
}
catch (Exception ex)
{
ex.PrintStack();
}
await Task.Delay(this._configuration.GetValue<int>("timer.seconds") * 1000);
}
});
}
#region api
/// <summary>
/// 0x81获取当前连接所有设备
/// </summary>
/// <param name="sn"></param>
public void X81(string sn)
{
Console.WriteLine($"refresh {sn}");
this.Write(sn, RequestType.x81);
}
/// <summary>
/// 接收当前连接的设备信息返回值
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X01(string sn, byte[] data)
{
var create = false;
try
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var profileId = ms.ReadInt();
var deviceId = ms.ReadInt();
var deviceType = DeviceId.List.FirstOrDefault(o => o.RawDeviceId == deviceId);
if (deviceType != null)
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device == null)
{
create = true;
device = new FBeeDevice
{
Sn = sn,
Name = deviceType.Name,
EName = deviceType.EName,
Icon = deviceType.Icon,
CategoryNumber = deviceType.RawDeviceId,
CategoryName = deviceType.Category
};
deviceRepo.Add(device);
}
device.DataType = responseType;
device.DataLength = dataLength;
device.Address = address;
device.Endpoint = endpoint;
device.ProfileId = profileId;
device.DeviceId = deviceId;
device.SwitchState = ms.ReadByte();
device.NameLength = ms.ReadByte();
if (device.NameLength > 0)
{
device.CName = ms.ReadASIIString(device.NameLength);
}
device.IsOnline = ms.ReadByte();
device.IEEE = ms.ReadHexString(8);
device.SNLength = ms.ReadByte();
device.RawSN = ms.ReadHexString(device.SNLength);
device.ZoneType = ms.ReadInt();
if (device.DeviceId == 0x402)
{
if (device.ZoneType == 0x0028)
{
device.Name = "烟雾传感器";
}
else if (device.ZoneType == 0x000d)
{
device.Name = "红外感应器";
}
}
device.Battery = ms.ReadByte();
device.EpCount = ms.ReadByte();
device.Data = ms.ReadHexString(4);
device.RawValue = BitConverter.ToString(data);
deviceRepo.SaveChanges();
if (create)
{
this.UpdateStatus(device);
}
}
else
{
Console.WriteLine("uknown device type");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void UpdateStatus(FBeeDevice device)
{
var deviceId = device.DeviceId;
var sn = device.Sn;
var ieee = device.IEEE;
if (new int[] { 0x0002, 0x0009, 0x0081, 0x0202, 0x0220, 0x0051 }.Contains(deviceId))
{
this.X85(sn, ieee);
}
if (deviceId == 0x0220)
{
this.X86(sn, ieee);
this.X87(sn, ieee);
this.X88(sn, ieee);
this.XA9(sn, ieee);
}
else if (deviceId == 0x0163)
{
this.XA70080(sn, ieee);
}
}
/// <summary>
/// 0x95删除指定设备
/// </summary>
/// <param name="sn"></param>
/// <param name="ieee"></param>
public void X95(string sn, string ieee)
{
Console.WriteLine($"delete {ieee} from {sn}");
var list = new List<byte>();
list.AddRange(ieee.HexToBytes());
list.Add(0x01);
this.Write(sn, RequestType.x95, ieee, list, 0);
}
//0x94更改指定设备名
/// <summary>
/// 0x82设置指定设备的开关状态
/// </summary>
/// <param name="sn"></param>
/// <param name="ieee"></param>
/// <param name="status"></param>
public void X82(string sn, string ieee, byte status)
{
var list = new List<byte>();
list.Add(status);
this.Write(sn, RequestType.x82, ieee, list);
}
/// <summary>
/// 0x85-0x07接收指定设备的开关状态
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X07(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device != null)
{
device.SwitchState = ms.ReadInt();
deviceRepo.SaveChanges();
}
else
{
Console.WriteLine($"device {address} hasn't save in database");
}
}
}
}
/// <summary>
/// 0x83设置指定设备的亮度
/// </summary>
/// <param name="sn"></param>
/// <param name="ieee"></param>
/// <param name="value">0-255</param>
public void X83(string sn, string ieee, [Range(0, 255)]byte brightness)
{
var list = new List<byte>();
list.Add(brightness);
list.AddRange(new byte[] { 0x00, 0x00 });
this.Write(sn, RequestType.x83, ieee, list);
}
/// <summary>
/// 0x08接收指定设备的亮度状态返回值
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X08(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device != null)
{
device.Brightness = ms.ReadByte();
deviceRepo.SaveChanges();
}
else
{
Console.WriteLine($"device {address} hasn't save in database");
}
}
}
}
/// <summary>
/// 0x83设置指定设备的颜色即色调和饱和度
/// </summary>
public void X84(string sn, string ieee, [Range(0, 255)]byte hue, [Range(0, 255)]byte saturation)
{
var list = new List<byte>();
list.Add(hue);
list.Add(saturation);
list.AddRange(new byte[] { 0x00, 0x00 });
this.Write(sn, RequestType.x84, ieee, list);
}
/// <summary>
/// 0x09接收指定设备的色调返回值
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X09(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device != null)
{
device.Hue = ms.ReadByte();
deviceRepo.SaveChanges();
}
else
{
Console.WriteLine($"device {address} hasn't save in database");
}
}
}
}
/// <summary>
/// 0x09接收指定设备的饱和度返回值
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X0A(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device != null)
{
device.Saturation = ms.ReadByte();
deviceRepo.SaveChanges();
}
else
{
Console.WriteLine($"device {address} hasn't save in database");
}
}
}
}
/// <summary>
/// 0x85-0x07查询开关状态
/// </summary>
public void X85(string sn, string ieee)
{
var list = new List<byte>();
this.Write(sn, RequestType.x85, ieee, list);
}
/// <summary>
/// 0x86-0x08查询亮度状态
/// </summary>
public void X86(string sn, string ieee)
{
var list = new List<byte>();
this.Write(sn, RequestType.x86, ieee, list);
}
/// <summary>
/// 0x87-0x09查询色度状态
/// </summary>
public void X87(string sn, string ieee)
{
var list = new List<byte>();
this.Write(sn, RequestType.x87, ieee, list);
}
/// <summary>
/// 0x88-0x0a查询饱和度状态
/// </summary>
public void X88(string sn, string ieee)
{
var list = new List<byte>();
this.Write(sn, RequestType.x88, ieee, list);
}
//0x8d
//0x96
//0x8e
//0x8f
//0x97
//0x98
//0x90
//0x91
//0x92
//0x93
//0x8a
//0x8b
//0x8c
//0x99
//0x9a
//0x9b
//0x9c
//0x9d获取网关信息
public void X9d(string sn)
{
this.Write(sn, RequestType.x9d);
}
/// <summary>
/// 0x15接收网关信息
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X15(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var version = ms.ReadASIIString(5);
var snid = ms.ReadHexString(4);
using (var scope = _applicationServices.CreateScope())
{
var gatewayRepo = scope.ServiceProvider.GetService<IRepository<Gateway>>();
var gateway = gatewayRepo.Table().FirstOrDefault(o => o.Sn == sn);
if (gateway == null)
{
Console.WriteLine($"gateway {sn} hasn't save in database");
}
else
{
gateway.Version = version;
gateway.UserName = ms.ReadASIIString(20);
gateway.Password = ms.ReadASIIString(20);
gateway.DeviceCount = ms.ReadByte();
gateway.GroupCount = ms.ReadByte();
gateway.TimerCount = ms.ReadByte();
gateway.SceneCount = ms.ReadByte();
gateway.TaskCount = ms.ReadByte();
var hex = ms.ReadHexString(5);
gateway.CompileVersion = ms.ReadHexString(5);
}
gatewayRepo.SaveChanges();
}
}
}
//0x9e
//0x9f
//0xa0
//0xa1
//0xa2
//0xa3
//0xa4
//0xa5
/// <summary>
/// 0xa8设置指定设备的色温
/// </summary>
public void XA8(string sn, string ieee, [Range(2700, 6500)]ushort color)
{
var list = new List<byte>();
list.AddRange(BitConverter.GetBytes(color));
list.AddRange(new byte[] { 0x00, 0x00 });
this.Write(sn, RequestType.xa8, ieee, list);
}
/// <summary>
/// 0x27接收指定设备的色温返回值
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X27(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
if (device != null)
{
device.ColorTemperature = ms.ReadInt();
deviceRepo.SaveChanges();
}
else
{
Console.WriteLine($"device {address} hasn't save in database");
}
}
}
}
/// <summary>
/// 0080查询红外版本号
/// </summary>
/// <param name="sn"></param>
/// <param name="ieee"></param>
public void XA70080(string sn, string ieee)
{
var list = new List<byte>();
list.Add(0x03);//控制标志
list.Add(0xff);//包长
list.Add(0x00);//包序号
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x02);
list.AddRange(new byte[] { 0x80, 0x00 });
list.Add(0x82);
list[1] = (byte)(list.Count() - 3);
this.Write(sn, RequestType.xa7, ieee, list, 2);
}
/// <summary>
/// 0081开始匹配遥控器
/// </summary>
/// <param name="sn"></param>
/// <param name="ieee"></param>
public void XA70081(string sn, string ieee, string version, [Range(1, 5)]byte type)
{
var list = new List<byte>();
list.Add(0x03);//控制标志
list.Add(0xff);//包长
list.Add(0x00);//包序号
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x09);
list.AddRange(version.HexToBytes());
list.AddRange(new byte[] { 0x81, 0x00 });
list.Add(type);
list[1] = (byte)(list.Count() - 3 + 2);
list.Add((byte)list.Skip(3).Take(12).Select(o => (int)o).Sum());
list.Add(0x0a);
this.Write(sn, RequestType.xa7, ieee, list, 2);
}
public void XA70082(string sn, string ieee, byte type, ushort code)
{
var list = new List<byte>();
list.Add(0x03);//控制标志
list.Add(0xff);//包长
list.Add(0x00);//包序号
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x0b);
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = repo.ReadOnlyTable().FirstOrDefault(o => o.Sn == sn && o.IEEE == ieee);
var version = device.IRVersion;
list.AddRange(version.HexToBytes());
}
list.AddRange(new byte[] { 0x82, 0x00 });
list.Add(type);
list.AddRange(BitConverter.GetBytes(code));
list[1] = (byte)(list.Count() - 3 + 1);
list.Add((byte)list.Skip(5).Take(12).Select(o => (int)o).Sum());
this.Write(sn, RequestType.xa7, ieee, list, 2);
}
public void XA70083(string sn, string ieee, byte type, ushort code)
{
if (type == 1)
{
if (code <= 602)
{
throw new Exception($"code {code} must > 602 when type is {type} ");
}
}
else
{
if (code <= 43)
{
throw new Exception($"code {code} must > 43 when type is {type} ");
}
}
var list = new List<byte>();
list.Add(0x03);//控制标志
list.Add(0xff);//包长
list.Add(0x00);//包序号
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x0b);
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = repo.ReadOnlyTable().FirstOrDefault(o => o.Sn == sn && o.IEEE == ieee);
var version = device.IRVersion;
list.AddRange(version.HexToBytes());
}
list.AddRange(new byte[] { 0x83, 0x00 });
list.Add(type);
list.AddRange(BitConverter.GetBytes(code));
list[1] = (byte)(list.Count() - 3 + 2);
list.Add((byte)list.Skip(5).Take(12).Select(o => (int)o).Sum());
list.Add(0x0a);
this.Write(sn, RequestType.xa7, ieee, list, 2);
}
/// <summary>
/// 0xa9-0x27查询色温状态
/// </summary>
public void XA9(string sn, string ieee)
{
var list = new List<byte>();
this.Write(sn, RequestType.xa9, ieee, list);
}
//0xab
///// <summary>
///// 0xa7查询红外数据
///// </summary>
///// <param name="sn"></param>
//public void XA7X05(string sn, string ieee)
//{
// Console.WriteLine($"search {ieee} ir data from {sn}");
// this.Clients.TryGetValue(sn, out TcpClientWrapper client);
// using (var scope = _applicationServices.CreateScope())
// {
// var repo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
// var device = repo.ReadOnlyTable().FirstOrDefault(o => o.IsOnline != 0 && o.IEEE == ieee);
// var address = device.Address;
// var list = new List<byte>();
// list.Add(0x04);
// list.AddRange(new byte[] { 0x00, 0x00, 0x00 });
// //list.AddRange(address.HexToBytes());
// //list.Add((byte)device.Endpoint);
// list.Add(0x05);
// this.Write(sn, RequestType.xa7, list);
// }
//}
//0xac
//0xaf
//0xb0
/// <summary>
/// 0x70设备上报信息
/// </summary>
/// <param name="sn"></param>
/// <param name="data"></param>
private void X70(string sn, byte[] data)
{
using (var ms = new MemoryStream(data))
{
var responseType = ms.ReadByte();
var dataLength = ms.ReadByte();
var address = ms.ReadHexStringDesc(2);
var endpoint = ms.ReadByte();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = deviceRepo.Table().FirstOrDefault(o => o.Sn == sn && o.Address == address);
var clusterId = (ClusterId)ms.ReadInt();
if (device != null)
{
var reportCount = ms.ReadByte();
var props = new Dictionary<int, byte[]>();
for (int i = 0; i < reportCount; i++)
{
var propId = ms.ReadInt();
var propDataTypeValue = ms.ReadByte();
int propDataLength;
if (Enum.IsDefined(typeof(FBeeDataType), propDataTypeValue))
{
var propDataType = (FBeeDataType)propDataTypeValue;
if (propDataType == FBeeDataType.bitstring || propDataType == FBeeDataType.characterstring)
{
propDataLength = ms.ReadByte();
}
else if (propDataType == FBeeDataType.longbitstring || propDataType == FBeeDataType.longcharacterstring)
{
propDataLength = ms.ReadInt();
}
else if (propDataType == FBeeDataType.sequence || propDataType == FBeeDataType.set || propDataType == FBeeDataType.bag)
{
propDataLength = ms.ReadInt();
}
else if (propDataType == FBeeDataType.unknown)
{
propDataLength = 0;
}
else
{
try
{
propDataLength = Convert.ToInt32(Regex.Match(propDataType.GetName(), @"(\d+)$").Groups[1].Value);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
propDataLength = 1;
}
}
}
else
{
propDataLength = 1;
}
var propData = ms.Read(propDataLength);
props.Add(propId, propData);
}
if (clusterId == ClusterId.off)
{
var status = props.First().Value[0];
if (status == 0x00)//离网
{
deviceRepo.Delete(device);
}
else if (status == 0x03)//入网
{
}
}
else if (clusterId == ClusterId.light)
{
device.Light = BitConverter.ToInt16(props[0x0000]);
}
else if (clusterId == ClusterId.alarm)
{
device.Warning = BitConverter.ToInt16(props[0x0080]);
var bitArray = new BitArray(props[0x0080]);
device.IsWarning = bitArray[0];
device.UnderVoltage = bitArray[3];
}
else if (clusterId == ClusterId.pm25)
{
device.PM25 = BitConverter.ToInt16(props[0x0000]);
device.PM100 = BitConverter.ToInt16(props[0x0002]);
device.PM10 = BitConverter.ToInt16(props[0x0001]);
}
else if (clusterId == ClusterId.temperature)
{
device.Temperature = BitConverter.ToInt16(props[0x0000]) / 100f;
}
else if (clusterId == ClusterId.humidity)
{
device.Humidity = BitConverter.ToInt16(props[0x0000]) / 100f;
}
else if (clusterId == ClusterId.voltage)
{
device.Voltage = props[0x21][0] / 2f;
}
if (device.DeviceId == 0x0163)
{
if (props.ContainsKey(0x400a))
{
var irdata = props[0x400a];
if (irdata.Length == 10)
{
device.IRVersion = BitConverter.ToString((props[0x400a].Skip(3).Take(6).ToArray())).Replace("-", "").ToLower();
}
else
{
var irtype = BitConverter.ToInt16(irdata.Skip(9).Take(2).ToArray());
if (irtype == 0x0082)
{
var irDeviceType = irdata.Skip(11).First();
if (irDeviceType == 0x01)
{
var keyCode = BitConverter.ToInt16(irdata.Skip(12).Take(2).ToArray());
}
}
}
}
}
deviceRepo.SaveChanges();
}
}
}
}
//0x72
//0xb1
//0xb2
//0xc2
//0xc3
//0xc4
//0xc5
//0x75
#endregion api
public void Refresh()
{
var ips = NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.Select(nic => nic.GetIPProperties().UnicastAddresses)
.SelectMany(o => o.ToList())
.Select(o => o.Address)
.Where(o => o.AddressFamily == AddressFamily.InterNetwork)
.ToList();
var list = new ConcurrentBag<string>();
foreach (var ip in ips)
{
Console.WriteLine($"search:{ip}");
var tokenSource = new CancellationTokenSource();
using (var client = new UdpClient(new IPEndPoint(ip, 0)))
{
var message = Encoding.ASCII.GetBytes("GETIP\r\n");
client.Send(message, message.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 9090));
Task.Run(() =>
{
try
{
var ep = new IPEndPoint(IPAddress.Any, 3702);
while (!tokenSource.IsCancellationRequested)
{
if (client.Available > 0)
{
var buffer = client.Receive(ref ep);
var result = Encoding.ASCII.GetString(buffer);
Console.WriteLine(result);
if (!list.Any(o => o == result))
{
list.Add(result);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}, tokenSource.Token);
Thread.Sleep(1000);
tokenSource.Cancel();
}
}
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Gateway>>();
foreach (var result in list)
{
var sn = Regex.Match(result, @"SN:([^\s]*)").Groups[1].Value;
var ip = Regex.Match(result, @"IP:([^\s]*)").Groups[1].Value;
var gateway = repo.Table().FirstOrDefault(o => o.Sn == sn);
if (gateway == null)
{
gateway = new Gateway { Sn = sn, Ip = ip, Enable = true };
repo.Add(gateway);
repo.SaveChanges();
}
else
{
if (gateway.Ip != ip)
{
gateway.Ip = ip;
repo.Add(gateway);
}
}
}
var gateways = repo.ReadOnlyTable().ToList();
foreach (var gateway in gateways)
{
if (gateway.Enable)
{
if (Clients.Any(o => o.Key == gateway.Sn))
{
Clients.TryGetValue(gateway.Sn, out TcpClientWrapper client);
if (client.Ip != gateway.Ip)
{
this.Connect(client);
}
else
{
if (!client.Client.Connected)
{
this.Connect(client);
}
}
}
else
{
var client = new TcpClientWrapper { Sn = gateway.Sn, Ip = gateway.Ip, Client = new TcpClient() };
Clients.TryAdd(gateway.Sn, client);
this.Connect(client);
}
this.X81(gateway.Sn);
}
else
{
if (Clients.Any(o => o.Key == gateway.Sn))
{
Clients.TryRemove(gateway.Sn, out TcpClientWrapper client);
if (client.Client.Connected)
{
client.Client.Close();
}
}
}
}
}
}
private void Connect(TcpClientWrapper client)
{
try
{
if (client != null)
{
client.Client.Dispose();
client.Client = new TcpClient();
}
Console.WriteLine($"connect {client.Ip} for {client.Sn}");
client.Client.Connect(client.Ip, 8001);
new Thread(() =>
{
var stream = client.Client.GetStream();
while (client.Client.Connected)
{
try
{
if (stream.DataAvailable)
{
var buffer = new byte[512];
var length = stream.Read(buffer);
var data = buffer.ToList().Take(length).ToArray();
Console.WriteLine($"response:{BitConverter.ToString(data)}");
this.Handle(client.Sn, data);
}
}
catch (Exception ex)
{
ex.PrintStack("read stream error");
break;
}
}
}).Start();
this.X9d(client.Sn);
}
catch (Exception ex)
{
ex.PrintStack();
}
}
private void Handle(string sn, byte[] data)
{
var length = 2 + data[1];
if (data.Length > length)
{
Handle(sn, data.Skip(length).ToArray());
}
this.HandleInternal(sn, data.Take(length).ToArray());
}
private void HandleInternal(string sn, byte[] data)
{
Console.WriteLine($"read:{BitConverter.ToString(data).Replace("-", " ")}");
var responseType = data[0];
if (responseType == ResponseType.x15)
{
this.X15(sn, data);
}
else if (responseType == ResponseType.x01)
{
this.X01(sn, data);
}
else if (responseType == ResponseType.x07)
{
this.X07(sn, data);
}
else if (responseType == ResponseType.x08)
{
this.X08(sn, data);
}
else if (responseType == ResponseType.x09)
{
this.X09(sn, data);
}
else if (responseType == ResponseType.x0a)
{
this.X0A(sn, data);
}
else if (responseType == ResponseType.x27)
{
this.X27(sn, data);
}
else if (responseType == ResponseType.x70)
{
this.X70(sn, data);
}
else
{
Console.WriteLine($"{responseType} hasn't handle");
}
}
private void Write(string sn, byte commandType, string ieee = null, List<byte> command = null, int format = 1, byte addressType = 0x02)
{
this.Clients.TryGetValue(sn, out TcpClientWrapper client);
var data = new List<byte>();
data.AddRange(sn.HexToBytes().Reverse());//sn号
data.Add(RequestType.xfe);//控制标志
data.Add(commandType);//控制类型
if (command != null)
{
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<FBeeDevice>>();
var device = repo.ReadOnlyTable().FirstOrDefault(o => o.Sn == sn && o.IEEE == ieee);
if (format == 0)
{
data.Add((byte)(command.Count() + 1 + 2));//数据总长
data.Add(addressType);//地址模式
data.AddRange(device.Address.HexToBytes().Reverse());
data.AddRange(command);
}
else if (format == 1)
{
data.Add((byte)(command.Count() + 1 + 2 + 6 + 1 + 2));//数据总长
data.Add(addressType);//地址模式
data.AddRange(device.Address.HexToBytes().Reverse());
data.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
data.Add((byte)device.Endpoint);
data.AddRange(new byte[] { 0x00, 0x00 });
data.AddRange(command);
}
else if (format == 2)
{
data.Add((byte)(command.Count() + 2 + 1));//数据总长
data.AddRange(device.Address.HexToBytes().Reverse());
data.Add((byte)device.Endpoint);
data.AddRange(command);
}
}
}
var head = BitConverter.GetBytes(data.Count() + 2).ToList();//消息总长
if (BitConverter.IsLittleEndian)
{
head.Reverse();
}
head = head.Skip(2).Reverse().ToList();
var list = new List<byte>();
list.AddRange(head);
list.AddRange(data);
var bytes = list.ToArray();
this.Send(client, bytes);
}
private void Send(TcpClientWrapper client, byte[] bytes)
{
Console.WriteLine($"write:{BitConverter.ToString(bytes).Replace("-", " ")}");
try
{
client.Client.GetStream().Write(bytes);
}
catch (IOException)
{
if (!client.Client.Connected)
{
this.Connect(client);
client.Client.GetStream().Write(bytes);
}
}
}
private NotifyModel CreateModel(string name, string number, string path, string icon)
{
var host = string.IsNullOrEmpty(this._configuration["server.ip"]) ? "localhost" : this._configuration["server.ip"];
var port = Convert.ToInt32(Regex.Match(this._configuration["server.urls"], @"(?<=:)\d+").Value);
return new NotifyModel
{
CategoryName = "电器",
CategoryNumber = "20",
Name = name,
Number = number,
Icon = icon,
IsOnline = true,
BaseUrl = $"http://{host}:{port}/{path}",
ApiPath = "/api"
};
}
private void NotifyServer(NotifyModel model)
{
var url = $"http://{this._configuration["node.url"]}/Notify";
Console.WriteLine(url);
var hc = this._httpClientFactory.CreateClient();
var task = this._httpClientFactory.CreateClient().PostAsync(url, new FormUrlEncodedContent(model.ToList()));
task.Wait();
using (var response = task.Result)
{
using (var content = response.Content)
{
var value = content.ReadAsStringAsync().Result;
Console.WriteLine($"end:{url}:{value}");
}
}
}
public void Dispose()
{
Console.WriteLine("dispose...");
this._tokenSource.Cancel();
foreach (var item in Clients)
{
if (item.Value.Client != null)
{
item.Value.Client.Dispose();
}
}
}
}
}