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.
iot/projects/IoT/IoT.Shared/DeviceServices/FBee/FBeeService.cs

1400 lines
59 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 Infrastructure.Data;
using Infrastructure.Extensions;
using Application.Models;
using IoT.Shared.Infrastructure;
using Microsoft.EntityFrameworkCore;
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.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace IoT.Shared.DeviceServices.FBee
{
public class FBeeService : BaseDeviceService
{
private readonly ConcurrentDictionary<string, TcpClientWrapper> Clients = new ConcurrentDictionary<string, TcpClientWrapper>();
public FBeeService(IServiceProvider applicationServices, IConfiguration configuration)
: base(applicationServices, configuration)
{
}
#region impl interface
public override void Start()
{
base.Start();
this.HealthCheck();
}
public override void Execute()
{
Refresh();
}
public override void Stop()
{
foreach (var item in Clients)
{
if (item.Value.Client != null)
{
item.Value.Client.Dispose();
}
}
}
#endregion impl interface
#region private
private void HealthCheck()
{
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);
}
});
}
private 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)
{
ex.PrintStack();
}
}, tokenSource.Token);
Thread.Sleep(1000);
tokenSource.Cancel();
}
}
using (var scope = _applicationServices.CreateScope())
{
var categoryRepo = scope.ServiceProvider.GetService<IRepository<Category>>();
var productNumber = "fbee:gateway";
var productRepo = scope.ServiceProvider.GetService<IRepository<Product>>();
var product = productRepo.Table().FirstOrDefault(o => o.Number == productNumber);
var category = categoryRepo.ReadOnlyTable().FirstOrDefault(o => o.Number == "00");
if (product == null)
{
product = new Product
{
Number = productNumber,
Name = "FBee网关",
Icon = "gateway",
ApiJson = this.GetApiJson("/Gateway/"),
CategoryId = category.Id
};
productRepo.Add(product);
productRepo.SaveChanges();
var productDto = product.To<ProductDto>();
productDto.CategoryNumber = category.Number;
this.SendProduct(productDto);
}
var deviceNodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var node = deviceNodeRepo.ReadOnlyTable().FirstOrDefault();
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
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 device = deviceRepo.Table().FirstOrDefault(o => o.Number == sn);
if (device == null)
{
device = new Device
{
Number = sn,
Name = "网关",
Icon = "gateway",
ProductId = product.Id,
NodeId = node.Id,
};
device.ConnectId = this._configuration["connectId"];
deviceRepo.Add(device);
}
device.Ip = ip;
deviceRepo.SaveChanges();
var deviceDto = device.To<DeviceDto>();
deviceDto.ProductNumber = product.Number;
deviceDto.NodeNumber = node.Number;
this.SendDevice(deviceDto);
}
var gateways = deviceRepo.ReadOnlyTable().Where(o => o.Product.Name == "FBee网关").ToList();
foreach (var gateway in gateways)
{
if (Clients.Any(o => o.Key == gateway.Number))
{
Clients.TryGetValue(gateway.Number, 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.Number, Ip = gateway.Ip, Client = new TcpClient() };
Clients.TryAdd(gateway.Number, client);
this.Connect(client);
}
this.X81(gateway.Number);
}
}
}
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 if (responseType == ResponseType.x72)
{
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? ep = null)
{
if (ieee != null && ieee.Contains('-'))
{
ieee = ieee.Split('-')[1];
}
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)
{
byte addressType = 0x02;
var payload = new List<byte>();
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
var device = this.GetDevice(deviceRepo, sn, ieee);
var address = device.GetDataValue(Keys.Address).HexToBytes().Reverse();
var endPoint = Convert.ToInt32(device.GetDataValue(Keys.EndPoint));
if (format == 0)
{
payload.Add((byte)(command.Count() + 1 + 2));//数据总长
payload.Add(addressType);//地址模式
payload.AddRange(address);
payload.AddRange(command);
}
else if (format == 1)
{
payload.Add((byte)(command.Count() + 1 + 2 + 6 + 1 + 2));//数据总长
payload.Add(addressType);//地址模式
payload.AddRange(address);
payload.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
payload.Add(ep ?? (byte)endPoint);
payload.AddRange(new byte[] { 0x00, 0x00 });
payload.AddRange(command);
}
else if (format == 2)
{
payload.Add((byte)(command.Count() + 2 + 1));//数据总长
payload.AddRange(address);
payload.Add(ep ?? (byte)endPoint);
payload.AddRange(command);
}
data.AddRange(payload);
}
}
var MessageLength = BitConverter.GetBytes((ushort)(data.Count() + 2));//消息总长
if (BitConverter.IsLittleEndian)
{
MessageLength.Reverse();
}
var message = new List<byte>();
message.AddRange(MessageLength);
message.AddRange(data);
var bytes = message.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 (Exception ex)
{
ex.PrintStack();
if (!client.Client.Connected)
{
this.Connect(client);
client.Client.GetStream().Write(bytes);
}
}
}
#endregion private
#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)
{
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 switchState = ms.ReadByte();
var nameLength = ms.ReadByte();
var cname = "";
if (nameLength > 0)
{
cname = ms.ReadASIIString(nameLength);
}
var isOnline = ms.ReadByte();
var ieee = ms.ReadHexString(8);
var snLength = ms.ReadByte();
var rawSn = ms.ReadHexString(snLength);
var zoneType = ms.ReadInt();
var deviceType = DeviceId.List.FirstOrDefault(o => o.RawDeviceId == deviceId);
var deviceName = deviceType.Name;
if (deviceId == 0x402)
{
if (zoneType == 0x0028)
{
deviceName = "烟雾传感器";
}
else if (zoneType == 0x000d)
{
deviceName = "红外感应器";
}
}
else if (deviceId == 0x002)
{
if (zoneType == 0x0001)
{
deviceName = "一路开关";
}
else if (zoneType == 0x0002)
{
deviceName = "二路开关";
}
else if (zoneType == 0x0003)
{
deviceName = "三路开关";
}
}
var productNumber = $"fbee:{deviceType.RawDeviceId.ToString("x4")}:{zoneType.ToString("x2")}";
if (deviceType != null)
{
var number = deviceType.RawDeviceId;
var categoryRepo = scope.ServiceProvider.GetService<IRepository<Category>>();
var productRepo = scope.ServiceProvider.GetService<IRepository<Product>>();
var product = productRepo.Table().FirstOrDefault(o => o.Number == productNumber);
var category = categoryRepo.ReadOnlyTable().FirstOrDefault(o => o.Number == deviceType.CategoryNumber);
if (product == null)
{
product = new Product
{
Name = deviceName,
Number = productNumber,
Icon = deviceType.Icon,
CategoryId = category.Id
};
if (deviceName == "插座" || deviceName == "智能插座")
{
product.ApiJson = this.GetApiJson("/Socket/");
}
else if (deviceName == "一路开关")
{
product.ApiJson = this.GetApiJson("/Switch/");
}
else if (deviceName == "二路开关")
{
product.ApiJson = this.GetApiJson("/Switch2/");
}
else if (deviceName == "三路开关")
{
product.ApiJson = this.GetApiJson("/Switch3/");
}
else if (deviceName == "窗帘")
{
product.ApiJson = this.GetApiJson("/Curtain/");
}
else if (deviceName == "调色灯")
{
product.ApiJson = this.GetApiJson("/ColorLight/");
}
else if (deviceName == "红外转发器")
{
product.ApiJson = this.GetApiJson("/Ir/");
}
productRepo.Add(product);
productRepo.SaveChanges();
var productDto = product.To<ProductDto>();
productDto.CategoryNumber = category.Number;
this.SendProduct(productDto);
}
var deviceNodeRepo = scope.ServiceProvider.GetService<IRepository<Node>>();
var node = deviceNodeRepo.ReadOnlyTable().FirstOrDefault();
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
var device = this.GetDevice(deviceRepo, sn, ieee);
if (device == null)
{
device = new Device
{
Number = $"{sn}-{ieee}",
Name = deviceName,
Icon = deviceType.Icon,
Gateway = sn,
ProductId = product.Id,
NodeId = node.Id
};
if (deviceName == "红外转发器")
{
device.AddorUpdateData(device.CreateData("KeyCodeType1", "关", DeviceDataType.String, "空调"));
device.AddorUpdateData(device.CreateData("KeyCodeType2", "关", DeviceDataType.String, "电视"));
device.AddorUpdateData(device.CreateData("KeyCodeType3", "关", DeviceDataType.String, "图影仪"));
device.AddorUpdateData(device.CreateData("KeyCodeType4", "关", DeviceDataType.String, "机顶盒"));
device.AddorUpdateData(device.CreateData("KeyCodeType5", "关", DeviceDataType.String, "自定义"));
}
deviceRepo.Add(device);
}
device.IsOnline = isOnline != 0x00;
device.ConnectId = this._configuration["connectId"];
device.AddorUpdateData(device.CreateData(Keys.DeviceId, deviceId, DeviceDataType.Int, Keys.DeviceId, hidden: true));
device.AddorUpdateData(device.CreateData(Keys.Address, address, DeviceDataType.String, Keys.Address, hidden: true));
device.AddorUpdateData(device.CreateData(Keys.EndPoint, endpoint, DeviceDataType.Int, Keys.EndPoint, hidden: true));
if (new int[] { 0x0002, 0x0009, 0x0081, 0x0202, 0x0220, 0x0051 }.Contains(deviceId))
{
if (deviceId == 0x202)
{
}
device.AddorUpdateData(device.CreateData(Keys.State, switchState == 0 ? "关" : (switchState == 1 ? "开" : "停"), DeviceDataType.String, "状态"));
}
var battery = ms.ReadByte();
device.AddorUpdateData(device.CreateData(Keys.Battery, battery, DeviceDataType.Int, Keys.Battery, hidden: true));
var epCount = ms.ReadByte();
device.AddorUpdateData(device.CreateData(Keys.EndPointCount, battery, DeviceDataType.Int, Keys.EndPointCount, hidden: true));
var historyData = ms.ReadHexString(4);
device.AddorUpdateData(device.CreateData(Keys.Data, historyData, DeviceDataType.String, Keys.Data, hidden: true));
device.AddorUpdateData(device.CreateData(Keys.ZoneType, zoneType, DeviceDataType.String, Keys.ZoneType, hidden: true));
deviceRepo.SaveChanges();
var deviceDto = device.To<DeviceDto>();
deviceDto.ProductNumber = product.Number;
deviceDto.NodeNumber = node.Number;
this.SendDevice(deviceDto);
var dataList = new List<DataDto>();
foreach (var deviceData in device.Data.Where(o => !o.Hidden))
{
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
this.SendData(dataList);
this.UpdateStatus(device);
}
else
{
Console.WriteLine("uknown device type");
}
}
}
}
catch (Exception ex)
{
ex.PrintStack();
}
}
private void UpdateStatus(Device device)
{
try
{
var deviceId = Convert.ToInt32(device.GetDataValue(Keys.DeviceId));
var sn = device.Gateway;
var ieee = device.Number;
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);
}
else if (deviceId == 0x0051)
{
this.X8D07020000(sn, ieee);
}
}
catch (Exception ex)
{
ex.PrintStack();
}
}
/// <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, byte? ep = null)
{
var list = new List<byte>
{
status
};
this.Write(sn, RequestType.x82, ieee, list, ep: ep);
}
/// <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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
if (device != null)
{
var dataList = new List<DataDto>();
var switchState = ms.ReadInt();
if (device.Name.Contains("二路开关") || device.Name.Contains("三路开关"))
{
if (endpoint == 0x10)
{
var deviceData = device.CreateData(Keys.L1State, switchState == 0 ? "关" : "开", DeviceDataType.String, "L1状态");
device.AddorUpdateData(deviceData);
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
else if (endpoint == 0x11)
{
var deviceData = device.CreateData(Keys.L2State, switchState == 0 ? "关" : "开", DeviceDataType.String, "L2状态");
device.AddorUpdateData(deviceData);
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
else if (endpoint == 0x12)
{
var deviceData = device.CreateData(Keys.L3State, switchState == 0 ? "关" : "开", DeviceDataType.String, "L3状态");
device.AddorUpdateData(deviceData);
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
}
else
{
var deviceData = device.CreateData(Keys.State, switchState == 0 ? "关" : (switchState == 1 ? "开" : "停"), DeviceDataType.String, "状态");
device.AddorUpdateData(deviceData);
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
deviceRepo.SaveChanges();
this.SendData(dataList);
}
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>
{
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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
if (device != null)
{
var deviceData = device.CreateData(Keys.Brightness, ms.ReadByte(), DeviceDataType.Int, "亮度");
device.AddorUpdateData(deviceData);
deviceRepo.SaveChanges();
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
this.SendData(new List<DataDto> { dataDto });
}
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>
{
hue,
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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
if (device != null)
{
var deviceData = device.CreateData(Keys.Hue, ms.ReadByte(), DeviceDataType.Int, "色调");
device.AddorUpdateData(deviceData);
deviceRepo.SaveChanges();
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
this.SendData(new List<DataDto> { dataDto });
}
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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
if (device != null)
{
var deviceData = device.CreateData(Keys.Saturation, ms.ReadByte(), DeviceDataType.Int, "饱和度");
device.AddorUpdateData(deviceData);
deviceRepo.SaveChanges();
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
this.SendData(new List<DataDto> { dataDto });
}
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);
}
/// <summary>
/// 0x8d-0x70发送zcl指令读取簇id为0702属性为0000的电量值
/// </summary>
public void X8D07020000(string sn, string ieee)
{
var list = new List<byte>() { 0x02, 0x07, 0x00, 0x00, 0x00 };
this.Write(sn, RequestType.xa7, ieee, list, 2);
}
//
//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<Device>>();
var gateway = gatewayRepo.Table()
.Include(o => o.Data)
.FirstOrDefault(o => o.Number == sn);
if (gateway == null)
{
Console.WriteLine($"gateway {sn} hasn't save in database");
}
else
{
gateway.UserName = ms.ReadASIIString(20);
gateway.Password = ms.ReadASIIString(20);
var deviceData1 = gateway.CreateData(Keys.Version, version, DeviceDataType.String, "版本");
var deviceData2 = gateway.CreateData(Keys.DeviceCount, ms.ReadByte(), DeviceDataType.Int, "设备数量");
gateway.AddorUpdateData(deviceData1);
gateway.AddorUpdateData(deviceData2);
gatewayRepo.SaveChanges();
var dataDto1 = deviceData1.To<DataDto>();
dataDto1.DeviceNumber = gateway.Number;
var dataDto2 = deviceData2.To<DataDto>();
dataDto2.DeviceNumber = gateway.Number;
this.SendData(new List<DataDto> { dataDto1, dataDto2 });
ms.ReadByte();
ms.ReadByte();
ms.ReadByte();
ms.ReadByte();
var hex = ms.ReadHexString(5);
var compileVersion = ms.ReadHexString(5);
}
}
}
}
//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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
if (device != null)
{
var deviceData = device.CreateData(Keys.ColorTemperature, ms.ReadInt(), DeviceDataType.Int, "色温");
device.AddorUpdateData(deviceData);
deviceRepo.SaveChanges();
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
this.SendData(new List<DataDto> { dataDto });
}
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>
{
0x03,//控制标志
0xff,//包长
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>
{
0x03,//控制标志
0xff,//包长
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>
{
0x03,//控制标志
0xff,//包长
0x00//包序号
};
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x0b);
using (var scope = _applicationServices.CreateScope())
{
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
var number = $"{sn}-{ieee}";
var device = deviceRepo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
var version = device.GetDataValue(Keys.Version);
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>
{
0x03,//控制标志
0xff,//包长
0x00//包序号
};
list.AddRange(new byte[] { 0x55, 0x55 });
list.Add(0x0b);
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
var number = $"{sn}-{ieee}";
var device = repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
var version = device.GetDataValue(Keys.Version);
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);
}
//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<Device>>();
var device = this.GetDeviceByAddress(deviceRepo, sn, address);
var clusterId = (ClusterId)ms.ReadInt();
if (device != null)
{
var dataList = new List<DataDto>();
var deviceId = Convert.ToInt32(device.GetDataValue(Keys.DeviceId));
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);
deviceRepo.Delete(device);
}
else if (status == 0x03)//入网
{
}
}
else if (clusterId == ClusterId.light)
{
var deviceData = device.CreateData(Keys.Light, BitConverter.ToInt16(props[0x0000]), DeviceDataType.Int, "光照度", "lux");
device.AddorUpdateData(deviceData);
var dataDto = deviceData.To<DataDto>();
dataDto.DeviceNumber = device.Number;
dataList.Add(dataDto);
}
else if (clusterId == ClusterId.alarm)
{
var state = BitConverter.ToInt16(props[0x0080]);
var data1 = device.CreateData(Keys.Warning, state == 1 ? "报警" : "正常", DeviceDataType.String, "状态");
var data2 = device.CreateData(Keys.UnderVoltage, new BitArray(props[0x0080])[3], DeviceDataType.Int, "低电量");
device.AddorUpdateData(data1);
device.AddorUpdateData(data2);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
var dto2 = data2.To<DataDto>();
dto2.DeviceNumber = device.Number;
dataList.Add(dto1);
dataList.Add(dto2);
}
else if (clusterId == ClusterId.pm25)
{
var data1 = device.CreateData(Keys.PM25, BitConverter.ToInt16(props[0x0000]), DeviceDataType.Int, "PM2.5", "μg/m³");
var data2 = device.CreateData(Keys.PM100, BitConverter.ToInt16(props[0x0002]), DeviceDataType.Int, "PM10", "μg/m³");
var data3 = device.CreateData(Keys.PM10, BitConverter.ToInt16(props[0x0001]), DeviceDataType.Int, "PM1.0", "μg/m³");
device.AddorUpdateData(data1);
device.AddorUpdateData(data2);
device.AddorUpdateData(data3);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
var dto2 = data2.To<DataDto>();
dto2.DeviceNumber = device.Number;
var dto3 = data3.To<DataDto>();
dto3.DeviceNumber = device.Number;
dataList.Add(dto1);
dataList.Add(dto2);
dataList.Add(dto3);
}
else if (clusterId == ClusterId.temperature)
{
var data1 = device.CreateData(Keys.Temperature, BitConverter.ToInt16(props[0x0000]) / 100f, DeviceDataType.Float, "温度", "℃");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
else if (clusterId == ClusterId.humidity)
{
var data1 = device.CreateData(Keys.Humidity, BitConverter.ToInt16(props[0x0000]) / 100f, DeviceDataType.Float, "湿度", "RH%");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
else if (clusterId == ClusterId.voltage)
{
var data1 = device.CreateData(Keys.Voltage, props[0x21][0] / 2f, DeviceDataType.Float, "电量");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
else if (clusterId == ClusterId.socket)
{
if (props.Keys.Contains(0x0000))
{
var tempBytes = new List<byte>();
tempBytes.AddRange(props[0x00]);
tempBytes.Add(0x00);
tempBytes.Add(0x00);
var electricity = BitConverter.ToInt64(tempBytes.ToArray()) / 1000f;
var data1 = device.CreateData(Keys.Electricity, electricity, DeviceDataType.Long, "电量", "kw/h");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
}
if (deviceId == 0x0163)
{
if (props.ContainsKey(0x400a))
{
var irdata = props[0x400a];
if (irdata.Length == 10)
{
var irVersion = BitConverter.ToString((props[0x400a].Skip(3).Take(6).ToArray())).Replace("-", "").ToLower();
if (!string.IsNullOrEmpty(irVersion))
{
var data1 = device.CreateData(Keys.Version, irVersion, DeviceDataType.String, "红外版本");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
}
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());
var data1 = device.CreateData(Keys.KeyPress, keyCode, DeviceDataType.Int, "按键");
device.AddorUpdateData(data1);
var dto1 = data1.To<DataDto>();
dto1.DeviceNumber = device.Number;
dataList.Add(dto1);
}
}
}
}
}
else if (deviceId == 0x0051)
{
if (clusterId == ClusterId.SummationDivisor)
{
this.X8D07020000(sn, device.Number);
}
}
deviceRepo.SaveChanges();
this.SendData(dataList);
}
}
}
}
//0xb1
//0xb2
//0xc2
//0xc3
//0xc4
//0xc5
//0x75
#endregion api
public void SetKeyCodeType(string sn, string ieee, string keyType, string value)
{
using (var scope = _applicationServices.CreateScope())
{
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
var number = $"{sn}-{ieee}";
var device = repo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
var data = device.Data.FirstOrDefault(o => o.Key == keyType);
if (data != null)
{
data.Value = value;
repo.SaveChanges();
var dataDto = data.To<DataDto>();
dataDto.DeviceNumber = device.Number;
this.SendData(new List<DataDto> { dataDto });
}
}
}
private Device GetDevice(IRepository<Device> deviceRepo, string sn, string ieee)
{
var number = $"{sn}-{ieee}";
return deviceRepo.Table()
.Include(o => o.Data)
.FirstOrDefault(o => o.Number == number);
}
private Device GetDeviceByAddress(IRepository<Device> deviceRepo, string sn, string address)
{
return deviceRepo.Table()
.Include(o => o.Data)
.FirstOrDefault(o => o.Number.StartsWith(sn) && o.Data.Any(d => d.Key == Keys.Address && d.Value == address));
}
}
}