Skip to content

Latest commit

 

History

History
1283 lines (1142 loc) · 50.7 KB

File metadata and controls

1283 lines (1142 loc) · 50.7 KB

MQTT的重新订阅

using Dept9IOT.DeviceInfo.IRepository.MongoDB;
using Dept9IOT.DeviceInfo.Model.DbModels;
using Dept9IOT.DeviceInfo.Model.Enums;
using Dept9IOT.DeviceInfo.Model.MongoDBModels;
using Dept9IOT.DeviceInfo.Unity.Consts;
using Dept9IOT.DeviceInfo.Unity.Enums.Mqtt;
using Dept9IOT.DeviceInfo.Unity.Models.BllModels;
using Dept9IOT.DeviceInfo.Unity.Models.MqttDto.Pulish;
using Dept9IOT.DeviceInfo.Unity.MqttDto;
using Dept9IOT.DeviceInfo.WebApi.CoreBuilder.CoreMqtt;
using evoc9.Json;
using evoc9.Redis;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Publishing;
using MQTTnet.Protocol;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Dept9IOT.DeviceInfo.Services.MqttClientService
{
    /// <summary>
    /// MQTT客户端服务
    /// </summary>
    public class NMqttClientService : INMqttClientService
    {
        private readonly ILogger _logger;
        private IMqttClient mqttClient;
        private IMqttClientOptions _options;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public NMqttClientService(ILogger<NMqttClientService> logger, 
            IMqttClientOptions options,
            IServiceScopeFactory serviceScopeFactory)
        {
            _logger = logger;
            _options = options;
            mqttClient = new MqttFactory().CreateMqttClient();
            ConfigureMqttClient();
            _serviceScopeFactory = serviceScopeFactory;
        }

        private void ConfigureMqttClient()
        {
            mqttClient.ConnectedHandler = this;
            mqttClient.DisconnectedHandler = this;
            mqttClient.ApplicationMessageReceivedHandler = this;
            StartAsync(CancellationToken.None).Wait();
        }

        #region 客户端操作函数
        //连接成功处理函数
        public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
        {
            await Task.CompletedTask;
        }

        //断开连接处理函数
        public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs)
        {
            try
            {
                _logger.LogInformation($"mqtt断开连接,正在尝试重连... ...");
                await Task.Delay(TimeSpan.FromSeconds(5));
                await mqttClient.ConnectAsync(_options, CancellationToken.None);
            }
            catch (Exception ex)
            {
                _logger.LogError($"mqtt重联失败,异常信息:{eventArgs.Exception.Message}");
            }
        }

        //启动
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            await mqttClient.ConnectAsync(_options);
            Console.WriteLine("StartAsync:::" + _options.ChannelOptions.ToJsonString());
            if (!mqttClient.IsConnected)
            {
                await mqttClient.ReconnectAsync();
            }
        }

        //停止
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            if (mqttClient.IsConnected)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    var disconnectOption = new MqttClientDisconnectOptions
                    {
                        ReasonCode = MqttClientDisconnectReason.NormalDisconnection,
                        ReasonString = "NormalDiconnection"
                    };
                    await mqttClient.DisconnectAsync(disconnectOption, cancellationToken);
                }
                await mqttClient.DisconnectAsync();
            }
        }

        //启动,未处理
        public void Start(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        //停止,未处理
        public void Stop(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        #endregion

        /// <summary>
        /// 订阅主题
        /// </summary>
        /// <param name="topic"></param>
        /// <returns></returns>
        public async Task<bool> SubscribeAsync(string topic)
        {
            try
            {
                await mqttClient.SubscribeAsync(topic, MqttQualityOfServiceLevel.ExactlyOnce);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"主题:{topic} 订阅失败,错误详情:{ex.Message}",ex);
                throw;
            }
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="reploy"></param>
        /// <returns></returns>
        public async Task<bool> PublishAsync(string topic, string reploy)
        {
            var pushResult = await mqttClient.PublishAsync(topic, reploy, MqttQualityOfServiceLevel.ExactlyOnce);
            if (pushResult.ReasonCode == MqttClientPublishReasonCode.Success)
                return true;
            return false;
        }

        /// <summary>
        /// 订阅消息处理函数
        /// </summary>
        /// <param name="eventArgs"></param>
        /// <returns></returns>
        public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
        {
            var operateTypeStr = string.Empty;
            try
            {
                _logger.LogInformation($"{DateTime.Now} 接收到主题为:{eventArgs.ApplicationMessage.Topic}的消息,消息内容为:{Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)}");
                var topic = eventArgs.ApplicationMessage.Topic;
                var topicItem = topic.Split("/");
                var joinToMqttWay = (JoinToMqttWay)(int.Parse(topicItem[2]));
                var deviceId = topic.Split("/")[3];
                var msg = Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload);
                var messageDto = JsonConvert.DeserializeObject<MqttMessageDto>(msg);
                operateTypeStr = messageDto.Type.ToString();
                if (messageDto.Code == MqttResultStatusCode.Success)
                {
                    switch (messageDto.Type)
                    {
                        case MqttOperateType.DeviceConnectToGateway:
                            //设备连接网关订阅处理函数
                            await DeviceConnectToGatewaySubHandle(topic, messageDto);
                            break;
                        case MqttOperateType.HongStudy:
                            //设备连接网关订阅处理函数
                            await HongStudySubHandle(topic, messageDto);
                            break;
                        case MqttOperateType.DeviceHeartbeat:
                            //设备心跳处理函数
                            await DeviceHeartbeatSubHandle(topic, messageDto);
                        // case MqttOperateType.DeviceHeartbeat:
                        //     //网关心跳处理函数
                        //     await DeviceHeartbeatSubHandle(topic, messageDto);
                        //     break;
                        default:
                            break;
                    }
                }
                else
                {
                    _logger.LogWarning($"设备层业务处理失败,主题信息:{topic}");
                }
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError($"MQTT订阅消息处理函数出现异常,主题为:{eventArgs.ApplicationMessage.Topic},操作类型:{operateTypeStr}",ex);
            }
        }

        #region 私有方法
        /// <summary>
        /// 设备连接网关订阅处理函数
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="messageDto"></param>
        private async Task DeviceConnectToGatewaySubHandle(string topic, MqttMessageDto messageDto)
        {
            var topicItem = topic.Split("/");
            var joinToMqttWay = (JoinToMqttWay)(int.Parse(topicItem[2]));
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<_91iotdbContext>();
                var redisClient = scope.ServiceProvider.GetRequiredService<RedisClient>();
                var subDto = JsonConvert.DeserializeObject<DeviceCTRGatewayJoinSbuDto>(messageDto.Msg.ToString());
                string key = ApplicationConst.RedisKey.DeviceConnectedToRealGatewayJoinPreFix + subDto.SendBack.Key;
                if (!redisClient.KeyExists(key))
                    _logger.LogError($"设备连接网关订阅处理函数|出现异常|缓冲不存在;主题信息:{topic}");

                var cacheStr = redisClient.StringGet<string>(key);
                var cacheModel = JsonConvert.DeserializeObject<DeviceJoinCacheModel>(cacheStr);

                var deviceEntitys = await dbContext.Devices.Where(a => a.GCPortId == cacheModel.GCPortId && a.IsDelete == false).ToListAsync();
                if (deviceEntitys.Count > 0)
                {
                    var deviceEntity =await dbContext.Devices.FirstOrDefaultAsync(a => a.Id == cacheModel.DeviceId);
                    if(deviceEntity==null)
                        _logger.LogError($"设备连接网关订阅处理函数|出现异常|查询不到新增设备;主题信息:{topic},新增设备id:{cacheModel.DeviceId}");

                    deviceEntity.JoinStatus = JoinStatus.Joined;
                    deviceEntity.Status =(int)DeviceStatus.Online;
                    dbContext.Devices.Update(deviceEntity);
                    await dbContext.SaveChangesAsync();

                    var deviceIds = deviceEntitys.Select(a => a.Id).ToList();
                    _logger.LogInformation($"设备成功接入到网关,网关id:{deviceEntitys[0].GatewayId},设备id:{string.Join(",", deviceIds)}");
                }
                else
                {
                    _logger.LogWarning($"设备连接网关出现异常,查询不到接入的设备!");
                }
            }
        }

        /// <summary>
        /// 红外学习处理函数
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="messageDto"></param>
        private async Task HongStudySubHandle(string topic, MqttMessageDto messageDto)
        {
            var topicItem = topic.Split("/");
            var joinToMqttWay = (JoinToMqttWay)(int.Parse(topicItem[2]));
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var subDto = JsonConvert.DeserializeObject<InfraredStudySubDto>(messageDto.Msg.ToString());
                if (string.IsNullOrEmpty(subDto.CmdCode))
                    return;

                var redisClient = scope.ServiceProvider.GetRequiredService<RedisClient>();
                var dbContext = scope.ServiceProvider.GetRequiredService<_91iotdbContext>();
                using (var transaction = dbContext.Database.BeginTransaction())
                {
                    try
                    {
                        string key = ApplicationConst.RedisKey.InfraredStudyPreFix + subDto.SendBack.Key;
                        if (!redisClient.KeyExists(key))
                            throw new Exception("红外学习的缓存key不存在!");

                        var value = await redisClient.StringGetAsync<string>(key);
                        var deviceId = value.Split("|")[0];
                        var modelCmdId = value.Split("|")[1];

                        //将学习码放在缓存中,前端轮训获取
                        string noticKey = ApplicationConst.RedisKey.InfraredStudyNoticePreFix + deviceId;
                        if (!redisClient.KeyExists(noticKey))
                            throw new Exception("红外学习通知的缓存key不存在!");

                        await redisClient.StringSetAsync(noticKey, subDto.CmdCode, TimeSpan.FromSeconds(300));

                        //更新学习结果到数据库中
                        var modelCmd = await dbContext.ModelCmds.FirstOrDefaultAsync(a => a.Id == modelCmdId);
                        if (modelCmd != null)
                        {
                            modelCmd.Code = subDto.CmdCode;
                            dbContext.Update(modelCmd);
                        }

                        lock (this)
                        {
                            //将学习码更新到设备命令表中
                            var deviceCmd = dbContext.DeviceCmds.FirstOrDefault(a => a.Name == modelCmd.Name && a.DeviceId == deviceId);
                            if (deviceCmd == null)
                            {
                                var cmdEntity = new DeviceCmd
                                {
                                    CmdId = Guid.NewGuid().ToString(),
                                    DeviceId = deviceId,
                                    Code = subDto.CmdCode,
                                    CreateBy = modelCmd.UpdateBy,
                                    CreateTime = DateTime.Now,
                                    Name = modelCmd.Name,
                                    UpdateBy = modelCmd.UpdateBy,
                                    UpdateTime = DateTime.Now,
                                    Remark = string.Empty
                                };
                                dbContext.Add(cmdEntity);
                            }
                            else
                            {
                                deviceCmd.Code = subDto.CmdCode;
                                dbContext.Update(deviceCmd);
                            }

                            dbContext.SaveChanges();
                            transaction.Commit();
                            redisClient.KeyDelete(key);
                            redisClient.KeyDelete(noticKey);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"订阅红外学习结果失败,错误详情:{ex.Message}");
                        await transaction.RollbackAsync();
                        throw;
                    }
                }
            }
        }

        /// <summary>
        /// 设备心跳处理函数
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="messageDto"></param>
        /// <returns></returns>
        private async Task DeviceHeartbeatSubHandle(string topic, MqttMessageDto messageDto)
        {
            var topicItem = topic.Split("/");
            var gatewayId = topicItem[3];
            var subDto = JsonConvert.DeserializeObject<DeviceHeartbeatSubDto>(messageDto.Msg.ToString());
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                //更新设备状态
                var dbContext = scope.ServiceProvider.GetRequiredService<_91iotdbContext>();
                var query = from a in dbContext.GatewayCommunicationPorts
                            join b in dbContext.Devices on a.Id equals b.GCPortId
                            where a.PortCode == subDto.PortNum && a.IsDelete == false && b.GatewayId == gatewayId && b.AddressBitNum == subDto.DeviceAddr && b.IsDelete == false
                            select b;

                var deviceEntitys =await query.ToListAsync();
                if (deviceEntitys.Count == 0)
                {
                    _logger.LogError($"设备心跳上报失败,查找不到设备,设备挂接的网关端口编码:{subDto.PortNum},设备的地址位:{subDto.DeviceAddr},主题信息:{topic}");
                    return;
                }

                var deviceEntity = deviceEntitys.FirstOrDefault() ;
                deviceEntity.Status = (int)subDto.Alive;
                deviceEntity.StatusUpdateTime = DateTime.Now;
                dbContext.Update(deviceEntity);
                await dbContext.SaveChangesAsync();

                //将状态持久化到状态历史表
                var baseRepository = scope.ServiceProvider.GetRequiredService<IDeviceStateHistoryRepository>();
                var history = new DeviceStateHistory
                {
                    Id = Guid.NewGuid().ToString(),
                    DeviceId = deviceEntity.Id,
                    DeviceName = deviceEntity.Name,
                    Status = subDto.Alive,
                    CreateTime = DateTime.Now
                };
                await baseRepository.Insert(history);
            }
        }
        #endregion
    }
}
using Dept9IOT.DeviceInfo.IRepository;
using Dept9IOT.DeviceInfo.IServices;
using Dept9IOT.DeviceInfo.Model.DbModels;
using Dept9IOT.DeviceInfo.Unity;
using Dept9IOT.DeviceInfo.Unity.DtoModel;
using Dept9IOT.DeviceInfo.Unity.Enums;
using Dept9IOT.DeviceInfo.Unity.Helpers;
using Dept9IOT.DeviceInfo.Unity.InputModel;
using Dept9IOT.DeviceInfo.Unity.InputModel.UpdateInput;
using Dept9IOT.DeviceInfo.Unity.Models.InputModel.DeviceBrand;
using evoc9.Collections;
using evoc9.Common;
using evoc9.Linq;
using evoc9.Redis;
using Evoc9.Common;
using Evoc9.Common.Client;
using Evoc9.EFCore.SqlBase;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Dept9IOT.DeviceInfo.Services
{
     public  class DeviceBrandService:IDeviceBrandService
    {
        private readonly ILogger _logger;
        private readonly _91iotdbContext _dbContext;

        public DeviceBrandService(ILogger<DeviceBrandService> logger,_91iotdbContext dbContext)
        {
            _logger = logger;
            _dbContext = dbContext;
    }

        //删除
        public async Task Delete(string id)
        {
            var entity = await _dbContext.DeviceBrands.FirstOrDefaultAsync(a => a.Id == id && a.IsDelete == false);
            if (entity == null)
                throw new Exception("要删除的品牌不存在!");

            entity.IsDelete = true;
           // _dbContext.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        //批量删除
        public async Task Delete(List<string> ids)
        {
            using var tran = _dbContext.Database.BeginTransaction();
            try
            {
                var entitys = await _dbContext.DeviceBrands.Where(a => ids.Contains(a.Id) && a.IsDelete == false).ToListAsync();

                foreach (var item in entitys)
                {
                    item.IsDelete = true;
                }

                _dbContext.UpdateRange(entitys);
                await _dbContext.SaveChangesAsync();

                await tran.CommitAsync();
            }
            catch (Exception ex)
            {
                await tran.RollbackAsync();
                throw new Exception($"删除失败!详情:{ex.Message}");
            }
        }

        //获取
        public async Task<DeviceBrand> Get(string id)
        {
            var entity = await _dbContext.DeviceBrands.FirstOrDefaultAsync(a => a.Id == id && a.IsDelete == false);
            if(entity==null)
                throw new Exception("品牌不存在!");
            return entity;
        }

        //获取分页列表
        public async Task<PageResult<DeviceBrandDto>> GetListBySearch(DeviceBrandSearchInput input)
        {
            var query = from a in _dbContext.DeviceBrands
                        join b in _dbContext.DeviceModels on a.Id equals b.BrandId
                        select new
                        {
                            DeviceBrand = a,
                            DeviceModel = b
                        };

            var queryTuple = await query.ToListAsync();
            List<DeviceBrand> entitys;
            int count;
            count = await _dbContext.DeviceBrands
                .WhereIf(a=> a.Name.Contains(input.KeyWord) || a.EnName.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                .WhereIf(a => a.DictId == input.DictId, !string.IsNullOrEmpty(input.DictId))
                .WhereIf(a => a.BrandCategory == (int)input.BrandCategory, input.BrandCategory != BrandCategory.CheckAll)
                .Where(a =>a.IsDelete==false).CountAsync();
            entitys = await _dbContext.DeviceBrands
                 .WhereIf(a => a.Name.Contains(input.KeyWord) || a.EnName.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                .WhereIf(a => a.DictId == input.DictId, !string.IsNullOrEmpty(input.DictId))
                .WhereIf(a => a.BrandCategory == (int)input.BrandCategory, input.BrandCategory != BrandCategory.CheckAll)
                .Where(a => a.IsDelete == false)
                .Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToListAsync();
            PageResult<DeviceBrandDto> pageResult = new PageResult<DeviceBrandDto>();
            List<DeviceBrandDto> dtos = new List<DeviceBrandDto>();
            
            entitys.ForEach(a =>
            {
                DeviceBrandDto dto = new DeviceBrandDto();
                //同等效果代码:
                dto = ExpressionMapper<DeviceBrand, DeviceBrandDto>.Map(a);
                dto.BrandCategory = (BrandCategory)a.BrandCategory;
                dto.Number = queryTuple.Where(b => b.DeviceModel.BrandId == a.Id && b.DeviceModel.IsDelete == false).Count();
                dtos.Add(dto);
            });

            pageResult.DataList = dtos;
            pageResult.PageIndex = input.PageIndex;
            pageResult.PageSize = input.PageSize;
            pageResult.TotalCount = count;
            return pageResult;
        }

        private DeviceBrandSimpleDto GetModelDto(DeviceBrand deviceBrand)
        {
            return new DeviceBrandSimpleDto
            {
                //BrandCategory = (BrandCategory)deviceBrand.BrandCategory,
                DictId = deviceBrand.DictId,
                Id = deviceBrand.Id,
                Name = deviceBrand.Name,
                EnName = deviceBrand.EnName
            };
        }

        //获取简单数据列表
        public async Task<List<DeviceBrandSimpleDto>> GetSimpleList()
        {
            var deviceBrandList = await _dbContext.DeviceBrands.Where(a => a.IsDelete != true).ToListAsync();
            List<DeviceBrandSimpleDto> list = null;
            if(deviceBrandList != null)
            {
                list = new List<DeviceBrandSimpleDto>();
                deviceBrandList.ForEach(a =>
                {
                    
                    list.Add(GetModelDto(a));
                });
            }
            return list;
        }

        //根据DictId获取品牌简单数据列表
        public async Task<List<DeviceBrandSimpleDto>> GetSimpleListByDictId(string dictId)
        {
            var deviceBrandList = await _dbContext.DeviceBrands.Where(a =>a.DictId==dictId && a.IsDelete == false).ToListAsync();
            List<DeviceBrandSimpleDto> list = null;
            if (deviceBrandList != null)
            {
                list = new List<DeviceBrandSimpleDto>();
                deviceBrandList.ForEach(a =>
                {
                    
                    list.Add(GetModelDto(a));
                });
            }
            return list;
        }

        //插入
        public async Task Insert(DeviceBrand deviceBrand)
        {
            //先从数据库里查出来 查重
            var entity = await _dbContext.DeviceBrands.FirstOrDefaultAsync(a => a.Name == deviceBrand.Name && a.DictId == deviceBrand.DictId && a.IsDelete == false);
            if (entity != null)
                throw new Exception("品牌已存在,请勿重复添加!");

            await _dbContext.DeviceBrands.AddAsync(deviceBrand);
            await _dbContext.SaveChangesAsync();
        }

        //更新
        public async Task Update(string _userId, DeviceBrandUpdateInput input)
        {
            //先从数据库里查出来,逐个改状态,除了唯一ID和Creat系列都改变
            var entity = await _dbContext.DeviceBrands.FirstOrDefaultAsync(a => a.Id == input.Id && a.IsDelete == false);
            if (entity == null)
            {
                throw new Exception("要更新的品牌ID不存在");
            }
            {
                entity.BrandCategory = (int)input.BrandCategory;
                entity.DictId = input.DictId;
                entity.Name = input.Name;
                entity.EnName = input.EnName;
                entity.Remark = input.Remark;
                entity.UpdateBy = _userId;
                entity.UpdateTime = DateTime.Now;
            }
            _dbContext.DeviceBrands.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        #region A06版本

        //根据品牌类型获取品牌简单数据列表
        public async Task<List<DeviceBrandSimpleDto>> GetSimpleListByGatewayCategory(BrandCategory brandCategory)
        {
            var deviceBrandList = await _dbContext.DeviceBrands
                 .WhereIf(a => a.BrandCategory == (int)brandCategory, brandCategory != BrandCategory.CheckAll)
                 .Where(a => a.IsDelete == false).ToListAsync();
               
            List<DeviceBrandSimpleDto> list = null;
            if (deviceBrandList != null)
            {
                list = new List<DeviceBrandSimpleDto>();
                deviceBrandList.ForEach(a =>
                {
                    
                    list.Add(GetModelDto(a));
                });
            }
            return list;
        }

        

        public Task<List<DeviceBrandSimpleDto>> GetSimInfoListBySearch(BrandCategory brandCategory)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}

using Evoc9.Common;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dept9IOT.DeviceInfo.Unity.InputModel;
using Dept9IOT.DeviceInfo.IServices;
using Evoc9.Common.Aop;
using Dept9IOT.DeviceInfo.Model.DbModels;
using evoc9.Filter;
using System.ComponentModel.DataAnnotations;
using Dept9IOT.DeviceInfo.Unity.InputModel.UpdateInput;
using Dept9IOT.DeviceInfo.Unity.DtoModel;
using Dept9IOT.DeviceInfo.Unity.Enums;
using Dept9IOT.DeviceInfo.Unity.Models.InputModel.DeviceBrand;

namespace Dept9IOT.DeviceInfo.WebApi.Controllers.A05
{
    /// <summary>
    /// 品牌表的增删改查接口
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class DeviceBrandController : ControllerBase
    {
        private readonly ILogger<DeviceBrandController> _logger;
        private readonly IDeviceBrandService _deviceBrandService;

        public DeviceBrandController(ILogger<DeviceBrandController> logger, IDeviceBrandService deviceBrandService)
        {
            _logger = logger;
            _deviceBrandService = deviceBrandService;
        }

        /// <summary>
        /// 插入一条品牌分类(后台对接)
        /// </summary>
        /// <param name="input">品牌模型输入</param>
        /// <returns></returns>
        [HttpPost("A06/Add")]
        public async Task<ApiResult> Insert(DeviceBrandInput input)
        {
            var _userId = User.GetLoginUserId();
            var verify = InputVerifyExtension.Verify(input);
            if (!string.IsNullOrEmpty(verify))
            {
                return ApiResultUnity.Error(ApiEnum.Error, $"校验失败:{verify}");
            }
            DeviceBrand deviceBrand = new DeviceBrand
            {
                DictId = input.DictId,
                BrandCategory = (int)input.BrandCategory,
                Name = input.Name,
                EnName = input.EnName,
                Remark = input.Remark,
                Id = Guid.NewGuid().ToString(),
                CreateBy = _userId,
                CreateTime = DateTime.Now,
                UpdateBy = _userId,
                UpdateTime = DateTime.Now,
            };

            await _deviceBrandService.Insert(deviceBrand);
            return ApiResultUnity.Success();
        }

        /// <summary>
        /// 根据品牌id获取一条信息(后台对接)
        /// </summary>
        /// <param name="id">品牌ID</param>
        /// <returns></returns>
        [HttpGet("A06/Get/{id}")]
        [ProducesResponseType(typeof(DeviceBrand), 200)]
        public async Task<ApiResult> Get([Required] string id)
        {
            var data = await _deviceBrandService.Get(id);
            return ApiResultUnity.Success(data);
        }

        /// <summary>
        /// 根据id删除一条品牌信息(后台对接)
        /// </summary>
        /// <param name="id">要删除的品牌ID</param>
        /// <returns></returns>
        [HttpDelete("A06/Delete/{id}")]
        public async Task<ApiResult> Delete([Required] string id)
        {

            await _deviceBrandService.Delete(id);
            return ApiResultUnity.Success();
        }

        /// <summary>
        /// 根据ids列表删除(后台对接)
        /// </summary>
        /// <param name="ids">要删除的ids</param>
        /// <returns></returns>
        [HttpDelete("A06/Delete/List")]
        public async Task<ApiResult> Delete([FromBody] List<string> ids)
        {
            await _deviceBrandService.Delete(ids);
            return ApiResultUnity.Success();
        }

        /*/// <summary>
        /// 获取品牌简单数据列表(APP 对接)
        /// </summary>
        /// <returns></returns>
        [HttpGet("A05/List")]
        [ProducesResponseType(typeof(List<DeviceBrandSimpleDto>), 200)]
        public async Task<ApiResult> GetSimpleList()
        {
            var data = await _deviceBrandService.GetSimpleList();
            return ApiResultUnity.Success(data);
        }*/

        /// <summary>
        /// 根据数据字典id(品类Id)获取品牌简单数据列表(APP对接)
        /// </summary>
        /// <param name="dictId">数据字典id(品类Id)</param>
        /// <returns></returns>
        [HttpGet("A06/SimInfo/List/ByDictId")]
        [ProducesResponseType(typeof(List<DeviceBrandSimpleDto>), 200)]
        public async Task<ApiResult> GetSimpleListByDictId(string dictId)
        {
            var data = await _deviceBrandService.GetSimpleListByDictId(dictId);
            return ApiResultUnity.Success(data);
        }


       
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("A06/Search/List")]
        [ProducesResponseType(typeof(PageResult<DeviceBrandDto>), 200)]
        public async Task<ApiResult> GetListBySearch([FromQuery]DeviceBrandSearchInput input)
        {
            var data = await _deviceBrandService.GetListBySearch(input);
            return ApiResultUnity.Success(data);
        }


        /// <summary>
        /// 更新数据(后台对接)
        /// </summary>
        /// <param name="input">品牌更新模型</param>
        /// <returns></returns>
        [HttpPut("A06/Update")]
        public async Task<ApiResult> Update([FromBody] DeviceBrandUpdateInput input)
        {
            var _userId = User.GetLoginUserId();

            await _deviceBrandService.Update(_userId, input);
            return ApiResultUnity.Success();
        }

        /// <summary>
        /// 根据品牌类型获取品牌简单数据列表(APP对接)
        /// </summary>
        /// <param name="brandCategory">品牌类型(0全部 1设备 2网关)</param>
        /// <returns></returns>
        [HttpGet("A06/SimInfo/List/ByBrandCategory")]
        [ProducesResponseType(typeof(List<DeviceBrandSimpleDto>), 200)]
        public async Task<ApiResult> GetSimpleListByGatewayCategory([Required]BrandCategory brandCategory)
        {
            var data = await _deviceBrandService.GetSimpleListByGatewayCategory(brandCategory);
            return ApiResultUnity.Success(data);
        }

    }   
}
using Dept9IOT.DeviceInfo.IRepository.Base;
using Dept9IOT.DeviceInfo.Model.DbModels;
using Dept9IOT.DeviceInfo.Unity.DtoModel;
using Dept9IOT.DeviceInfo.Unity.Enums;
using Dept9IOT.DeviceInfo.Unity.InputModel;
using Dept9IOT.DeviceInfo.Unity.InputModel.UpdateInput;
using Dept9IOT.DeviceInfo.Unity.Models.InputModel.DeviceBrand;
using Evoc9.Common;
using Evoc9.EFCore.SqlBase;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Dept9IOT.DeviceInfo.IServices
{
    public interface IDeviceBrandService
    {
        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        Task Insert(DeviceBrand entity);

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="_userId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        Task Update( string _userId, DeviceBrandUpdateInput input);

        /// <summary>
        /// 根据id获取
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<DeviceBrand> Get(string id);

        /// <summary>
        /// 根据id删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task Delete(string id);

        /// <summary>
        /// 根据id列表删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        Task Delete(List<string> ids);

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        Task<PageResult<DeviceBrandDto>> GetListBySearch(DeviceBrandSearchInput input);

        /// <summary>
        /// 获取品牌简单数据列表
        /// </summary>
        /// <returns></returns>
        Task<List<DeviceBrandSimpleDto>> GetSimpleList();

        /// <summary>
        /// 根据DictId获取品牌简单数据列表
        /// </summary>
        /// <param name="dictId">数据字典Id(品类Id)</param>
        /// <returns></returns>
        Task<List<DeviceBrandSimpleDto>> GetSimpleListByDictId(string dictId);



        #region A06 版本
        /// <summary>
        /// 根据品牌类型获取品牌简单数据列表
        /// </summary>
        /// <param name="gatewayCategory">品牌类型</param>
        /// <returns></returns>
        Task<List<DeviceBrandSimpleDto>> GetSimpleListByGatewayCategory(BrandCategory brandCategory);

        
        #endregion
    }
}
using CrateProjectModel.Models;
using Dept9IOT.DeviceInfo.IServices;
using Dept9IOT.DeviceInfo.Model.DbModels;
using Dept9IOT.DeviceInfo.Unity.DtoModel.GatewayDevice;
using Dept9IOT.DeviceInfo.Unity.InputModel.CustomProtocol;
using Evoc9.EFCore.SqlBase;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using evoc9.Collections;
using Dept9IOT.DeviceInfo.Model.Enums;
using Dept9IOT.DeviceInfo.Unity.Helpers;
using Dept9IOT.DeviceInfo.Unity.InputModel.Gateway;
using Dept9IOT.DeviceInfo.WebApi.CoreBuilder.CoreMqtt;
using Dept9IOT.DeviceInfo.Unity.Consts;
using Dept9IOT.DeviceInfo.Unity.Models.InputModel.Gateway;

namespace Dept9IOT.DeviceInfo.Services
{
    /// <summary>
    /// 网关服务
    /// </summary>
    public class GatewayService : IGatewayService
    {
        private readonly _91iotdbContext _dbContext;
        private readonly INMqttClientService _mqttClientService;

        public GatewayService(_91iotdbContext dbContext,
            INMqttClientService mqttClientService)
        {
            _dbContext = dbContext;
            _mqttClientService = mqttClientService;
        }

        //添加
        public async Task Insert(Gateway entity)
        {
            var t_entity =await _dbContext.Gateways.FirstOrDefaultAsync(a=>(a.Snid==entity.Snid||a.Mac==entity.Mac)&&a.IsDelete==false);
            if (t_entity != null)
                throw new Exception($"添加失败,已存在Snid为{entity.Snid},或Mac为{entity.Mac}的网关");
            await _dbContext.AddAsync(entity);
            await _dbContext.SaveChangesAsync();
        }

        //更新网关信息
        public async Task UpdateByDto(UpdateGatewayInput input)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a => a.Id == input.Id);
            if (entity == null)
                throw new Exception("要删除的网关不存在");
            entity.Mac = input.Mac;
            entity.Ip = input.Ip;
            entity.Mac = input.Mac;
            entity.Snid = input.Snid;
            entity.Name = input.Name;
            entity.QrCodeInfo = input.QrCodeInfo;
            entity.BrandId = input.BrandId;
            entity.ModelId = input.ModelId;
            entity.Remark = input.Remark;
            _dbContext.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        //根据id删除
        public async Task Delete(string Id)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a=>a.Id== Id);
            if (entity == null)
                throw new Exception("要删除的网关不存在");
            entity.IsDelete = true;
            _dbContext.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        //接入真实网关
        public async Task<GatewayBriefDto> JoinRealGateway(JoinRealGatewayInput input)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a => a.Snid== input.Snid&&a.IsDelete==false);
            if (entity == null)
                throw new Exception($"接入网关失败,网关尚未录入系统,网关snid:{input.Snid}!");
            entity.Mac = input.Mac;
            entity.Ip = input.Ip;
            entity.JoinStatus = JoinStatus.Joined;
            entity.Status = DeviceStatus.Offline;
            await _dbContext.SaveChangesAsync();

            //订阅服务
            var resultTopic = ApplicationConst.SubToticPrefix+ $"{(int)JoinToMqttWay.Real}/{entity.Id}";
            var subscribeResult = await _mqttClientService.SubscribeAsync(resultTopic);
            return new GatewayBriefDto { Id= entity.Id, GwHbTime = entity.StatusTimeInterval};
        }

        /// <summary>
        /// 检查接入状态
        /// </summary>
        /// <param name="sind"></param>
        /// <returns></returns>
        public async Task CheckJoinStatus(string sind, string userId)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a => a.Snid == sind);
            if (entity == null)
                throw new Exception("网关未接入!");
            entity.UserId = userId;
            _dbContext.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        //接入虚拟网关
        public async Task<GatewayBriefDto> JoinVirtualGateway(JoinVirtualGatewayInput input)
        {
            using var tran = _dbContext.Database.BeginTransaction();
            try
            {
                var verifyCode = await _dbContext.VerifyCodes.FirstOrDefaultAsync(a => a.Code == input.VerifyCode);
                if (verifyCode == null || verifyCode?.CreateTime.AddSeconds((double)verifyCode?.ValidTime) > DateTime.Now || verifyCode.IsValid == false)
                    throw new Exception("验证码不存在!");

                verifyCode.IsValid = false;
                _dbContext.Update(verifyCode);
                Gateway entity = new Gateway
                {
                    Id = Guid.NewGuid().ToString(),
                    Mac = input.Mac,
                    UserId = verifyCode.UserId,
                    Ip = input.Ip,
                    Snid = input.Sind,
                    Remark = input.Remark,
                    JoinStatus = JoinStatus.Joined,
                    Status = DeviceStatus.Online
                };

                await _dbContext.AddAsync(entity);
                await tran.CommitAsync();
                return new GatewayBriefDto { Id = entity.Id, GwHbTime = entity.StatusTimeInterval };
            }
            catch (Exception ex)
            {
                await tran.RollbackAsync();
                throw new Exception($"接入失败!详情:{ex.Message}");
            }
        }

        //根据id获取信息
        public async Task<Gateway> Get(string Id)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a => a.Id == Id);
            if (entity == null)
                throw new Exception("查询的网关不存在");

            return entity;
        }

        //根据id获取dto信息
        public async Task<GatewayDto> GetDto(string Id)
        {
            var entity = await _dbContext.Gateways.FirstOrDefaultAsync(a => a.Id == Id);
            if (entity == null)
                throw new Exception("查询的网关不存在");

            var brandEntity = await _dbContext.DeviceBrands.FirstOrDefaultAsync(a => a.Id == entity.BrandId);
            var modelEntity = await _dbContext.DeviceModels.FirstOrDefaultAsync(a => a.Id == entity.ModelId);

            var dto = ExpressionMapper<Gateway, GatewayDto>.Map(entity);
            dto.BrandName = brandEntity != null ? brandEntity.Name : string.Empty;
            dto.ModelName = modelEntity != null ? modelEntity.Name : string.Empty;
            return dto;
        }

        //搜索获取分页信息列表
        public async Task<PageResult<GatewayDto>> GetListBySearch(GatewaySearchInput input)
        {
            var entitys =await _dbContext.Gateways
                .WhereIf(a => a.Name.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                .WhereIf(b => b.GatewayType == input.GatewayType, input.GatewayType != GatewayType.CheckAll)
                .WhereIf(b => b.Status == input.Status, input.Status != DeviceStatus.CheckAll)
                .WhereIf(b => b.JoinStatus == input.JoinStatus, input.JoinStatus != JoinStatus.CheckAll)
                .WhereIf(b => b.GatewayType == input.GatewayType, input.GatewayType != GatewayType.CheckAll)
                .Where(c=>c.IsDelete==false)
                .Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToListAsync();

            var count = await _dbContext.Gateways
               .WhereIf(a => a.Name.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
               .WhereIf(b => b.Status == input.Status, input.Status != DeviceStatus.CheckAll)
               .WhereIf(b => b.JoinStatus == input.JoinStatus, input.JoinStatus != JoinStatus.CheckAll)
               .WhereIf(b => b.GatewayType == input.GatewayType, input.GatewayType != GatewayType.CheckAll)
               .Where(c => c.IsDelete == false).CountAsync();

            var brandIds = entitys.Select(a=>a.BrandId).Distinct().ToList();
            var brandEntitys = await _dbContext.DeviceBrands.Where(a => brandIds.Contains(a.Id)).ToListAsync();

            var modelIds = entitys.Select(a => a.ModelId).Distinct().ToList();
            var modelIdEntitys = await _dbContext.DeviceModels.Where(a => modelIds.Contains(a.Id)).ToListAsync();

            PageResult<GatewayDto> pageResult = new PageResult<GatewayDto>();
            List<GatewayDto> dtos = new List<GatewayDto>();
            entitys.ForEach(item =>
            {
                GatewayDto dto = new GatewayDto();
                dto = ExpressionMapper<Gateway, GatewayDto>.Map(item);
                var brand = brandEntitys.FirstOrDefault(a=>a.Id==item.BrandId);
                var model = modelIdEntitys.FirstOrDefault(a => a.Id == item.ModelId);
                dto.BrandName = brand != null ? brand.Name : string.Empty;
                dto.ModelName = model != null ? model.Name : string.Empty;
                dtos.Add(dto);
            });

            pageResult.DataList = dtos;
            pageResult.PageIndex = input.PageIndex;
            pageResult.PageSize = input.PageSize;
            pageResult.TotalCount = count;
            return pageResult;
        }
    }
}

