CarTrackingRuleEngine/RuleEngine/Services/DeviceService.cs

710 lines
29 KiB
C#
Raw Normal View History

2025-05-15 10:01:56 +07:00
using System.Globalization;
using Microsoft.EntityFrameworkCore;
using RuleEngine.Common;
using RuleEngine.Constants;
using RuleEngine.Database;
using RuleEngine.DTOs;
using RuleEngine.Interfaces;
using RuleEngine.Models;
using RuleEngine.Requests;
namespace RuleEngine.Services
{
public class DeviceService : IDeviceService
{
private readonly DatabaseContext _dbContext;
private readonly IConfiguration _config;
private readonly static string logFolderPath = LogConstants.LOG_FILE_PATH;
private readonly static string exceptionFolder = LogConstants.LOG_EXCEPTION_FILE_PATH;
private static readonly Dictionary<string, LimitedSizeQueue<DateTime>> dictCarHistory = [];
2025-05-15 15:53:21 +07:00
readonly Dictionary<string, DeviceInstantInfo> carHistory = [];
2025-05-15 10:01:56 +07:00
public DeviceService(DatabaseContext dbContext, IConfiguration config)
{
_dbContext = dbContext;
_config = config;
}
public async Task<bool> UpdatePVT(DeviceMessage deviceMessage)
{
DeviceLogRequest? deviceLogRequest = null;
try
{
var enableLogFile = _config.GetValue<bool>("EnableLogFile");
if (enableLogFile)
{
string Imei = "";
try
{
Imei = deviceMessage.Imei ?? string.Empty;
}
catch (Exception ex)
{
// Log the exception
Console.WriteLine(ex.Message);
}
}
deviceLogRequest = CreatePVTRequest(deviceMessage);
if (deviceLogRequest == null)
{
return false;
}
if (deviceLogRequest.Code == "ERROR")
{
return false;
}
if (deviceLogRequest.GpsLat == 0 && deviceLogRequest.GpsLon == 0)
{
var online = _dbContext.Onlines.Where(x => (x.CarId ?? 0) == deviceLogRequest.CarID).FirstOrDefault();
if (online == null)
{
await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei);
}
else
{
if ((deviceLogRequest.GpsLat == 0) &&
(deviceLogRequest.GpsLon == 0))
{
deviceLogRequest.GpsLat = online.GpsLat;
deviceLogRequest.GpsLon = online.GpsLon;
}
//if ( (deviceLogRequest.NetworkLat == 0) &&
// (deviceLogRequest.NetworkLon == 0))
//{
// deviceLogRequest.NetworkLat = online.NetworkLat;
// deviceLogRequest.NetworkLon = online.NetworkLon;
//}
await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei);
}
}
else
{
await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei);
}
await InsertHistoryProcedure(deviceLogRequest, deviceLogRequest.Imei);
}
catch (Exception ex)
{
// Log the exception
if (Directory.Exists(logFolderPath))
StaticResources.Log2File(logFolderPath + "PVTException.txt", ex.ToString());
return false;
}
return true;
}
private DeviceLogRequest? CreatePVTRequest(DeviceMessage deviceMessage, bool bReupPVT = false)
{
DeviceLogRequest? requestLog = null;
var strServerTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
string Imei = deviceMessage?.Imei ?? string.Empty;
string strReceivedTime = deviceMessage?.ReceivedTime ?? string.Empty;
DateTime receivedTime = DateTime.UtcNow;
try
{
receivedTime = DateTime.ParseExact(strReceivedTime, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(strReceivedTime))
{
receivedTime = Convert.ToDateTime(strReceivedTime);
}
}
catch (Exception ex)
{
StaticResources.Log2File(logFolderPath + "PVTException.txt", ex.ToString());
}
if ((bReupPVT == true) && (Imei != null) && (Imei != ""))
{
if (!dictCarHistory.TryGetValue(Imei, out LimitedSizeQueue<DateTime>? queue))
{
queue = new LimitedSizeQueue<DateTime>(QueueConstant.QUEUESIZE);
dictCarHistory.Add(Imei, queue);
}
if (queue != null && !queue.Contains(receivedTime))
{
queue.Enqueue(receivedTime);
}
else
{
return null;
}
}
double longtitude = deviceMessage?.Longitude ?? 0;
double latitude = deviceMessage?.Latitude ?? 0;
int gpsSpeed = deviceMessage?.GpsSpeed ?? 0;
bool isSos = deviceMessage?.IsSOS ?? false;
bool isStrongBoxOpen = deviceMessage?.IsStrongBoxOpen ?? false; //co mo ket: dong/mo
bool isEngineOn = deviceMessage?.IsEngineOn ?? false; //co dong co bat/tat
bool isStopping = deviceMessage?.IsStopping ?? false; //co dung do dung/do
bool isGPSLost = deviceMessage?.IsGPSLost ?? true; //co GPS mat/co
int totalImageCam1 = deviceMessage?.TotalImgCam1 ?? 0;
int totalImageCam2 = deviceMessage?.TotalImgCam2 ?? 0;
string strRFID = deviceMessage?.StrRFID ?? string.Empty;
string strOBD = deviceMessage?.StrOBD ?? string.Empty;
string strLac = deviceMessage?.LacID ?? string.Empty;
string version = deviceMessage?.Version ?? string.Empty;
2025-05-15 15:53:21 +07:00
string provider = deviceMessage?.Provider ?? string.Empty;
2025-05-15 10:01:56 +07:00
var gpsInfor = deviceMessage?.GpsInfor;
bool isJamming = deviceMessage?.IsJamming ?? false;
bool isSpoofing = deviceMessage?.IsSpoofing ?? false;
bool cam1OK = deviceMessage?.Cam1OK ?? false;
bool cam2OK = deviceMessage?.Cam2OK ?? false;
bool camDetach = deviceMessage?.CamDetach ?? false;
double cell_lat = 0;
double cell_lon = 0;
try
{
if (gpsInfor != null)
{
int cellid = gpsInfor.Cellid != null ? Convert.ToInt32(gpsInfor.Cellid) : 0;
int lacid = gpsInfor.Lacid != null ? Convert.ToInt32(gpsInfor.Lacid) : 0;
int mcc = gpsInfor.Mcc != null ? Convert.ToInt32(gpsInfor.Mcc) : 0;
int mnc = gpsInfor.Mnc != null ? Convert.ToInt32(gpsInfor.Mnc) : 0;
string strCellType = gpsInfor.NetworkType != null ? gpsInfor.NetworkType.Trim() : string.Empty;
if ((cellid > 0) && (strCellType != null))
{
strCellType = strCellType.ToLower();
int? CellTypeGoogle = 0;
if (strCellType.Contains("cellsignalstrengthgsm"))
CellTypeGoogle = 3;
else if (strCellType.Contains("cellsignalstrengthcdma"))
CellTypeGoogle = 2;
else if (strCellType.Contains("cellsignalstrengthwcdma"))
CellTypeGoogle = 1;
else if (strCellType.Contains("cellsignalstrengthlte"))
CellTypeGoogle = 0;
var cellinfor = _dbContext.CellInfors.Where(x => (x.LacId == lacid) &&
(x.CellId == cellid) &&
(x.MCC == mcc) && (x.MNC == mnc)
&& (x.NetworkType == CellTypeGoogle)
).FirstOrDefault();
if (cellinfor == null)
{
if (CellTypeGoogle != null)
{
cellinfor = new CellInfor
{
CellId = cellid,
LacId = lacid,
MCC = mcc,
MNC = mnc,
NetworkType = CellTypeGoogle
};
_dbContext.CellInfors.Add(cellinfor);
_dbContext.SaveChanges();
}
}
else
{
cell_lat = cellinfor.NetworkLat ?? 0;
cell_lon = cellinfor.NetworkLon ?? 0;
if (cell_lat != 0 && cell_lon != 0 && latitude != 0 && longtitude != 0)
{
var dist = StaticResources.DistanceGpsCalculate(latitude, longtitude, cell_lat, cell_lon, 'K');
if (dist > DeviceConfig.SPOOFING_THRESH_DISTANCE)
{
isSpoofing = true;
var strLog = string.Format($"{strServerTime} {Imei} {cellinfor.Id} {cellinfor.NetworkLat} {cellinfor.NetworkLon} {latitude} {longtitude} {dist}");
if (Directory.Exists(logFolderPath))
StaticResources.Log2File(logFolderPath + "SpoofingDetection.txt", strLog);
}
}
}
}
}
}
catch (Exception ex)
{
if (Directory.Exists(logFolderPath))
StaticResources.Log2File(logFolderPath + "CELLException.txt", ex.ToString());
}
2025-05-15 15:53:21 +07:00
DateTime currentDate = DateTime.UtcNow;
DateTime checkedTime = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, 0, 0, 0);
// begin validate data
if (string.IsNullOrEmpty(Imei))
{
return new DeviceLogRequest { Imei = Imei, Code = "ERROR", Message = "NO Imei" };
//return new DeviceLogRequest { }
}
if (Imei.Length < 10 || Imei.Length > 25)
{
return new DeviceLogRequest { Imei = Imei, Code = "ERROR", Message = "WRONG Imei" };
}
// end validate data
var deviceInfor = FindIdXeFromDeviceImei(_dbContext, Imei);
if (!carHistory.ContainsKey(Imei))
{
carHistory.Add(Imei, new DeviceInstantInfo { Latitude = latitude, Longtitude = longtitude });
}
else
{
carHistory[Imei] = new DeviceInstantInfo { Latitude = latitude, Longtitude = longtitude };
}
//chuyen sang gio Vietnam
TimeSpan ts = new TimeSpan(7, 0, 0);
receivedTime = receivedTime + ts;
double oriLati = 0;
double oriLongi = 0;
int Cellid = 1;
if (provider != null)
{
Cellid = provider.Contains("network") == true ? 1 : 0;
}
int carStatus = 0; //is runing
//kiem tra neu trang thai xe dang la chay nhung khoang cach vi tri den diem truoc do qua xa --> nhieu do ublox tinh sai vi tri
if (isStopping == false)
{
if (carHistory.ContainsKey(Imei))
{
double last_Longi = carHistory[Imei].Longtitude != null ? carHistory[Imei].Longtitude.Value : 0;
double last_Lati = carHistory[Imei].Latitude != null ? carHistory[Imei].Latitude.Value : 0;
if (StaticResources.DistanceGpsCalculate(latitude, longtitude, last_Lati, last_Longi, 'K') > DeviceConfig.MAX_DISTANCE)
{
oriLati = latitude;
oriLongi = latitude;
latitude = last_Lati;
longtitude = last_Longi;
carStatus = 2; //xe dang do nhung bi nhay vi tri
}
//hiephv
if (gpsSpeed < 3)
{
// loc truong hop xe dung yen, nhung toa do xe dich
if (StaticResources.DistanceGpsCalculate(latitude, longtitude, last_Lati, last_Longi, 'K') > DeviceConfig.MAX_DISTANCE_STOP)
{
oriLati = latitude;
oriLongi = latitude;
latitude = last_Lati;
longtitude = last_Longi;
}
}
}
}
if (isStopping == true)
{
carStatus = 1; //dung
}
else
{
if ((isEngineOn == false)
&& (gpsSpeed <= DeviceConfig.STOP_SPEED_LIMIT))
{
carStatus = 1;
}
}
if (receivedTime.Hour > 21)
{
carStatus = 2; // do
}
string RFID = "";
if (!string.IsNullOrEmpty(strRFID))
{
RFID = strRFID.Trim().Length > 255 ? strRFID.Trim().Substring(0, 255) : strRFID.Trim();
}
int LacID = 0;
if (!string.IsNullOrEmpty(strLac))
{
LacID = int.Parse(strLac, System.Globalization.NumberStyles.HexNumber);
}
if (deviceInfor.CarID > 0)
{
requestLog = new DeviceLogRequest()
{
Imei = Imei,
CarID = deviceInfor.CarID,
UnitID = deviceInfor.UnitID,
ReceivedTime = receivedTime,
GpsLat = latitude,
GpsLon = longtitude,
NetworkLat = cell_lat,
NetworkLon = cell_lon,
OriLati = oriLati,
OriLongi = oriLongi,
GpsSpeed = gpsSpeed,
CellID = Cellid,
LacID = 0,
IsSos = isSos,
IsStrongBoxOpen = isStrongBoxOpen,
IsEngineOn = isEngineOn,
CarStatus = carStatus,
IsGPSLost = isGPSLost,
StrRFID = RFID,
Version = version,
GPSInfor = gpsInfor != null ? gpsInfor.ToString() : string.Empty,
IsJamming = isJamming,
IsSpoofing = isSpoofing,
Cam1OK = cam1OK,
Cam2OK = cam2OK,
CamDetach = camDetach,
Code = "OK",
};
}
2025-05-15 10:01:56 +07:00
return requestLog;
}
2025-05-15 15:53:21 +07:00
private async Task UpdateOnlineProcedure(DeviceLogRequest request, string Imei)
2025-05-15 10:01:56 +07:00
{
try
{
DateTime currentTimeUTC = DateTime.UtcNow;
DateTime localTime = currentTimeUTC.AddHours(7);
if (request.ReceivedTime.Year <= (localTime.Year - 1)) //lost GPS
{
await UpdateLostGpsOnline(request.CarID, true, localTime);
return;
}
// loc ban tin tuong lai
TimeSpan diff02 = localTime.AddMinutes(5).Subtract(request.ReceivedTime);
if (diff02.TotalSeconds > 0) // TotalSeconds < 0 - ban tin gui lai, ko cap nhat bang truc tuyen
{
await UpdateOnlines(request, localTime);
}
}
catch (Exception ex)
{
2025-05-15 15:53:21 +07:00
StaticResources.LogException2File(exceptionFolder, Imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertLst_TrucTuyen " + ex.ToString());
2025-05-15 10:01:56 +07:00
}
}
private async Task UpdateOnlines(DeviceLogRequest request, DateTime localTime)
{
var isSos = request.IsSos == true;
var isGpsLost = request.IsGPSLost == true;
var strongBoxOpen = request.IsStrongBoxOpen == true;
var engineOn = request.IsEngineOn == true;
var carId = request.CarID;
var deviceTime = request.ReceivedTime;
var resetStatusMinute = DeviceConfig.SECONDS_SET_CAR_STOP / 60;
var existingOnline = await _dbContext.Onlines
.FindAsync(carId);
if (existingOnline != null)
{
var diffSeconds = (deviceTime - existingOnline.DeviceTime)?.TotalSeconds ?? 0;
if (diffSeconds <= 0)
{
// Device sent an older or duplicate message; do nothing
return;
}
int carStatus = request.CarStatus ?? 0;
if (diffSeconds > resetStatusMinute)
{
carStatus = 2; // timeout -> set as disconnected
}
// Update record
existingOnline.GpsVelocity = request.GpsSpeed ?? 0;
existingOnline.IsSos = isSos;
existingOnline.IsGPSLost = isGpsLost;
existingOnline.StrongBoxOpen = strongBoxOpen;
existingOnline.EngineOn = engineOn;
existingOnline.CarStatus = carStatus;
existingOnline.Rfidstring = request.StrRFID;
existingOnline.CellId = request.CellID;
existingOnline.LacId = request.LacID ?? 0;
existingOnline.GpsLat = request.GpsLat ?? 0;
existingOnline.GpsLon = request.GpsLon ?? 0;
existingOnline.NetworkLat = request.NetworkLat ?? 0;
existingOnline.NetworkLon = request.NetworkLon ?? 0;
existingOnline.IsJamming = request.IsJamming == true;
existingOnline.IsSpoofing = request.IsSpoofing == true;
existingOnline.IsCam1OK = request.Cam1OK == true;
existingOnline.IsCam2OK = request.Cam2OK == true;
existingOnline.GpsInfor = request.GPSInfor ?? "";
existingOnline.ReceivedTime = localTime;
existingOnline.DeviceTime = deviceTime;
existingOnline.AppVersion = request.Version;
_dbContext.Onlines.Update(existingOnline);
}
else
{
// Insert new record
var newOnline = new Online
{
CarId = carId,
GpsVelocity = request.GpsSpeed ?? 0,
IsSos = isSos,
IsGPSLost = isGpsLost,
StrongBoxOpen = strongBoxOpen,
EngineOn = engineOn,
CarStatus = request.CarStatus ?? 0,
Rfidstring = request.StrRFID,
CellId = request.CellID,
LacId = request.LacID ?? 0,
GpsLat = request.GpsLat ?? 0,
GpsLon = request.GpsLon ?? 0,
NetworkLat = request.NetworkLat ?? 0,
NetworkLon = request.NetworkLon ?? 0,
IsJamming = request.IsJamming == true,
IsSpoofing = request.IsSpoofing == true,
IsCam1OK = request.Cam1OK == true,
IsCam2OK = request.Cam2OK == true,
GpsInfor = request.GPSInfor ?? "",
ReceivedTime = localTime,
DeviceTime = deviceTime,
AppVersion = request.Version
};
await _dbContext.Onlines.AddAsync(newOnline);
}
await _dbContext.SaveChangesAsync();
}
2025-05-15 15:53:21 +07:00
private async Task InsertHistoryProcedure(DeviceLogRequest request, string Imei)
2025-05-15 10:01:56 +07:00
{
try
{
DateTime currentTimeUTC = DateTime.UtcNow;
DateTime localTime = currentTimeUTC.AddHours(7);
var history = new History
{
CarId = request.CarID,
UnitId = request.UnitID,
GpsVelocity = request.GpsSpeed ?? 0,
IsSos = request.IsSos == true,
IsGPSLost = request.IsGPSLost == true,
StrongBoxOpen = request.IsStrongBoxOpen == true,
EngineOn = request.IsEngineOn == true,
CarStatus = request.CarStatus ?? 0,
Rfidstring = request.StrRFID,
GpsLat = request.GpsLat ?? 0,
GpsLon = request.GpsLon ?? 0,
GpsInfor = request.GPSInfor ?? string.Empty,
IsJamming = request.IsJamming == true,
IsSpoofing = request.IsSpoofing == true,
Cam1OK = request.Cam1OK == true,
Cam2OK = request.Cam2OK == true,
CamDetach = request.CamDetach == true,
ReceivedTime = localTime,
DeviceTime = request.ReceivedTime,
DeviceDate = int.Parse(request.ReceivedTime.ToString("yyyyMMdd"))
};
await _dbContext.Histories.AddAsync(history);
await _dbContext.SaveChangesAsync();
}
catch (Exception ex)
{
2025-05-15 15:53:21 +07:00
StaticResources.LogException2File(exceptionFolder, Imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertHistoryProcedure " + ex.ToString());
2025-05-15 10:01:56 +07:00
}
}
public async Task UpdateLostGpsOnline(int carId, bool isGpsLost, DateTime receivedTime)
{
try
{
var online = await _dbContext.Onlines.FindAsync(carId);
if (online != null)
{
online.IsGPSLost = isGpsLost;
online.ReceivedTime = receivedTime;
await _dbContext.SaveChangesAsync();
}
}
catch (Exception ex)
{
StaticResources.LogException2File(exceptionFolder, carId + "_ex_pvt", DateTime.UtcNow.ToString() + " UpdateLostGpsOnline " + ex.ToString());
}
}
2025-05-15 15:53:21 +07:00
public ShortDeviceInfor FindIdXeFromDeviceImei(DatabaseContext context, string Imei)
{
var shortDeviceInfor = new ShortDeviceInfor
{
CarID = 0,
UnitID = 0
};
try
{
try
{
var device = context.Devices.AsNoTracking()
.Where(p => p.Imei == Imei)
.Select(p => new { p.Id, p.UnitId })
.FirstOrDefault();
if (device != null)
{
// da ton tai thiet bi tren he thong
// truong hop nhap thang truc tiep Imei qua website
// truong hop xoa bien so xe, nhung Imei thiet bi van con
var car = context.Cars.AsNoTracking()
.Where(p => p.DeviceId == device.Id)
.Select(p => new { p.Id, p.UnitId })
.FirstOrDefault();
if (car != null)
{
shortDeviceInfor.CarID = car.Id;
shortDeviceInfor.UnitID = car.UnitId ?? 0;
return shortDeviceInfor;
}
else
{
var autoAddConfig = context.AppCfgs.AsNoTracking()
.Where(p => p.CfgKey == "AUTO_ADD_DEVICE")
.Select(p => new { p.CfgValue })
.FirstOrDefault();
if (autoAddConfig != null && Convert.ToInt32(autoAddConfig.CfgValue ?? 0) == 1)
{
shortDeviceInfor = AutoAddDevice(context, Imei, device.Id);
return shortDeviceInfor;
}
}
}
else
{
// chua ton tai thiet bi
// tao moi thiet bi
var autoAddConfig = context.AppCfgs.AsNoTracking()
.Where(p => p.CfgKey == "AUTO_ADD_DEVICE")
.Select(p => new { p.CfgValue })
.FirstOrDefault();
if (autoAddConfig != null && (int)autoAddConfig.CfgValue == 1)
{
shortDeviceInfor = AutoAddDevice(context, Imei, 0);
return shortDeviceInfor;
}
}
}
catch (Exception ex)
{
StaticResources.Log2File(logFolderPath + "Debug.txt", ex.ToString());
}
shortDeviceInfor.CarID = 0;
shortDeviceInfor.UnitID = 0;
}
catch (Exception ex)
{
StaticResources.Log2File(logFolderPath + "Debug.txt", ex.ToString());
}
return shortDeviceInfor;
}
private ShortDeviceInfor AutoAddDevice(DatabaseContext context,string Imei, int existDeviceId)
{
ShortDeviceInfor shortDeviceInfor = new ShortDeviceInfor
{
CarID = 0,
UnitID = 0
};
try
{
// check nhom xe
var orgDevice = context.Units.AsNoTracking().Where(p => p.Province == "INSTALLING_CAR").FirstOrDefault();
var demoUser = context.Users.AsNoTracking()
.Where(p => p.UserName == "demo")
.FirstOrDefault();
if (demoUser == null)
{
demoUser = new User();
demoUser.UserName = "demo";
context.Users.Add(demoUser);
context.SaveChanges();
}
if (orgDevice == null)
{
orgDevice = new Unit();
orgDevice.Name = "Xe đang lắp đặt";
orgDevice.Description = "Xe đang lắp đặt";
orgDevice.CreatedAt = DateTime.UtcNow.AddHours(7);
orgDevice.UpdatedAt = DateTime.UtcNow.AddHours(7);
orgDevice.Province = "INSTALLING_CAR";
context.Units.Add(orgDevice);
context.SaveChanges();
}
var orgUser = _dbContext.UserUnits.AsNoTracking()
.Where(p => p.UserId == demoUser.Id && p.UnitId == orgDevice.Id)
.FirstOrDefault();
if (orgUser == null)
{
orgUser = new UserUnit();
orgUser.UserId = demoUser.Id;
orgUser.UnitId = orgDevice.Id;
context.UserUnits.Add(orgUser);
context.SaveChanges();
}
int tempDeviceId = 0;
if (existDeviceId > 0)
{
// da ton tai thiet bi
tempDeviceId = existDeviceId;
}
else
{
// thiet bi chua ton tai tren he thong
// Add device
var newDevice = new Device();
newDevice.DeviceNumber = Imei;
newDevice.Imei = Imei;
newDevice.UnitId = orgDevice.Id;
newDevice.IsActive = true;
newDevice.AllowUpdate = false;
_dbContext.Devices.Add(newDevice);
_dbContext.SaveChanges();
tempDeviceId = newDevice.Id;
}
// Add Car
var newCar = new Car();
newCar.LicensePlate = Imei;
newCar.DeviceId = tempDeviceId;
newCar.UnitId = orgDevice.Id;
_dbContext.Cars.Add(newCar);
_dbContext.SaveChanges();
shortDeviceInfor.CarID = newCar.Id;
shortDeviceInfor.UnitID = newCar.UnitId??0;
}
catch (Exception ex)
{
StaticResources.Log2File(logFolderPath + "LogAddDevice.txt", Imei + "_" + DateTime.Now.ToString() + ": " + ex.ToString());
}
return shortDeviceInfor;
}
2025-05-15 10:01:56 +07:00
}
}