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> dictCarHistory = []; readonly Dictionary carHistory = []; public DeviceService(DatabaseContext dbContext, IConfiguration config) { _dbContext = dbContext; _config = config; } public async Task UpdatePVT(DeviceMessage deviceMessage) { DeviceLogRequest? deviceLogRequest = null; try { var enableLogFile = _config.GetValue("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? queue)) { queue = new LimitedSizeQueue(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; string provider = deviceMessage?.Provider ?? string.Empty; 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()); } 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", }; } return requestLog; } private async Task UpdateOnlineProcedure(DeviceLogRequest request, string Imei) { 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) { StaticResources.LogException2File(exceptionFolder, Imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertLst_TrucTuyen " + ex.ToString()); } } 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(); } private async Task InsertHistoryProcedure(DeviceLogRequest request, string Imei) { 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) { StaticResources.LogException2File(exceptionFolder, Imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertHistoryProcedure " + ex.ToString()); } } 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()); } } 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; } } }