using CrateProjectModel.Models;
using Dept9IOT.DeviceInfo.IServices;
using Dept9IOT.DeviceInfo.Model.DbModels;
using Dept9IOT.DeviceInfo.Model.Enums;
using Dept9IOT.DeviceInfo.Unity.DtoModel.Device;
using Dept9IOT.DeviceInfo.Unity.DtoModel.GatewayCommunicationPort;
using Dept9IOT.DeviceInfo.Unity.Helpers;
using Dept9IOT.DeviceInfo.Unity.InputModel.Device;
using Dept9IOT.DeviceInfo.Unity.InputModel.GatewayCommunicationPort;
using evoc9.Collections;
using Evoc9.EFCore.SqlBase;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dept9IOT.DeviceInfo.Services
{
    /// <summary>
    /// 网关通讯端口服务接口
    /// </summary>
    public class GatewayCommunicationPortService : IGatewayCommunicationPortService
    {
        private readonly _91iotdbContext _dbContext;

        public GatewayCommunicationPortService(_91iotdbContext dbContext)
        {
            _dbContext = dbContext;
        }

        //插入
        public async Task Insert(GatewayCommunicationPort entity)
        {
            await _dbContext.AddAsync(entity);
            await _dbContext.SaveChangesAsync();
        }

        //根据id删除
        public async Task Delete(string Id)
        {
            var entity =await _dbContext.GatewayCommunicationPorts.FirstOrDefaultAsync(a=>a.Id == Id);
            if (entity == null)
                throw new Exception("网关端口不存在!");
            entity.IsDelete = true;
            _dbContext.Update(entity);
            await _dbContext.SaveChangesAsync();
        }

        //根据id获取
        public Task<GatewayCommunicationPort> Get(string Id)
        {
            throw new NotImplementedException();
        }

        //获取通讯端口信息
        public async Task<GatewayCommunicationPortDto> GetDto(string Id)
        {
            var entity = await _dbContext.GatewayCommunicationPorts.FirstOrDefaultAsync(a => a.Id == Id&&a.IsDelete==false);
            if(entity==null)
                throw new Exception("查询的设备不存在!");

            var gatewayEntity = await _dbContext.Gateways.FirstOrDefaultAsync(a=>a.Id== entity.GatewayId&&a.IsDelete==false);
            if(gatewayEntity==null)
                throw new Exception("通讯端口所属的网关不存在,请检查数据的完整性!");

            var dto = ExpressionMapper<GatewayCommunicationPort, GatewayCommunicationPortDto>.Map(entity);
            dto.GatewayName = gatewayEntity.Name;
            return dto;
        }

        //搜索获取分页信息列表
        public async Task<PageResult<GatewayCommunicationPortDto>> GetListBySearch(GCPortSearchInput input)
        {
            var entitys = await _dbContext.GatewayCommunicationPorts
                .WhereIf(a=>a.GatewayId== input.GatewayId,!string.IsNullOrEmpty(input.GatewayId))
                    .WhereIf(a => a.PortName.Contains(input.KeyWord) || a.GatewayId.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                    .WhereIf(b => b.CommunicationModeType == input.PortType, input.PortType != CommunicationModeType.CheckAll)
                    .Where(f => f.IsDelete == false)
                    .Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToListAsync();

            var count = await _dbContext.GatewayCommunicationPorts
                .WhereIf(a => a.GatewayId == input.GatewayId, !string.IsNullOrEmpty(input.GatewayId))
                 .WhereIf(a => a.PortName.Contains(input.KeyWord) || a.GatewayId.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                 .WhereIf(b => b.CommunicationModeType == input.PortType, input.PortType != CommunicationModeType.CheckAll)
                .Where(f => f.IsDelete == false).CountAsync();

            var gatewayIds = entitys.Select(a=>a.GatewayId).ToList();
            var gatewagyEntitys = await _dbContext.Gateways.Where(a => gatewayIds.Contains(a.Id) && a.IsDelete == false).ToListAsync();

            PageResult<GatewayCommunicationPortDto> pageResult = new PageResult<GatewayCommunicationPortDto>();
            List<GatewayCommunicationPortDto> dtos = new List<GatewayCommunicationPortDto>();
            entitys.ForEach(item =>
            {       
                var dto = ExpressionMapper<GatewayCommunicationPort, GatewayCommunicationPortDto>.Map(item);
                var gateway = gatewagyEntitys.FirstOrDefault(a => a.Id == item.GatewayId);
                dto.GatewayName = gateway != null ? gateway.Name : string.Empty;
                dtos.Add(dto);
            });

            pageResult.DataList = dtos;
            pageResult.PageIndex = input.PageIndex;
            pageResult.PageSize = input.PageSize;
            pageResult.TotalCount = count;
            return pageResult;

        }

        //搜索获取简要信息分页列表
        public async Task<PageResult<GCPortSimDto>> GetSimInfoListBySearch(GCPortSearchInput input)
        {
            var entitys = await _dbContext.GatewayCommunicationPorts
                .WhereIf(a => a.GatewayId == input.GatewayId, !string.IsNullOrEmpty(input.GatewayId))
                        .WhereIf(a => a.PortName.Contains(input.KeyWord) || a.GatewayId.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                        .WhereIf(b => b.CommunicationModeType == input.PortType, input.PortType != CommunicationModeType.CheckAll)
                        .Where(f => f.IsDelete == false)
                        .Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToListAsync();

            var count = await _dbContext.GatewayCommunicationPorts
                .WhereIf(a => a.GatewayId == input.GatewayId, !string.IsNullOrEmpty(input.GatewayId))
                 .WhereIf(a => a.PortName.Contains(input.KeyWord) || a.GatewayId.Contains(input.KeyWord), !string.IsNullOrEmpty(input.KeyWord))
                 .WhereIf(b => b.CommunicationModeType == input.PortType, input.PortType != CommunicationModeType.CheckAll)
                .Where(f => f.IsDelete == false).CountAsync();

            PageResult<GCPortSimDto> pageResult = new PageResult<GCPortSimDto>();
            List<GCPortSimDto> dtos = new List<GCPortSimDto>();
            entitys.ForEach(item =>
            {
                var dto = ExpressionMapper<GatewayCommunicationPort, GCPortSimDto>.Map(item);
                dtos.Add(dto);
            });

            pageResult.DataList = dtos;
            pageResult.PageIndex = input.PageIndex;
            pageResult.PageSize = input.PageSize;
            pageResult.TotalCount = count;
            return pageResult;
        }
    }
}