Waste/Waste.Application/ThirdApiInfo/OpenService.cs

611 lines
25 KiB
C#
Raw Normal View History

using DotNetCore.CAP;
using Furion;
2021-07-29 19:10:19 +08:00
using Furion.DependencyInjection;
2021-07-30 18:15:58 +08:00
using Furion.DistributedIDGenerator;
2022-03-28 17:19:48 +08:00
using Microsoft.Extensions.Caching.Distributed;
2021-07-29 19:10:19 +08:00
using Nirvana.Common;
using SqlSugar;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Waste.Application.SubscribeInfo;
2021-07-29 19:10:19 +08:00
using Waste.Domain;
namespace Waste.Application.ThirdApiInfo
{
/// <summary>
/// 设备对接接口
/// </summary>
public class OpenService : IOpenService, ITransient
{
private static string ApiUrl = App.Configuration["SZDevPlatSetting:ApiUrl"];
private static string UserId = App.Configuration["SZDevPlatSetting:UserId"];
private static string ApiSecret = App.Configuration["SZDevPlatSetting:ApiSecret"];
private static string ApiSecretHash = App.Configuration["SZDevPlatSetting:ApiSecretHash"];
private static string WebSocketUrl = App.Configuration["SZDevPlatSetting:SocketUrl"];
2021-07-29 19:10:19 +08:00
private readonly ISqlSugarRepository<W_Device> repository;
private readonly SqlSugarClient dbClient;
private readonly ISuZhouService _suZhouService;
2021-09-04 08:36:42 +08:00
private readonly ILoggerService _loggerService;
private readonly ICapPublisher _capBus;
2022-03-28 17:19:48 +08:00
private readonly IDistributedCache _cahce;
private readonly IResultService _resultService;
2022-09-14 11:32:38 +08:00
private readonly IDistributedIDGenerator _idgen;
2022-03-28 17:19:48 +08:00
2022-09-14 11:32:38 +08:00
public OpenService(ISqlSugarRepository<W_Device> sqlSugarRepository, ISuZhouService suZhouService, ILoggerService loggerService, ICapPublisher capPublisher, IDistributedCache distributedCache, IResultService resultService, IDistributedIDGenerator distributedIDGenerator)
2021-07-29 19:10:19 +08:00
{
repository = sqlSugarRepository;
dbClient = repository.Context;
_suZhouService = suZhouService;
2021-09-04 08:36:42 +08:00
_loggerService = loggerService;
_capBus = capPublisher;
2022-03-28 17:19:48 +08:00
_cahce = distributedCache;
_resultService = resultService;
2022-09-14 11:32:38 +08:00
_idgen = distributedIDGenerator;
2021-07-29 19:10:19 +08:00
}
2021-07-29 19:10:19 +08:00
/// <summary>
2021-08-13 19:34:39 +08:00
/// 更新上报状态
2021-07-29 19:10:19 +08:00
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
2021-08-13 19:34:39 +08:00
public async Task<ResultInfo> UpdateStatusAsync(UpdateStatusDto data)
2021-07-29 19:10:19 +08:00
{
//await _capBus.PublishAsync("result.service.update", data);
//return new ResultInfo(ResultState.SUCCESS, "success");
Guid resultid = Guid.Empty;
if (!string.IsNullOrEmpty(data.ResultId) && Guid.TryParse(data.ResultId, out resultid))
{
if (await dbClient.Queryable<W_ResultExt>().AnyAsync(x => x.ResultId == resultid))
{
await dbClient.Updateable<W_ResultExt>().SetColumns(x => new W_ResultExt
{
Status = data.status
}).Where(x => x.ResultId == resultid).ExecuteCommandAsync();
}
else
{
var insertdata = new W_ResultExt
{
2022-09-14 11:32:38 +08:00
Id = _idgen.Create().ToGuid(),
Status = data.status,
CreateTime = DateTime.Now,
ResultId = resultid
};
await dbClient.Insertable(insertdata).ExecuteCommandAsync();
}
return new ResultInfo(ResultState.SUCCESS, "success");
}
return new ResultInfo(ResultState.SUCCESS, "记录id未找到");
2021-08-13 19:34:39 +08:00
}
2021-08-13 19:34:39 +08:00
/// <summary>
/// 获取设备上报相关信息
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public async Task<ResultInfo> GetDevInfoAsync(GetDevInfoRequestDto data)
{
//更新上报记录结果
Guid resultid = Guid.Empty;
//这里进行去重处理
if (!string.IsNullOrEmpty(data.ResultId) && Guid.TryParse(data.ResultId, out resultid))
{
var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == data.ECode);
if (device == null)
{
return new ResultInfo(ResultState.FAIL, "设备未找到");
}
var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
if (devicesecret == null || string.IsNullOrEmpty(devicesecret.Secret)
|| string.IsNullOrEmpty(devicesecret.SecretHash)
|| string.IsNullOrEmpty(devicesecret.DevId))
{
return new ResultInfo(ResultState.FAIL, "设备还未获取验证信息");
}
int timestamp = _suZhouService.GetUTCTimestamp();
int noncestr = _suZhouService.GetNonce();
var result = await dbClient.Queryable<W_Result>().FirstAsync(x => x.Id == resultid);
if (result == null)
{
return new ResultInfo(ResultState.SUCCESS, "记录id未找到");
}
var returndata = new GetDevInfoResponseDto
{
DeviceId = devicesecret.DevId,
noncestr = noncestr,
timestamp = timestamp,
Secret = devicesecret.Secret,
SecretHash = devicesecret.SecretHash,
UserId = UserId,
PostUrl = ApiUrl,
ScanningTime = timestamp,
ResultId = resultid,
trash = result.Registration,
Weight = result.GrossWeight.ToDouble(),
status = 0,
IsSuccessed = true,
type = TrashType(result.WasteType)
};
string[] paramlist = new string[] {
returndata.Weight.ToString(),returndata.trash,returndata.type.ToString(),returndata.ScanningTime.ToString(),returndata.status.ToString()};
returndata.sign = _suZhouService.GetUserApiSign(returndata.Secret, paramlist);
return new ResultInfo(ResultState.SUCCESS, "success", returndata);
}
else
{
var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == data.ECode);
if (device == null)
2021-08-13 19:34:39 +08:00
{
return new ResultInfo(ResultState.FAIL, "设备未找到");
2021-08-13 19:34:39 +08:00
}
if (device.Status == (int)DeviceStatus.Error)
2021-08-13 19:34:39 +08:00
{
return new ResultInfo(ResultState.FAIL, "设备已停止运行");
}
var returndata = new GetDevInfoResponseDto
{
2022-09-14 11:32:38 +08:00
ResultId = _idgen.Create().ToGuid(),
UserId = UserId,
PostUrl = ApiUrl
};
var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
if (devicesecret == null || string.IsNullOrEmpty(devicesecret.Secret)
|| string.IsNullOrEmpty(devicesecret.SecretHash)
|| string.IsNullOrEmpty(devicesecret.DevId))
{
return new ResultInfo(ResultState.FAIL, "设备还未获取验证信息");
}
// trash@1@62942200205496@4.964 trash@垃圾种类@垃圾桶编号@垃圾重量
if (!string.IsNullOrEmpty(data.data) && data.data.StartsWith("trash@"))
{
var arr = data.data.Split('@');
var type = arr.GetListValue(1);
returndata.trash = arr.GetListValue(2);
var weight = arr.GetListValue(3);
var result = await UpdateDevInfo(data, returndata, device, type, weight);
if (result != null) return result;
}
//解析协议,IC卡数据@垃圾桶编号@厨余垃圾@7.91
// 00000000003031 40 0F00010009 40 C6E4CBFBC0ACBBF8 40 31352E39
// 00000000003031 40 000F000002 40 C6E4CBFBC0ACBBF8 40 35312E30 0D0A
else if (!string.IsNullOrEmpty(data.data) && data.data.Length > 52)
{
data.data = data.data.Replace(" ", "");
//收到的为16进制,对数据进行解析,0-4预留,5-垃圾种类,6-垃圾桶大小,7-@,8-12垃圾桶编号,13@,14-21垃圾种类汉字,22@,23-结束重量, OD OA 回车换行
data.data = data.data.Substring(0, data.data.Length - 4);
var trashhex = data.data.Substring(16, 10); //垃圾桶编号
var typehex = data.data.Substring(28, 16); //垃圾种类
var sizehex = data.data.Substring(12, 2);//桶大小,30-小桶,31-大桶
var weighthex = data.data.Substring(46, data.data.Length - 46);
returndata.trash = HextToDec(trashhex).ToString(); //垃圾桶编号使用10进制
var type = GetChsFromHex(typehex);
var weight = GetChsFromHex(weighthex);
2023-01-09 15:14:06 +08:00
var result = await UpdateDevInfo(data, returndata, device, type, weight);
if (result != null) return result;
2021-08-13 19:34:39 +08:00
}
else
2021-08-13 19:34:39 +08:00
{
_loggerService.AddLogger($"{data.ECode},{device.Name},协议格式不正确:{data.ToJson()}", 1);
return new ResultInfo(ResultState.FAIL, "协议格式不正确");
}
int timestamp = _suZhouService.GetUTCTimestamp();
int noncestr = _suZhouService.GetNonce();
returndata.DeviceId = devicesecret.DevId;
returndata.noncestr = noncestr;
returndata.timestamp = timestamp;
returndata.Secret = devicesecret.Secret;
returndata.SecretHash = devicesecret.SecretHash;
returndata.ScanningTime = timestamp;
string[] paramlist = new string[] {
2021-09-04 08:36:42 +08:00
returndata.Weight.ToString(),returndata.trash,returndata.type.ToString(),returndata.ScanningTime.ToString(),returndata.status.ToString()
2021-09-29 08:53:06 +08:00
};
returndata.sign = _suZhouService.GetUserApiSign(returndata.Secret, paramlist);
_loggerService.AddLogger($"{data.ECode},{device.Name},发送的数据:{returndata.ToJson()}", 1);
return new ResultInfo(ResultState.SUCCESS, "success", returndata);
}
2021-07-29 19:10:19 +08:00
}
2021-07-30 18:15:58 +08:00
/// <summary>
/// 16进制转10进制
/// </summary>
/// <param name="hex"></param>
/// <returns></returns>
public long HextToDec(string hex)
{
char[] nums = hex.ToCharArray();
long total = 0;
try
{
for (int i = 0; i < nums.Length; i++)
{
String strNum = nums[i].ToString().ToUpper();
switch (strNum)
{
case "A":
strNum = "10";
break;
case "B":
strNum = "11";
break;
case "C":
strNum = "12";
break;
case "D":
strNum = "13";
break;
case "E":
strNum = "14";
break;
case "F":
strNum = "15";
break;
default:
break;
}
double power = Math.Pow(16, Convert.ToDouble(nums.Length - i - 1));
total += Convert.ToInt64(strNum) * Convert.ToInt64(power);
}
}
catch (System.Exception ex)
{
string strErorr = ex.ToString();
return 0;
}
return total;
}
/// <summary>
2021-07-30 18:15:58 +08:00
/// 心跳数据上报
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public async Task<ResultInfo> PostHeartAsync(DevHeartRequestDto data)
{
if (!await dbClient.Queryable<W_Device>().AnyAsync(x => x.Ecode == data.ECode))
2021-07-30 18:15:58 +08:00
{
return new ResultInfo(ResultState.FAIL, "设备未找到");
}
await _capBus.PublishAsync("device.service.postheart", data);
2021-07-30 18:15:58 +08:00
return new ResultInfo(ResultState.SUCCESS, "success");
}
2021-07-30 18:15:58 +08:00
/// <summary>
/// 获取设备注册信息,第一次开机使用
/// </summary>
/// <param name="ecode"></param>
/// <returns></returns>
public async Task<ResultInfo> RegInfoAsync(string ecode)
{
var device = await dbClient.Queryable<W_Device>().FirstAsync(x => x.Ecode == ecode);
if (device == null)
{
return new ResultInfo(ResultState.FAIL, "设备未找到", new DevRegInfoResponseDto());
}
//更新开机时间
await _capBus.PublishAsync("device.service.update", device.Id);
2021-07-30 18:15:58 +08:00
var data = new DevRegInfoResponseDto
{
2021-08-11 08:16:16 +08:00
status = 0,
WebSocketUrl = WebSocketUrl
2021-07-30 18:15:58 +08:00
};
2021-08-11 08:16:16 +08:00
//获取授权信息
var devicesecret = await dbClient.Queryable<W_SZDevice>().FirstAsync(x => x.DeviceId == device.Id);
if (devicesecret != null && !string.IsNullOrEmpty(devicesecret.Secret)
&& !string.IsNullOrEmpty(devicesecret.SecretHash)
&& !string.IsNullOrEmpty(devicesecret.DevId))
{
2021-08-13 17:30:59 +08:00
data.timestamp = _suZhouService.GetUTCTimestamp();
2021-08-11 08:16:16 +08:00
data.noncestr = _suZhouService.GetNonce();
data.UserId = UserId;
data.Secret = devicesecret.Secret;
data.SecretHash = devicesecret.SecretHash;
2021-08-13 09:11:36 +08:00
data.DeviceId = devicesecret.DevId.ToString();
2021-08-11 08:16:16 +08:00
}
2021-07-30 18:15:58 +08:00
return new ResultInfo(ResultState.SUCCESS, "success", data);
}
/// <summary>
/// 更新设备版本信息
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public async Task UpdateVersionAsync(DeviceVerS2SDto data)
{
await _capBus.PublishAsync("device.service.updatever", data);
}
2022-03-28 17:19:48 +08:00
/// <summary>
/// 通过ailink wifi模式发送的数据
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public async Task<object> WifiPostAsync(WifiRequestC2SDto data)
{
//记录发送过来的数据
_loggerService.AddLogger($"wifi发送原始数据,data={data.ToJson()}", 3);
var successdata = Encoding.UTF8.GetBytes("A901019A");
var returndata = new
{
status = "1",
data = Convert.ToBase64String(successdata)
};
//数据解析
var result = AnalyProto(data);
if (!result.ischecked)
{
return returndata;
}
if (result.databyte.Length == 0)
{
return returndata;
}
//小于14则表示结束
if (result.databyte.Length < 14)
{
var databytes = await _cahce.GetAsync(result.sn);
if (databytes != null && databytes.Length > 0)
{
2022-03-30 10:49:47 +08:00
await _cahce.RemoveAsync(result.sn);
2022-03-28 17:19:48 +08:00
byte[] newval = new byte[databytes.Length + result.databyte.Length];
databytes.CopyTo(newval, 0);
result.databyte.CopyTo(newval, databytes.Length);
2022-03-29 09:33:34 +08:00
//解析协议,IC卡数据@垃圾桶编号@厨余垃圾@7.91
var datahex = BytesToHexStr(databytes);
datahex = datahex.Replace(" ", "");
//收到的为16进制,对数据进行解析,0-4预留,5-垃圾种类,6-垃圾桶大小,7-@,8-12垃圾桶编号,13@,14-21垃圾种类汉字,22@,23-结束重量
var trashhex = datahex.Substring(16, 10); //垃圾桶编号
var typehex = datahex.Substring(28, 16); //垃圾种类
var size = datahex.Substring(12, 2);//桶大小,30-小桶,31-大桶
var weighthex = datahex.Substring(46, datahex.Length - 46);
string trashno = HextToDec(trashhex).ToString(); //垃圾桶编号使用10进制
var wastetype = GetChsFromHex(typehex);
var weight = GetChsFromHex(weighthex);
2022-03-28 17:19:48 +08:00
await _resultService.InsertResultByWifiAsync(new WifiPackage
{
sn = result.sn,
WasteType = wastetype,
Weight = weight,
trashcode = trashno,
size = size,
IsHeart = result.IsHeart
});
}
}
else
{
var val = await _cahce.GetAsync(result.sn);
2022-03-30 10:49:47 +08:00
var time = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(30));
2022-03-28 17:19:48 +08:00
if (val != null && val.Length > 0)
{
byte[] newval = new byte[val.Length + result.databyte.Length];
val.CopyTo(newval, 0);
result.databyte.CopyTo(newval, val.Length);
await _cahce.SetAsync(result.sn, newval, time);
}
else
{
await _cahce.SetAsync(result.sn, result.databyte, time);
}
}
return returndata;
}
2023-01-09 15:14:06 +08:00
/// <summary>
/// 16进制转汉字
/// </summary>
/// <param name="hex"></param>
/// <returns></returns>
private string GetChsFromHex(string hex)
{
if (hex == null)
return "";
if (hex.Length % 2 != 0)
{
hex += "20";//空格
}
// 需要将 hex 转换成 byte 数组。
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
try
{
// 每两个字符是一个 byte。
bytes[i] = byte.Parse(hex.Substring(i * 2, 2),
System.Globalization.NumberStyles.HexNumber);
}
catch
{
}
}
// 获得 GB2312Chinese Simplified。
Encoding chs = Encoding.GetEncoding("gb2312");
return chs.GetString(bytes);
}
private int TrashType(string type)
{
if (type == "厨余垃圾") return 1;
else if (type == "可回收物") return 2;
else if (type == "有害垃圾") return 3;
else if (type == "其他垃圾") return 4;
else return 0;
}
private int GetTimestamp(DateTime time)
{
DateTime dateTimeStart = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1, 8, 0, 0));
int timestamp = Convert.ToInt32((time - dateTimeStart).TotalSeconds);
return timestamp;
}
/// <summary>
/// 字节数组转16进制
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
private string BytesToHexStr(byte[] bt)
{
string returnStr = "";
if (bt != null)
{
for (int i = 0; i < bt.Length; i++)
{
returnStr += bt[i].ToString("X2");
}
}
return returnStr;
}
2022-03-28 17:19:48 +08:00
/// <summary>
/// wifi数据解析
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private WifiRequestS2SDto AnalyProto(WifiRequestC2SDto data)
{
WifiRequestS2SDto dto = new WifiRequestS2SDto();
//检查是否为有效的base64数据
if (!AESEncrypt.IsBase64(data.@params))
{
dto.data = data.@params;
return dto;
}
//数据为base64加密
byte[] resultByte = Convert.FromBase64String(data.@params);
dto.data = BytesToHexStr(resultByte);
//574D07884A1882FCC2FE346BA1D80E 00 A903000D0A1A9A
_loggerService.AddLogger($"wifi结果推送,解析出的数据:{dto.data}", 3);
int len = resultByte.Count();//数据总长度
//长度格式是否正确,固定长度为36位
if (len < 23)
{
return dto;
}
//前15个字节为sn。中间以 00 分隔。后面为测量结果数据 A9 03 00 0D 0A 1A 9A
int i = 0;
byte[] snbyte = new byte[15];
for (i = 0; i < 15; i++)
{
snbyte[i] = resultByte[i];
}
dto.sn = BytesToHexStr(snbyte).Replace(" ", "");
dto.splitstr = ByteToHexStr(resultByte[i]);
i++;
dto.Header = ByteToHexStr(resultByte[i]);//固定为A9
if (dto.Header != "A9") //固定为A9
{
return dto;
}
string heartstr = ByteToHexStr(resultByte[i + 2]);//是否为测量数据
2022-03-30 11:00:04 +08:00
if (heartstr != "01")
2022-03-28 17:19:48 +08:00
{
dto.IsHeart = true;
}
dto.ischecked = true;
string datalenstr = ByteToHexStr(resultByte[i + 1]); //数据体长度
int datalen = HextToDec(datalenstr).ToInt();
i += 3;
dto.databyte = new byte[datalen - 1];
for (int j = 0; j < datalen; j++)
{
if (i < len - 2)
{
dto.databyte[j] = resultByte[i];
}
i++;
}
return dto;
}
///<summary>
/// 字节转16进制
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
private string ByteToHexStr(byte bt)
{
return ((int)bt).ToString("X2");
}
private async Task<ResultInfo> UpdateDevInfo(GetDevInfoRequestDto data, GetDevInfoResponseDto returndata, W_Device device,
string type, string weight)
{
returndata.type = TrashType(type);
returndata.Weight = weight.ToDouble();
//计算净重,毛重-皮重=净重如果净重小于等于0则不上报保存
returndata.Weight = (returndata.Weight - device.Tare.ToDouble()).ToDouble(2);
if (returndata.Weight <= 0)
{
_loggerService.AddLogger($"{data.ECode},{device.Name},重量小于等于0:{returndata.ToJson()}", 1);
return new ResultInfo(ResultState.FAIL, "无效的重量");
}
//检查是否为15分钟内第一次上报
//如果是巴城的设备则不使用这个限制
if (device.Businessid != Guid.Parse("39FCB9DE-404E-68F5-384B-EE2462EAB87C"))
{
var time15 = DateTime.Now.AddMinutes(-15);
if (await dbClient.Queryable<W_DeviceResult>().AnyAsync(x => x.DeviceId == device.Id && x.LastTrash == returndata.trash && x.LastHeartTime > time15))
{
_loggerService.AddLogger($"{data.ECode},{device.Name},重复垃圾桶编号的数据:{returndata.ToJson()}", 1);
return new ResultInfo(ResultState.FAIL, "15分钟内同一垃圾桶编号上报");
}
}
returndata.IsSuccessed = true;
//记录数据
data.IMEI = data.IMEI.ToStr();
data.ICCID = data.ICCID.ToStr();
data.IMSI = data.IMSI.ToStr();
await _capBus.PublishAsync("result.service.insert", new ResultS2SDto
{
BusinessId = device.Businessid,
DeviceId = device.Id,
gslq = data.GSLQ,
iccid = data.ICCID,
imei = data.IMEI,
imsi = data.IMSI,
LastHeartTime = device.LastHeartTime,
latitude = data.Latitude,
longtitude = data.Longitude,
ResultId = returndata.ResultId,
Tare = device.Tare,
trash = returndata.trash,
wastetype = type,
weight = weight
});
//推送数据给第三方
await _resultService.SendMessageToThird(new SendThirdMessageSubscribeS2SDto
{
DeviceId = device.Id,
WasteSType = "",
Time = DateTime.Now,
TrashCode = returndata.trash,
WasteType = type,
Weight = weight.ToDecimal(),
faccode = device.FacEcode,
ecode = device.Ecode,
province = device.Province,
city = device.City,
area = device.Area,
address = device.Address
});
return null;
}
2021-07-29 19:10:19 +08:00
}
}