添加项目文件。

This commit is contained in:
yanghongwei 2024-05-20 22:56:49 +08:00
parent 316344685d
commit 4d5444d8f6
51 changed files with 4499 additions and 0 deletions

25
.dockerignore Normal file
View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

25
langguanApi.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34221.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "langguanApi", "langguanApi\langguanApi.csproj", "{99745E10-D0AE-46BC-B23E-A24483532FEF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{99745E10-D0AE-46BC-B23E-A24483532FEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99745E10-D0AE-46BC-B23E-A24483532FEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99745E10-D0AE-46BC-B23E-A24483532FEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99745E10-D0AE-46BC-B23E-A24483532FEF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9FA08BD4-39EF-4F6E-B3C9-990729D8ED1A}
EndGlobalSection
EndGlobal

1255
langguanApi.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}

View File

@ -0,0 +1,41 @@
using langguanApi.Common.Redis;
using langguanApi.Extensions.AutoDI;
using Newtonsoft.Json;
using StackExchange.Redis;
namespace langguanApi.Common
{
/// <summary>
/// 缓存管理
/// </summary>
[ServiceInjection(InjectionType.Singleton)]
public class CacheManager
{
private readonly IDatabase _redisDatabase;
public CacheManager(RedisHelper redisHelper)
{
_redisDatabase = redisHelper._database;
}
/// <summary>
/// 缓存数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cacheKey"></param>
/// <param name="dataFetcher"></param>
/// <param name="seconds">缓存时间秒0=int.max </param>
/// <returns></returns>
public async Task<T> GetConvertVale<T>(string cacheKey, Func<Task<T>> dataFetcher, int seconds = 0)
{
var cacheData = await _redisDatabase.StringGetAsync(cacheKey);
if (cacheData.IsNull)
{
var temp = await dataFetcher();
cacheData = JsonConvert.SerializeObject(temp);
seconds = seconds == 0 ? int.MaxValue : seconds;
await _redisDatabase.StringSetAsync(cacheKey, cacheData, TimeSpan.FromSeconds(seconds), When.NotExists);
return temp;
}
return JsonConvert.DeserializeObject<T>(cacheData);
}
}
}

View File

@ -0,0 +1,20 @@
using StackExchange.Redis;
namespace langguanApi.Common.Redis
{
public class RedisHelper
{
public IDatabase _database;
/// <summary>
/// sub
/// </summary>
public ISubscriber _subscriber;
public RedisHelper()
{
// var con = RedisOptions.Default.GetConnect();
IConnectionMultiplexer connection = ConnectionMultiplexer.Connect(RedisOptions.Default.GetConnect());
_subscriber = connection.GetSubscriber();
_database = connection.GetDatabase(RedisOptions.Default.Index);
}
}
}

View File

@ -0,0 +1,11 @@
namespace langguanApi.Common.Redis
{
public class RedisKeylist
{
public static string UserLoginInfo = "UserLoginInfo";
/// <summary>
/// 缓存天气信息
/// </summary>
public static string Weather = "weather";
}
}

View File

@ -0,0 +1,54 @@
namespace langguanApi.Common.Redis
{
public class RedisOptions
{
public static readonly RedisOptions Default = new RedisOptions();
public RedisOptions()
{
this.Server = null;
this.Port = 6379;
this.Password = null;
this.Key = null;
this.Index = 0;
}
/// <summary>
/// redis 服务地址
/// </summary>
public string Server { get; set; }
/// <summary>
/// redis 端口
/// </summary>
public int Port { get; set; }
/// <summary>
/// redis 连接密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 自定义Key
/// </summary>
public string Key { get; set; }
/// <summary>
/// 默认数据库索引
/// </summary>
public int Index { get; set; }
public string Connection { get; set; }
/// <summary>
/// 转换数据库连接字符串
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public string GetConnect()
{
if (string.IsNullOrWhiteSpace(Password))
return $"{Server}";
else
return $"{Server},password={Password}";
}
}
}

View File

@ -0,0 +1,67 @@
using langguanApi.Model;
using langguanApi.Model.Dto;
using langguanApi.Service;
using Microsoft.AspNetCore.Mvc;
namespace langguanApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class DeviceController : ControllerBase
{
private readonly DeviceService _deviceService;
/// <summary>
///
/// </summary>
/// <param name="deviceService"></param>
public DeviceController(DeviceService deviceService)
{
_deviceService = deviceService;
}
/// <summary>
/// 列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Getpage([FromQuery] reqpage input)
{
var result = await _deviceService.GetPage(input);
return Ok(result);
}
/// <summary>
///新加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Addd([FromBody] DeviceDto input)
{
var result = await _deviceService.Add(input);
return Ok(result);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpDelete]
public async Task<IActionResult> Remove(IEnumerable<string> ids)
{
var result = await _deviceService.remove(ids);
return Ok(result);
}
/// <summary>
/// 更新
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPut]
public async Task<IActionResult> update([FromBody] DeviceDto input)
{
var result = await _deviceService.update(input);
return Ok(result);
}
}
}

View File

@ -0,0 +1,30 @@
using langguanApi.Service;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace langguanApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HJ212Controller : ControllerBase
{
private readonly Hj212Service _hj212Service;
public HJ212Controller(Hj212Service hj212Service)
{
_hj212Service = hj212Service;
}
/// <summary>
/// 获取指定设备的历史数据
/// </summary>
/// <param name="mn"></param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Get(string mn)
{
var resul = await _hj212Service.GetViewByDeviceMn(mn);
return Ok(resul);
}
}
}

View File

@ -0,0 +1,45 @@
using langguanApi.Model;
using langguanApi.Service;
using langguanApi.Service.HJ212;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Text;
namespace langguanApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly HomeService _homeService;
public HomeController(HomeService homeService)
{
_homeService = homeService;
}
/// <summary>
/// 首页view
/// </summary>
/// <returns></returns>
[HttpGet("view")]
public async Task<IActionResult> View()
{
return Ok( await _homeService.View() );
}
[HttpGet("test")]
/// <summary>
/// test
/// </summary>
/// <param name="num">数字</param>
/// <param name="key">字符串</param>
/// <returns></returns>
public async Task<IActionResult> test(int num = 1, string key = "")
{
// string rawText = "数据报:##0250QN=20240424224800000;ST=22;CN=2011;PW=123456;MN=LGYC022024690001;Flag=5;CP=&&DataTime=20240424224800;a34001-Rtd=356.2";
//NetPackage netPackage = NetPackage.Parse(rawText, null);
//((NetServer)Server).RaiseReceivedData(this, netPackage, rawText);
return Ok();
}
}
}

21
langguanApi/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base
WORKDIR /app
EXPOSE 80
#FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
#WORKDIR /src
#COPY ["langguanApi/langguanApi.csproj", "langguanApi/"]
#RUN dotnet restore "langguanApi/langguanApi.csproj"
COPY . .
#WORKDIR "/src/langguanApi"
#RUN dotnet build "langguanApi.csproj" -c Release -o /app/build
#
#FROM build AS publish
#RUN dotnet publish "langguanApi.csproj" -c Release -o /app/publish /p:UseAppHost=false
#
#FROM base AS final
#WORKDIR /app
#COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "langguanApi.dll"]

View File

@ -0,0 +1,23 @@
namespace langguanApi.Extensions.AutoDI
{
/// <summary>
/// 注入生命周期
/// </summary>
public enum InjectionType
{
/// <summary>
/// Transient
/// </summary>
Transient,
/// <summary>
/// Scoped
/// </summary>
Scoped,
/// <summary>
/// Singleton
/// </summary>
Singleton
}
}

View File

@ -0,0 +1,43 @@
namespace langguanApi.Extensions.AutoDI
{
[AttributeUsage(AttributeTargets.Class)]
public class ServiceInjectionAttribute : Attribute
{
/// <summary>
///
/// </summary>
public Type InterfaceType { get; set; }
/// <summary>
/// 注入类型
/// </summary>
public InjectionType InjectionType { get; }
/// <summary>
/// 服务注入
/// </summary>
public ServiceInjectionAttribute()
{
InjectionType = InjectionType.Scoped;
}
/// <summary>
/// 服务注入
/// </summary>
/// <param name="injectionType">注入类型</param>
public ServiceInjectionAttribute(InjectionType injectionType)
{
InjectionType = injectionType;
}
/// <summary>
/// 服务注入
/// </summary>
/// <param name="interfaceType">服务的接口类型</param>
/// <param name="injectionType">注入的类型</param>
public ServiceInjectionAttribute(Type interfaceType, InjectionType injectionType)
{
InterfaceType = interfaceType;
InjectionType = injectionType;
}
}
}

View File

@ -0,0 +1,70 @@
using System.Reflection;
namespace langguanApi.Extensions.AutoDI
{
/// <summary>
/// 自动注入
/// </summary>
public static class AutoDIExtensions
{
/// <summary>
///
/// </summary>
/// <param name="serviceCollection"></param>
/// <returns></returns>
public static IServiceCollection ServicesAutoInjectionExtension(this IServiceCollection serviceCollection)
{
var directory = AppDomain.CurrentDomain.BaseDirectory;
var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
.Select(Assembly.LoadFrom)
.SelectMany(a => a.GetTypes());
Injection(serviceCollection, types);
return serviceCollection;
}
/// <summary>
/// 服务自动注入
/// </summary>
/// <param name="serviceCollection">需要自动注入服务的服务集合</param>
/// <param name="selector">应用于每个Assembly的筛选函数</param>
/// <exception cref="ArgumentOutOfRangeException">指定的注入类型不在可注入的范围内</exception>
/// <exception cref="NoImplementationInterfaceException">指定注入的类型未实现任何服务</exception>
/// <exception cref="ArgumentException">输入的参数错误1、注入的类型未实现指定的服务。2、指定的服务不是Interface类型</exception>
/// <returns>自动注入服务后的服务集合</returns>
public static IServiceCollection ServicesAutoInjection(this IServiceCollection serviceCollection, Func<Assembly, bool> selector)
{
var directory = AppDomain.CurrentDomain.BaseDirectory;
var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
.Select(Assembly.LoadFrom)
.Where(selector)
.SelectMany(a => a.GetTypes());
Injection(serviceCollection, types);
return serviceCollection;
}
// 注入逻辑
private static void Injection(IServiceCollection serviceCollection, IEnumerable<Type> types)
{
foreach (var type in types)
{
var attribute = type.GetCustomAttribute<ServiceInjectionAttribute>();
if (attribute == null) continue;
switch (attribute.InjectionType)
{
case InjectionType.Transient:
serviceCollection.AddTransient(type);
break;
case InjectionType.Scoped:
serviceCollection.AddScoped(type);
break;
case InjectionType.Singleton:
serviceCollection.AddSingleton(type);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
}

View File

@ -0,0 +1,21 @@
using langguanApi.Common.Redis;
namespace langguanApi.Extensions
{
public static class RedisExtension
{
/// <summary>
/// add redis service
/// </summary>
/// <param name="services"></param>
/// <param name="redisOptions"></param>
public static void AddRedis(this IServiceCollection services, Action<RedisOptions> redisOptions)
{
services.AddSingleton<RedisHelper>();
if (redisOptions != null)
{
redisOptions.Invoke(RedisOptions.Default);
}
}
}
}

View File

@ -0,0 +1,22 @@
using langguanApi.Service;
namespace langguanApi.Extensions
{
public static class SocketExtension
{
/// <summary>
///
/// </summary>
/// <param name="services"></param>
public static void AddSocketService(this IServiceCollection services)
{
// services.AddSingleton<MQTTService>();
services.AddTransient<HJ212SocketServer>();
services.AddTransient<PingService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
_ = serviceProvider.GetService<HJ212SocketServer>().Start();
serviceProvider.GetService<PingService>().CreatTask();
}
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace langguanApi.Middleware
{
public class CustomerExceptionFilter : IAsyncExceptionFilter
{
/// <summary>
/// 日志
/// </summary>
public ILogger _logger;
/// <summary>
/// 构参
/// </summary>
/// <param name="loggerFactory"></param>
public CustomerExceptionFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<CustomerExceptionFilter>();
}
/// <summary>
/// 重写
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public Task OnExceptionAsync(ExceptionContext context)
{
if (context.ExceptionHandled == false)
{
var json = new { cdoe = -1, msg = context.Exception.Message, data = context.Exception.Data };
context.HttpContext.Response.StatusCode = 400;
context.Result = new JsonResult(json);
}
_logger.LogError($"请求出现异常,地址:{context.HttpContext?.Request?.Path},请求方式:{context.HttpContext.Request.Method},异常信息:{context.Exception.Message}");
//记录异常已经处理
context.ExceptionHandled = true;
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,7 @@
namespace langguanApi.Model
{
public class Alert : BaseModel
{
public string DeviceMn { get; set; }
}
}

View File

@ -0,0 +1,21 @@
namespace langguanApi.Model
{
/// <summary>
/// Api返回结果
/// </summary>
public class ApiResult
{
/// <summary>
/// code=0成功。1失败
/// </summary>
public int code { get; set; } = 0;
/// <summary>
/// 结果
/// </summary>
public object data { get; set; }
/// <summary>
/// 消息
/// </summary>
public string msg { get; set; }
}
}

View File

@ -0,0 +1,40 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace langguanApi.Model
{
/// <summary>
/// base model
/// </summary>
public class BaseModel
{
/// <summary>
/// //标记主键
/// </summary>
[BsonId]
[BsonRepresentation(BsonType.ObjectId)] //参数类型 无需赋值
public string Id { get; set; }
/// <summary>
/// //指明数据库中字段名为CreateDateTime
/// </summary>
[BsonElement(nameof(CreateDateTime))] //指明数据库中字段名为CreateDateTime
public DateTime CreateDateTime { get; set; }
/// <summary>
/// 标记删除
/// </summary>
//[BsonElement(nameof(IsDelete))]
public bool IsDelete { get; set; }=false;
/// <summary>
/// basemodel
/// </summary>
public BaseModel()
{
CreateDateTime = DateTime.Now;
IsDelete = false;
}
}
}

View File

@ -0,0 +1,38 @@
namespace langguanApi.Model
{
/// <summary>
/// 命令编码
/// </summary>
public enum CommandNumber
{
/// <summary>
/// 心跳包
/// </summary>
HeartbeatPackage = 1062,
/// <summary>
/// 工控机向上位机上传分钟数据
/// </summary>
UploadMinuteData = 2051,
/// <summary>
/// 工控机向上位机上传小时数据
/// </summary>
UploadHourlyData = 2061,
/// <summary>
/// 工控机向上位机上传日数据
/// </summary>
UploadDailyData = 2031,
/// <summary>
/// 工控机向上位机上传实时数据
/// </summary>
UploadRealTimeData = 2011,
/// <summary>
/// 上位机向工控机返回应答
/// </summary>
DataResponse = 9014
}
}

View File

@ -0,0 +1,114 @@
using IceCoffee.Common.Extensions;
using System.Reflection;
namespace langguanApi.Model
{
/// <summary>
/// CP指令
/// </summary>
public class CpCommand
{
public ResponseCode ExeRtn { get; set; }
/// <summary>
/// 数据时间信息
/// </summary>
public DateTime DataTime { get; set; }
/// <summary>
/// 污染物信息
/// </summary>
public List<PollutantInfo> PollutantInfo { get; set; }
/// <summary>
/// 解析
/// </summary>
/// <param name="cp"></param>
/// <returns></returns>
public static CpCommand Parse(string cp)
{
var cpCommand = new CpCommand();
cpCommand.PollutantInfo = new List<PollutantInfo>();
cpCommand.DataTime = DateTime.ParseExact(cp.GetMidStr("DataTime=", ";"), "yyyyMMddHHmmss", null);
cp = cp.Substring(24);
foreach (string project in cp.Split(';', StringSplitOptions.RemoveEmptyEntries))
{
var pollutantInfo = new PollutantInfo();
string[] classes = project.Split(',');
foreach (string @class in classes)
{
string[] keyValue = @class.Split('=');
string key = keyValue[0];
string value = keyValue[1];
string[] factorCodeType = key.Split('-');
string factorCode = factorCodeType[0];
string type = factorCodeType[1];
pollutantInfo.FactorCode = (FactorCode)Enum.Parse(typeof(FactorCode), factorCode);
switch (type)
{
case nameof(Model.PollutantInfo.Rtd):
if (string.IsNullOrEmpty(value) == false && decimal.TryParse(value, out decimal rtd))
{
pollutantInfo.Rtd = rtd;
}
break;
case nameof(Model.PollutantInfo.Avg):
if (string.IsNullOrEmpty(value) == false && decimal.TryParse(value, out decimal avg))
{
pollutantInfo.Avg = avg;
}
break;
case nameof(Model.PollutantInfo.Max):
if (string.IsNullOrEmpty(value) == false && decimal.TryParse(value, out decimal max))
{
pollutantInfo.Max = max;
}
break;
case nameof(Model.PollutantInfo.Min):
if (string.IsNullOrEmpty(value) == false && decimal.TryParse(value, out decimal min))
{
pollutantInfo.Min = min;
}
break;
case nameof(Model.PollutantInfo.Cou):
if (string.IsNullOrEmpty(value) == false && decimal.TryParse(value, out decimal cou))
{
pollutantInfo.Cou = cou;
}
break;
case nameof(Model.PollutantInfo.Flag):
pollutantInfo.Flag = (InstrumentationDataFlag)Enum.Parse(typeof(InstrumentationDataFlag), value);
break;
default:
throw new Exception("无效的CP指令字段名");
}
}
cpCommand.PollutantInfo.Add(pollutantInfo);
}
return cpCommand;
//}
//catch (Exception ex)
//{
// Console.WriteLine($"Error in CpCommand.Parse:{ex.Message}");
// throw new Exception("Error in CpCommand.Parse", ex);
//}
}
/// <summary>
/// 序列化
/// </summary>
/// <returns></returns>
public string Serialize()
{
return "ExeRtn=" + (int)ExeRtn;
}
}
}

View File

@ -0,0 +1,152 @@
using IceCoffee.Common.Extensions;
using System.Text;
namespace langguanApi.Model
{
/// <summary>
/// 数据段
/// </summary>
public class DataSegment
{
/// <summary>
/// 默认应答系统编码
/// </summary>
public const string ResponseST = "91";
/// <summary>
/// 请求编号
/// </summary>
/// <remarks>
/// yyyyMMddHHmmssZZZ 取当前系统时间, 精确到毫秒值, 用来唯一标识一次命令交互
/// </remarks>
public string QN { get; set; }
/// <summary>
/// 系统编号
/// </summary>
public string ST { get; set; }
/// <summary>
/// 命令编码
/// <para>详见附录 2</para>
/// </summary>
public CommandNumber CN { get; set; }
/// <summary>
/// 访问密码
/// <para>对接时提供给各个对接站点</para>
/// </summary>
public string PW { get; set; }
/// <summary>
/// 设备唯一标识
/// <para>对接时提供给各个对接站点</para>
/// </summary>
public string MN { get; set; }
/// <summary>
/// 拆分包及应答标志
/// </summary>
public PackageFlag PackageFlag { get; set; }
/// <summary>
/// 总包数
/// <para>PNUM 指示本次通讯中总共包含的包数,注:不分包时可以没有本字段,与标志位有关</para>
/// </summary>
public int PNUM { get; set; }
/// <summary>
/// 包号
/// <para>PNO 指示当前数据包的包号,注: 不分包时可以没有本字段,与标志位有关</para>
/// </summary>
public int PNO { get; set; }
/// <summary>
/// 指令
/// <para>CP=&&数据区&&( 详见表 5 )</para>
/// </summary>
public CpCommand CpCommand { get; set; }
/// <summary>
/// 解析
/// </summary>
/// <param name="data"></param>
/// <param name="unpackCacheFunc"></param>
/// <returns></returns>
public static DataSegment Parse(string data, Func<StringBuilder> unpackCacheFunc)
{
DataSegment dataSegment = new DataSegment();
try
{
int outEnd;
dataSegment.QN = data.GetMidStr("QN=", ";", out outEnd);
if (outEnd < 0)
{
outEnd = 0;
}
dataSegment.ST = data.GetMidStr("ST=", ";", out outEnd, outEnd);
dataSegment.CN = (CommandNumber)int.Parse(data.GetMidStr("CN=", ";", out outEnd, outEnd));
dataSegment.PW = data.GetMidStr("PW=", ";", out outEnd, outEnd);
dataSegment.MN = data.GetMidStr("MN=", ";", out outEnd, outEnd);
string packageFlag = data.GetMidStr("Flag=", ";", out outEnd, outEnd);
if (string.IsNullOrEmpty(packageFlag) || int.TryParse(packageFlag, out _) == false || outEnd < 0)
{
outEnd = 0;
}
else
{
dataSegment.PackageFlag = PackageFlag.Parse(packageFlag);
}
if (dataSegment.PackageFlag != null && dataSegment.PackageFlag.D == 1)
{
// 分包
dataSegment.PNUM = int.Parse(data.GetMidStr("PNUM=", ";", out outEnd, outEnd));
dataSegment.PNO = int.Parse(data.GetMidStr("PNO=", ";", out outEnd, outEnd));
string cp = data.GetMidStr("CP=&&", "&&", out outEnd, outEnd);
var cache = unpackCacheFunc.Invoke();
if (dataSegment.PNO == 1)// 第一个包
{
cache.Append(cp);
}
else if (dataSegment.PNUM == dataSegment.PNO)// 最后一个包
{
cache.Append(cp.Substring(23));
dataSegment.CpCommand = CpCommand.Parse(cache.ToString());
cache.Clear();
}
else// 中间的包
{
cache.Append(cp.Substring(23));// 23 - DataTime=20170920100000; 留分号
}
}
else
{
string cp = data.GetMidStr("CP=&&", "&&", out outEnd, outEnd);
// 过滤心跳包
dataSegment.CpCommand = dataSegment.CN == CommandNumber.HeartbeatPackage ? new CpCommand() : CpCommand.Parse(cp);
}
return dataSegment;
}
catch (Exception ex)
{
Console.WriteLine($"Error in DataSegment.Parse:{ex.Message}");
}
return dataSegment;
}
/// <summary>
/// 序列化
/// </summary>
/// <returns></returns>
public string Serialize()
{
return $"QN={QN};ST={ST};CN={(int)CN};PW={PW};MN={MN};Flag={PackageFlag.Serialize()};CP=&&{CpCommand.Serialize()}&&";
}
}
}

View File

@ -0,0 +1,16 @@
namespace langguanApi.Model
{
/// <summary>
/// 设备信息
/// </summary>
public class Device : BaseModel
{
public string deviceMN { get; set; }
public string Name { get; set; }
public string Ip { get; set; }
public double lng { get; set; }
public double lat { get; set; }
public string desricption { get; set; }
public int state { get; set; }
}
}

View File

@ -0,0 +1,13 @@
namespace langguanApi.Model.Dto
{
public class DeviceDto
{
public string deviceMN { get; set; }
public string Name { get; set; }
public string Ip { get; set; }
public double lng { get; set; }
public double lat { get; set; }
public string desricption { get; set; }
public int state { get; set; }
}
}

View File

@ -0,0 +1,143 @@
using System.Text;
namespace langguanApi.Model.Dto
{
/// <summary>
/// HJ212_2017
/// </summary>
public class HJ212_2017
{
/// <summary>
/// 数据帧头
/// </summary>
public string header { get; set; }
/// <summary>
/// 数据长度
/// </summary>
public string data_length { get; set; }
/// <summary>
/// 数据头
/// </summary>
public Dictionary<string, string> DATA_HEAD { get; set; }
/// <summary>
///
/// </summary>
public Dictionary<string, string> CP { get; set; }
/// <summary>
/// CRC校验
/// </summary>
public string CRC { get; set; }
/// <summary>
///
/// </summary>
/// <param name="Text"></param>
/// <returns></returns>
public bool DecodeData(string Text)
{
try
{
if (Text.Length < 12 || !Text.StartsWith("##"))
{
Console.WriteLine("不是HJ212协议的报文!");
return false;
}
Console.WriteLine($"开始解码数据:");
Text = Text.ToUpper().Replace(";CP=", "").Replace(" ", "");//有些厂家协议不很标准,有的大小写不一致,此处强制转大写字母
header = Text.Substring(0, 2);
data_length = Text.Substring(2, 4);
string[] data_0 = Text.Substring(6, Text.Length - 6).Split(new char[] { '&', '&' }, StringSplitOptions.RemoveEmptyEntries);
string[] data_1 = data_0[0].Split(new char[] { ';' });
DATA_HEAD = new Dictionary<string, string>();
for (int h = 0; h < data_1.Length; h++)
{
string[] d_1 = data_1[h].Split(new char[] { '=' });
DATA_HEAD.Add(d_1[0], d_1[1]);
}
string[] data_2 = data_0[1].Split(new char[] { ';' });
CP = new Dictionary<string, string>();
for (int i = 0; i < data_2.Length; i++)
{
string[] d_6 = data_2[i].Split(new char[] { ',' });
for (int j = 0; j < d_6.Length; j++)
{
string[] d_7 = d_6[j].Split(new char[] { '=' });
CP.Add(d_7[0].Replace("-RTD", ""), d_7[1]);
}
}
CRC = data_0[2];
return true;
}
catch (Exception ex)
{
//数据接收不完整
Console.WriteLine($" 解码失败err{ex},数据有问题," + Text);
//throw;
return false;
}
}
/// <summary>
/// 判断数据是否通过校验
/// </summary>
/// <param name="Text">原始数据</param>
/// <returns>是否通过</returns>
public bool Crc16(string Text)
{
try
{
string CRC = Text.Substring(Text.Length - 4, 4);
Text = Text.Substring(Text.IndexOf("QN"));
Text = Text.Substring(0, Text.Length - 4);
byte[] bytes = Encoding.ASCII.GetBytes(Text);
int crcRegister = 0xFFFF;
for (int i = 0; i < bytes.Length; i++)
{
crcRegister = (crcRegister >> 8) ^ bytes[i];
for (int j = 0; j < 8; j++)
{
int check = crcRegister & 0x0001;
crcRegister >>= 1;
if (check == 0x0001)
{
crcRegister ^= 0xA001;
}
}
}
string result = string.Format("{0:X}", crcRegister);//转十六进制
for (int i = result.Length; i < 4; i++)//补足 4 位
{
result = "0" + result;
}
//LogApi.WriteLog("计算校验码:" + result);
if (result == CRC)
{
return true;
}
else
{
Console.WriteLine("校验码有误," + CRC);
Console.WriteLine("待校验数据:" + Text);
Console.WriteLine("计算校验码:" + result);
//LogApi.WriteLog("校验码有误:" + CRC);
//LogApi.WriteLog("待校验数据:" + Text);
//LogApi.WriteLog("计算校验码:" + result);
return false;
}
}
catch (Exception)
{
Console.WriteLine("数据校验:数据有问题:" + Text);
//数据接收不完整
return false;
//throw;
}
}
}
}

View File

@ -0,0 +1,422 @@
namespace langguanApi.Model
{
/// <summary>
/// 污染物因子编码
/// </summary>
public enum FactorCode
{
#region VOCs 线
a24901,
a24904,
a24905,
a24042,
a25002,
a24036,
a24908,
a24909,
a24910,
a24012,
a24043,
a24084,
a24911,
a25003,
a24912,
a24913,
a24070,
a25004,
a25008,
a25038,
a25006,
a24044,
a25034,
a25033,
a25902,
a25014,
a25021,
a25901,
a25019,
a24068,
a25020,
a25903,
a25904,
a24914,
a24915,
a24001,
a24045,
a24002,
a24053,
a24038,
a24037,
a24079,
a24064,
a24919,
a24063,
a24902,
a24041,
a24039,
a24077,
a24074,
a24076,
a24907,
a24903,
a24011,
a24061,
a24906,
a31002,
a31005,
#region
a05002,
a99999,
a24088,
#endregion
a24072,
a05009,
a05014,
a24099,
a24058,
a24046,
a24078,
a24008,
a24015,
a24916,
a31004,
a31003,
a24047,
a05013,
a31024,
a99009,
a24003,
a28006,
a31015,
a24016,
a31900,
a24111,
a24004,
a24018,
a24005,
a24017,
a24049,
a24917,
a24027,
a31010,
a31026,
a24007,
a24112,
a24054,
a24019,
a24050,
a31009,
a24034,
a25010,
a24009,
a24020,
a25012,
a25011,
a30003,
a30008,
a99051,
a29026,
a29017,
a31025,
a24110,
a25072,
a29015,
a31030,
a31027,
a24006,
a25013,
a25068,
a25015,
a24113,
a25059,
a31001,
a31016,
a31018,
a31020,
a24102,
a30001,
a25905,
a24918,
a28900,
a28010,
a30002,
a30023,
a28001,
a24059,
a24944,
#endregion
#region 线
a01030,
a01004,
a01007,
a01008,
a06001,
a01001,
#endregion
#region
a21003,
a21004,
a21002,
a21029,
#endregion
#region
a34004,
a34002,
a21026,
// a21004,
a21005,
#endregion
#region 线
a06010,
a06011,
a06013,
a06009,
a06012,
a06005,
a06006,
a06019,
a06008,
a21001,
a20109,
// a21026,
a20110,
a21024,
// a21004,
a06007,
a06015,
a06018,
a06021,
a06017,
a06022,
a06023,
a06024,
a06025,
a06026,
a06027,
a06028,
a06029,
a06030,
a06031,
a06032,
a06033,
a34007,
a34006,
a34047,
a34048,
a34049,
a20044,
a20072,
a20058,
a20033,
a20026,
a20104,
a20041,
a20064,
a20111,
a20055,
a20095,
a20004,
a20092,
a20101,
a20012,
a20007,
a20029,
a20068,
a20038,
a20061,
a20112,
a20113,
a20089,
a20114,
a20115,
a20086,
a20116,
a20117,
a20118,
a20119,
a20079,
a20120,
a20002,
a20121,
a20075,
a20052,
a20122,
a20123,
a21012,
a20124,
a20107,
a20125,
a20126,
a20127,
a20128,
a20129,
a20098,
a20020,
a01031,
a01032,
a01029,
a01033,
a01034,
a01035,
a01036,
a01037,
// a01001,
// a01004,
a01038,
a01039,
// a06001,
a01022,
a01023,
// a34002,
// a34004,
a01024,
a19006,
a01025,
a01026,
a01020,
a01027,
a01028,
// a01029,
// a01022,
// a01023,
a05024,
a19999,
a19998,
a19997,
a19996,
a19995,
a19994,
a19993,
#endregion
#region HJ 524-2009
a00000,
//a01001,
a01002,
a01006,
//a01007,
//a01008,
a01010,
a01011,
a01012,
a01013,
a01014,
a01015,
a01016,
a01017,
a01901,
a01902,
a05001,
//a05002,
a05008,
//a05009,
//a05013,
a19001,
//a20007,
a20016,
a20025,
//a20026,
a20043,
//a20044,
a20057,
//a20058,
a20063,
a20091,
//a21001,
//a21002,
//a21003,
//a21004,
//a21005,
a21017,
a21018,
a21022,
//a21024,
//a21026,
a21028,
a23001,
//a24003,
//a24004,
//a24005,
//a24006,
//a24007,
//a24008,
//a24009,
//a24015,
//a24016,
//a24017,
//a24018,
//a24019,
//a24020,
//a24027,
//a24034,
//a24036,
//a24042,
//a24043,
//a24046,
//a24047,
//a24049,
//a24050,
//a24053,
//a24054,
//a24072,
//a24078,
a24087,
//a24088,
//a24099,
//a24110,
//a24111,
//a24112,
//a24113,
//a25002,
//a25003,
//a25004,
a25005,
//a25006,
a25007,
//a25008,
//a25010,
//a25011,
//a25012,
//a25013,
//a25014,
//a25015,
//a25019,
//a25020,
//a25021,
a25023,
//a25038,
a25044,
//a25072,
a26001,
//a29017,
//a29026,
//a30001,
//a30008,
a30022,
//a31001,
//a31002,
//a31024,
//a31025,
//a31030,
a34001,
//a34002,
//a34004,
a34005,
a34011,
a34013,
a34017,
a34038,
a34039,
a34040,
a99010,
a99049,
//a99051,
#endregion
}
}

View File

@ -0,0 +1,49 @@
using Swashbuckle.AspNetCore.SwaggerUI;
using System.ComponentModel;
using System.Reflection.Metadata;
namespace langguanApi.Model
{
public class HJ212 : BaseModel
{
/// <summary>
/// 设备ID
/// </summary>
public string deviceMN { get; set; }
/// <summary>
/// PM2.5浓度
/// </summary>
public double a34004 { get; set; }
/// <summary>
/// PM10浓度
/// </summary>
public double a34002 { get; set; }
/// <summary>
/// TSP浓度
/// </summary>
public double a34001 { get; set; }
/// <summary>
/// 温度
/// </summary>
public double a01001 { get; set; }
/// <summary>
/// 湿度
/// </summary>
public double a01002 { get; set; }
/// <summary>
/// 大气压
/// </summary>
public double a01006 { get; set; }
/// <summary>
/// 风速
/// </summary>
public double a01007 { get; set; }
/// <summary>
/// 风向
/// </summary>
public double a01008 { get; set; }
public double lat { get; set; }
public double lng { get; set; }
}
}

View File

@ -0,0 +1,64 @@
namespace langguanApi.Model
{
/// <summary>
/// 检测仪器数据标记
/// </summary>
public enum InstrumentationDataFlag
{
/// <summary>
/// 正常(有效)
/// <para>在线监控(监测)仪器仪表工作正常</para>
/// </summary>
N,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表停运</para>
/// </summary>
F,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表处于维护期间产生的数据 </para>
/// </summary>
M,
/// <summary>
/// 有效
/// <para>手工输入的设定值</para>
/// </summary>
S,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表故障</para>
/// </summary>
D,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表处于校准状态</para>
/// </summary>
C,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表采样数值超过测量上限</para>
/// </summary>
T,
/// <summary>
/// 无效
/// <para>在线监控(监测)仪器仪表与数采仪通讯异常</para>
/// </summary>
B,
/// <summary>
/// 无效(有效数据不足)
/// </summary>
/// <remarks>
/// 按照5分钟、1小时均值计算要求所获取的有效数据个数不足
/// </remarks>
H
}
}

View File

@ -0,0 +1,119 @@
using System.Text;
namespace langguanApi.Model
{
/// <summary>
/// 通讯包
/// </summary>
public class NetPackage
{
/// <summary>
/// 默认头
/// </summary>
public const string FixedHead = "##";
/// <summary>
/// 默认尾
/// </summary>
public const string FixedTail = "\r\n";
/// <summary>
/// 包头
/// </summary>
public string Head { get; set; }
/// <summary>
/// 数据段长度
/// </summary>
public int DataSegmentLength { get; set; }
/// <summary>
/// 数据段
/// </summary>
public DataSegment DataSegment { get; set; }
/// <summary>
/// CRC校验码
/// </summary>
public string CrcCode { get; set; }
/// <summary>
/// 包尾
/// </summary>
public string Tail { get; set; }
/// <summary>
/// CRC16校验
/// </summary>
/// <param name="arg">需要校验的字符串</param>
/// <returns>CRC16 校验码</returns>
private static string CRC16(string arg)
{
char[] puchMsg = arg.ToCharArray();
uint i, j, crc_reg, check;
crc_reg = 0xFFFF;
for (i = 0; i < puchMsg.Length; i++)
{
crc_reg = (crc_reg >> 8) ^ puchMsg[i];
for (j = 0; j < 8; j++)
{
check = crc_reg & 0x0001;
crc_reg >>= 1;
if (check == 0x0001)
{
crc_reg ^= 0xA001;
}
}
}
return crc_reg.ToString("X2").PadLeft(4, '0');
}
/// <summary>
/// 解析
/// </summary>
/// <param name="line"></param>
/// <param name="unpackCacheFunc"></param>
/// <returns></returns>
public static NetPackage Parse(string line, Func<StringBuilder> unpackCacheFunc = null)
{
try
{
NetPackage netPackage = new NetPackage();
netPackage.Head = line.Substring(0, 2);
netPackage.DataSegmentLength = int.Parse(line.Substring(2, 4));
string dataSegment = line.Substring(6, netPackage.DataSegmentLength);
string crcCode = line.Substring(6 + netPackage.DataSegmentLength, 4);
string calcCrcCode = CRC16(dataSegment);
if (crcCode != calcCrcCode)
{
throw new Exception("CRC校验失败 " + line);
}
netPackage.DataSegment = DataSegment.Parse(dataSegment, unpackCacheFunc);
netPackage.CrcCode = crcCode;
netPackage.Tail = line.Substring(10 + netPackage.DataSegmentLength);
return netPackage;
}
catch (Exception ex)
{
throw new Exception("Error in NetPackage.Parse", ex);
}
}
/// <summary>
/// 序列化
/// </summary>
/// <returns></returns>
public string Serialize()
{
string dataSegment = DataSegment.Serialize();
DataSegmentLength = dataSegment.Length;
CrcCode = CRC16(dataSegment);
return $"{Head}{DataSegmentLength.ToString().PadLeft(4, '0')}{dataSegment}{CrcCode}{Tail}";
}
}
}

View File

@ -0,0 +1,117 @@
namespace langguanApi.Model
{
/// <summary>
/// 拆分包及应答标志
/// </summary>
public class PackageFlag
{
public byte V5 { get; set; }
public byte V4 { get; set; }
public byte V3 { get; set; }
public byte V2 { get; set; }
public byte V1 { get; set; }
public byte V0 { get; set; }
/// <summary>
/// 命令是否应答1应答0不应答
/// </summary>
public byte A { get; set; }
/// <summary>
/// 是否有数据包序号1 - 数据包中包含包号和总包数两部分0 - 数据包中不包含包号和总包数两部分
/// </summary>
public byte D { get; set; }
/// <summary>
/// 标准版本号
/// <para>000000 表示标准 HJ/T212-2005</para>
/// <para>000001 表示本次标准修订版本号</para>
/// </summary>
public string Version
{
get
{
return $"{V5}{V4}{V3}{V2}{V1}{V0}";
}
}
/// <summary>
/// 解析
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static PackageFlag Parse(string data)
{
byte flag = byte.Parse(data);
return new PackageFlag()
{
V5 = GetBit(flag, 7),
V4 = GetBit(flag, 6),
V3 = GetBit(flag, 5),
V2 = GetBit(flag, 4),
V1 = GetBit(flag, 3),
V0 = GetBit(flag, 2),
D = GetBit(flag, 1),
A = GetBit(flag, 0)
};
}
/// <summary>
/// 序列化
/// </summary>
/// <returns></returns>
public string Serialize()
{
return Convert.ToInt32($"{V5}{V4}{V3}{V2}{V1}{V0}{D}{A}", 2).ToString();
}
/// <summary>
/// 获取取第index位
/// </summary>
/// <remarks>
/// index从0开始
/// </remarks>
/// <param name="b"></param>
/// <param name="index"></param>
/// <returns></returns>
private static byte GetBit(byte b, int index)
{
// (byte)((from & (0xFF << (index * 8))) >> (index * 8))
return ((b & (1 << index)) > 0) ? (byte)1 : (byte)0;
}
/// <summary>
/// 将第index位设为1
/// </summary>
/// <remarks>
/// index从0开始
/// </remarks>
/// <param name="b"></param>
/// <param name="index"></param>
/// <returns></returns>
private static byte SetBit(byte b, int index) { return (byte)(b | (1 << index)); }
/// <summary>
/// 将第index位设为0
/// </summary>
/// <remarks>
/// index从0开始
/// </remarks>
/// <param name="b"></param>
/// <param name="index"></param>
/// <returns></returns>
private static byte ClearBit(byte b, int index) { return (byte)(b & (byte.MaxValue - (1 << index))); }
/// <summary>
/// 将第index位取反
/// </summary>
/// <remarks>
/// index从0开始
/// </remarks>
/// <param name="b"></param>
/// <param name="index"></param>
/// <returns></returns>
private static byte ReverseBit(byte b, int index) { return (byte)(b ^ (byte)(1 << index)); }
}
}

View File

@ -0,0 +1,63 @@
namespace langguanApi.Model
{
/// <summary>
/// 污染物信息
/// </summary>
public class PollutantInfo
{
/// <summary>
/// 约定的无效值
/// </summary>
public const decimal InvaildValue = -9999;
/// <summary>
/// 污染物因子编码
/// </summary>
public FactorCode FactorCode { get; set; }
/// <summary>
/// 污染物实时采样数据
/// </summary>
/// <remarks>
/// 默认值为约定的无效值 <see cref="InvaildValue"/>
/// </remarks>
public decimal Rtd { get; set; } = InvaildValue;
/// <summary>
/// 污染物指定时问内平均值
/// </summary>
/// <remarks>
/// 默认值为约定的无效值 <see cref="InvaildValue"/>
/// </remarks>
public decimal Avg { get; set; } = InvaildValue;
/// <summary>
/// 污染物指定时问内最大值
/// </summary>
/// <remarks>
/// 默认值为约定的无效值 <see cref="InvaildValue"/>
/// </remarks>
public decimal Max { get; set; } = InvaildValue;
/// <summary>
/// 污染物指定时问内最小值
/// </summary>
/// <remarks>
/// 默认值为约定的无效值 <see cref="InvaildValue"/>
/// </remarks>
public decimal Min { get; set; } = InvaildValue;
/// <summary>
/// 污染物指定时问内累计值
/// </summary>
/// <remarks>
/// 默认值为约定的无效值 <see cref="InvaildValue"/>
/// </remarks>
public decimal Cou { get; set; } = InvaildValue;
/// <summary>
/// 检测仪器数据标记
/// </summary>
public InstrumentationDataFlag Flag { get; set; }
}
}

View File

@ -0,0 +1,13 @@
namespace langguanApi.Model
{
public class ReqPaing
{
public int pageSize { get; set; } = 10;
public int current { get; set; } = 1;
}
public class reqpage : ReqPaing
{
public string key { get; set;
}
}
}

View File

@ -0,0 +1,48 @@
namespace langguanApi.Model
{
/// <summary>
/// 回应代码集
/// </summary>
public enum ResponseCode
{
/// <summary>
/// 执行成功
/// </summary>
ExecSucceeded = 1,
/// <summary>
/// 执行失败,但不知道原因
/// </summary>
ExecutionFailed_DoNotKnowReason = 2,
/// <summary>
/// 执行失败,命令请求条件错误
/// </summary>
ExecutionFailed_InvalidCommand = 3,
/// <summary>
/// 通讯超时
/// </summary>
CommunicationTimeout = 4,
/// <summary>
/// 系统繁忙不能执行
/// </summary>
SystemBusy = 5,
/// <summary>
/// 系统时间异常
/// </summary>
InvalidSystemTime = 6,
/// <summary>
/// 没有数据
/// </summary>
NoneData = 100,
/// <summary>
/// 心跳包
/// </summary>
HeartbeatPackage = 300
}
}

View File

@ -0,0 +1,15 @@
namespace langguanApi.Model
{
public class columnView
{
/// <summary>
///
/// </summary>
public string hour { get; set; }
/// <summary>
/// a34004=PM2.5浓度,a34002=PM10,a34001=tsp浓度
/// </summary>
public string type { get; set; }
public double value { get; set; }
}
}

94
langguanApi/Program.cs Normal file
View File

@ -0,0 +1,94 @@
using langguanApi.Common.Redis;
using langguanApi.Extensions;
using langguanApi.Extensions.AutoDI;
using langguanApi.Middleware;
using Microsoft.Extensions.Configuration;
using Microsoft.OpenApi.Models;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers(options =>
{
options.Filters.Add<CustomerExceptionFilter>();
}).AddNewtonsoftJson(option =>
{
option.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
option.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
}).AddJsonOptions(option =>
{
option.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
//swagger
builder.Services.AddSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo()
{
Title = "Title",
Version = "v1",
Description = "Description",
});
var path = Path.Combine(AppContext.BaseDirectory, "langguanApi.xml");
options.IncludeXmlComments(path, true);
options.OrderActionsBy(_ => _.RelativePath);
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//redis
var redisoptions = builder.Configuration.GetSection("Redis").Get<RedisOptions>();
if (redisoptions != null)
{
builder.Services.AddRedis(options =>
{
options.Port = redisoptions.Port;
options.Server = redisoptions.Server;
options.Index = redisoptions.Index;
options.Password = redisoptions.Password;
options.Key = redisoptions.Key;
});
}
//×Ô¶¯×¢Èë
builder.Services.ServicesAutoInjectionExtension();
builder.Services.AddSocketService();
//cross domain
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyOrigin();
builder.AllowAnyMethod();
builder.AllowAnyHeader();
});
});
var app = builder.Build();
ServiceLocator.Instance = app.Services;
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseSwagger();
app.UseSwaggerUI();
app.UseCors("CorsPolicy");
//app.UseAuthorization();
app.MapControllers();
app.Run();
/// <summary>
/// ÔÝ´æ·þÎñ
/// </summary>
public static class ServiceLocator
{
public static IServiceProvider Instance { get; set; }
}

View File

@ -0,0 +1,40 @@
{
"profiles": {
"langguanApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5254"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "http://+:80"
},
"publishAllPorts": true
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:9471",
"sslPort": 0
}
}
}

View File

@ -0,0 +1,43 @@
using langguanApi.Extensions.AutoDI;
using langguanApi.Model;
using langguanApi.Model.Dto;
using System.Linq.Expressions;
namespace langguanApi.Service
{
[ServiceInjection(InjectionType.Transient)]
public class AlertService : BaseService<Alert>
{
public AlertService(IConfiguration config) : base(config, nameof(Device))
{
}
/// <summary>
/// 新加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<ApiResult> Add(Alert input)
{
if (input != null)
{
await base.CreateAsync(input);
return new ApiResult { code = 0, msg = "" };
}
return new ApiResult { code = -1, msg = "" }; ;
}
/// <summary>
/// 分页取数据
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<object> GetPage(reqpage input)
{
Expression<Func<Alert, bool>> exp = filter => filter.DeviceMn.Contains(input.key) && filter.IsDelete == false;
return await base.GetPager(new ReqPaing()
{
pageSize = input.pageSize,
current = input.current
}, exp);
}
}
}

View File

@ -0,0 +1,201 @@
using langguanApi.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.RazorPages;
using MongoDB.Driver;
using System.Linq.Expressions;
namespace langguanApi.Service
{
public class BaseService<T> where T : BaseModel
{
private readonly IMongoCollection<T> _collection; //数据表操作对象
/// <summary>
/// 构造
/// </summary>
/// <param name="config"></param>
/// <param name="tableName"></param>
public BaseService(IConfiguration config, string tableName)
{
var client = new MongoClient(config.GetSection("ConnectionStrings:MongoDBConn").Value); //获取链接字符串
var database = client.GetDatabase(config.GetSection("ConnectionStrings:DBName").Value);
_collection = database.GetCollection<T>(tableName);
if (_collection == null)
{
database.CreateCollection(tableName);
}
}
/// <summary>
/// 获取所有
/// </summary>
/// <returns></returns>
public List<T> Get()
{
return _collection.Find(T => true).ToList();
}
/// <summary>
/// 获取单个
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public T Get(string id)
{
return _collection.Find<T>(T => T.Id == id).FirstOrDefault();
}
/// <summary>
/// 创建
/// </summary>
/// <param name="T"></param>
/// <returns></returns>
public T Create(T T)
{
_collection.InsertOne(T);
return T;
}
/// <summary>
/// 更新
/// </summary>
/// <param name="id"></param>
/// <param name="TIn"></param>
public void Update(string id, T TIn)
{
_collection.ReplaceOne(T => T.Id == id, TIn);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="TIn"></param>
public void Remove(T TIn)
{
_collection.DeleteOne(T => T.Id == TIn.Id);
}
/// <summary>
/// 根据id删除
/// </summary>
/// <param name="id"></param>
public void Remove(string id)
{
_collection.DeleteOne(T => T.Id == id);
}
#region
/// <summary>
/// 取列表
/// </summary>
/// <returns></returns>
public async Task<List<T>> GetAsync()
{
return await _collection.Find(T => true).ToListAsync();
}
/// <summary>
/// 取单条
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<T> GetAsync(string id)
{
return await _collection.Find<T>(T => T.Id == id).FirstOrDefaultAsync();
}
/// <summary>
/// 新增
/// </summary>
/// <param name="T"></param>
/// <returns></returns>
public async Task<T> CreateAsync(T T)
{
await _collection.InsertOneAsync(T);
return T;
}
/// <summary>
/// 新增
/// </summary>
/// <param name="T"></param>
/// <returns></returns>
public async Task CreateManyAsync(IEnumerable<T> T)
{
await _collection.InsertManyAsync(T);
}
/// <summary>
/// 更新
/// </summary>
/// <param name="id"></param>
/// <param name="TIn"></param>
/// <returns></returns>
public async Task UpdateAsync(string id, T TIn)
{
await _collection.ReplaceOneAsync(T => T.Id == id, TIn);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task RemoveAsync(string id)
{
await _collection.DeleteOneAsync(T => T.Id == id);
}
#endregion
/// <summary>
/// 表达式取数据
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public Task<IQueryable<T>> GetListWithExp(Expression<Func<T, bool>> expression)
{
// var temp = _collection.AsQueryable<T>().Where(expression).ToList();
return Task.FromResult(_collection.AsQueryable<T>().Where(expression));
}
/// <summary>
/// filter查找
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public async Task<List<T>> FindListByFilter(Expression<Func<T, bool>> filter)
{
FilterDefinition<T> filters = Builders<T>.Filter.Where(filter);
return await _collection.Find(filters).ToListAsync();
}
/// <summary>
/// filterdefinition
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public async Task<List<T>> FindListyFilter(FilterDefinition<T> filter)
{
return await _collection.Find(filter).ToListAsync();
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public Task<bool> Exist(Expression<Func<T, bool>> expression)
{
var result = _collection.AsQueryable().Where(expression).Any();
return Task.FromResult(result);
}
/// <summary>
/// 分页取数据
/// </summary>
/// <param name="req"></param>
/// <param name="exp"></param>
/// <returns></returns>
public async Task<ApiResult> GetPager(ReqPaing req, Expression<Func<T, bool>> exp = null)
{
req.pageSize = req.pageSize == 0 ? 10 : req.pageSize;
var query = await GetListWithExp(exp);
var total = query.Count();
var items = query.OrderByDescending(s => s.CreateDateTime)
.Skip(req.pageSize * (req.current - 1)).Take(req.pageSize).ToList();
return new ApiResult()
{
code = 0,
data = new { total, items }
};
}
}
}

View File

@ -0,0 +1,99 @@
using langguanApi.Extensions.AutoDI;
using langguanApi.Model;
using langguanApi.Model.Dto;
using Mapster;
using System.Linq.Expressions;
namespace langguanApi.Service
{
[ServiceInjection(InjectionType.Scoped)]
public class DeviceService : BaseService<Device>
{
public DeviceService(IConfiguration config) : base(config, nameof(Device))
{
}
/// <summary>
/// 新加
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<ApiResult> Add(DeviceDto input)
{
if (await Exist(input))
{
return new ApiResult { code = 1, msg = $"已经存在名称为:{input.Name}" };
}
var entity = input.Adapt<Device>();
if (entity != null)
{
await base.CreateAsync(entity);
return new ApiResult { code = 0, msg = "" };
}
return new ApiResult { code = -1, msg = "" }; ;
}
/// <summary>
/// 是否存在
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<bool> Exist(DeviceDto input)
{
var entity = input.Adapt<Device>();
Expression<Func<Device, bool>> exp = filter => filter.deviceMN == entity.deviceMN;
return await base.Exist(exp);
}
/// <summary>
/// 更新
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<ApiResult> update(DeviceDto input)
{
var entity = input.Adapt<Device>();
await base.UpdateAsync(entity.Id, entity);
return new ApiResult { code = 0, msg = "" };
}
/// <summary>
/// remove
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<ApiResult> remove(IEnumerable<string> ids)
{
if (ids.Any())
{
foreach (var item in ids)
{
var entity = await base.GetAsync(item);
entity.IsDelete = true;
await base.UpdateAsync(entity.Id, entity);
}
return new ApiResult { code = 0, msg = "" };
}
return new ApiResult { code = -1, msg = "" };
}
// 通过devicemn获取设备信息
public async Task<Device> GetByDeviceMN(string deviceMN)
{
Expression<Func<Device, bool>> exp = filter => filter.deviceMN == deviceMN && filter.IsDelete == false;
return (await base.GetListWithExp(exp)).FirstOrDefault();
}
/// <summary>
/// 分页取数据
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<object> GetPage(reqpage input)
{
Expression<Func<Device, bool>> exp = filter => filter.Name.Contains(input.key) && filter.IsDelete == false;
return await base.GetPager(new ReqPaing()
{
pageSize = input.pageSize,
current = input.current
}, exp);
}
}
}

View File

@ -0,0 +1,58 @@
using IceCoffee.FastSocket.Tcp;
using langguanApi.Model;
using System.Net;
namespace langguanApi.Service.HJ212
{
public class NetServer : TcpServer
{
/// <summary>
/// 收到数据事件
/// </summary>
public event Action<NetSession, NetPackage, string> ReceivedData;
/// <summary>
/// 发送数据事件
/// </summary>
public event Action<NetSession, NetPackage, string> SendData;
public NetServer(IPAddress address, int port, TcpServerOptions options = null)
: base(address, port, options ?? new TcpServerOptions() { KeepAlive = true })
{
}
public NetServer(string address, int port, TcpServerOptions options = null)
: base(address, port, options ?? new TcpServerOptions() { KeepAlive = true })
{
}
public NetServer(IPEndPoint endPoint, TcpServerOptions options = null)
: base(endPoint, options ?? new TcpServerOptions() { KeepAlive = true })
{
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected override TcpSession CreateSession()
{
return new NetSession(this);
}
/// <summary>
/// 引发收到数据事件
/// </summary>
internal void RaiseReceivedData(NetSession netSession, NetPackage netPackage, string rawText)
{
ReceivedData?.Invoke(netSession, netPackage, rawText);
}
/// <summary>
/// 引发发送数据事件
/// </summary>
/// <param name="netSession"></param>
/// <param name="netPackage"></param>
/// <param name="rawText"></param>
internal void RaiseSendData(NetSession netSession, NetPackage netPackage, string rawText)
{
SendData?.Invoke(netSession, netPackage, rawText);
}
}
}

View File

@ -0,0 +1,87 @@
using IceCoffee.FastSocket.Tcp;
using langguanApi.Model;
using System.Text;
namespace langguanApi.Service.HJ212
{
public class NetSession : TcpSession
{
private StringBuilder _unpackCache;
public NetSession(TcpServer server) : base(server)
{
}
protected override void OnClosed()
{
base.OnClosed();
_unpackCache?.Clear();
}
/// <summary>
/// 获取分包缓存
/// </summary>
/// <returns></returns>
private StringBuilder GetUnpackCache()
{
return _unpackCache ??= new StringBuilder();
}
/// <summary>
///
/// </summary>
protected override void OnReceived()
{
if (ReadBuffer.IndexOf(35) != 0L)// '#'
{
return;
// throw new Exception("异常TCP连接 IP: " + RemoteIPEndPoint);
}
string rawText = null;
while (ReadBuffer.CanReadLine)
{
try
{
byte[] data = ReadBuffer.ReadLine();
rawText = Encoding.UTF8.GetString(data);
NetPackage netPackage = NetPackage.Parse(rawText, GetUnpackCache);
((NetServer)Server).RaiseReceivedData(this, netPackage, rawText);
if (netPackage.DataSegment.PackageFlag != null && netPackage.DataSegment.PackageFlag.A == 1)
{
Response(netPackage);
}
}
catch (Exception ex)
{
Console.WriteLine($"error :OnReceived:{ex.Message},data:{ex.Data}");
}
}
}
/// <summary>
/// 应答
/// </summary>
private void Response(NetPackage netPackage)
{
try
{
netPackage.DataSegment.ST = DataSegment.ResponseST;
netPackage.DataSegment.CN = CommandNumber.DataResponse;
netPackage.DataSegment.PackageFlag.A = 0;
netPackage.DataSegment.PackageFlag.D = 0;
netPackage.DataSegment.CpCommand.ExeRtn = ResponseCode.ExecSucceeded;
string rawText = netPackage.Serialize();
byte[] data = Encoding.UTF8.GetBytes(rawText);
SendAsync(data);
((NetServer)Server).RaiseSendData(this, netPackage, rawText);
}
catch (Exception ex)
{
throw new Exception("Error in NetSession", ex);
}
}
}
}

View File

@ -0,0 +1,140 @@
using System.Net.Sockets;
using System.Net;
using System.Text;
using IceCoffee.FastSocket.Tcp;
using langguanApi.Model.Dto;
using Newtonsoft.Json;
using langguanApi.Model;
using langguanApi.Service.HJ212;
using langguanApi.Extensions.AutoDI;
namespace langguanApi.Service
{
public class HJ212SocketServer
{
private Hj212Service _hj212Service;
public HJ212SocketServer(Hj212Service hj212Service)
{
_hj212Service = hj212Service;
}
/// <summary>
/// 缓冲器
/// </summary>
private byte[] result = new byte[1024];
/// <summary>
/// 最大连接数
/// </summary>
private int maxClientCount;
/// <summary>
/// 服务IP地址
/// </summary>
private string ip;
/// <summary>
/// 服务端口号
/// </summary>
private int port => 5001;
// 编码
// private string code;
/// <summary>
/// 客户端列表
/// </summary>
private List<Socket> ClientSockets;
/// <summary>
/// IP终端
/// </summary>
private IPEndPoint ipEndPoint;
/// <summary>
/// 服务端Socket
/// </summary>
private Socket ServerSocket;
private static NetServer server;
private static IceCoffee.FastSocket.Tcp.TcpClient client;
/// <summary>
/// 启动服务
/// </summary>
/// <returns></returns>
public async Task Start()
{
ip = IPAddress.Any.ToString();
server = new NetServer(ip, port);
server.Started += OnNetServer_Started;
server.ExceptionCaught += OnNetServer_ExceptionCaught;
server.SessionStarted += OnNetServer_SessionStarted;
server.SessionClosed += OnNetServer_SessionClosed;
server.ReceivedData += OnNetServer_ReceivedData;
server.SendData += OnNetServer_SendData;
server.Start();
}
private void OnNetServer_Started()
{
Console.WriteLine($"开始监听: {ip}:{port}");
}
private void OnNetServer_SendData(NetSession session, NetPackage netPackage, string rawText)
{
Console.WriteLine($"发送给: {session.RemoteIPEndPoint}: {rawText}");
}
private void OnNetServer_SessionClosed(TcpSession session)
{
Console.WriteLine("会话关闭: " + session.RemoteIPEndPoint + ", 当前会话总数: " + server.SessionCount);
}
private static void OnNetServer_SessionStarted(TcpSession session)
{
Console.WriteLine("会话开始: " + session.RemoteIPEndPoint + ", 当前会话总数: " + server.SessionCount);
}
private async void OnNetServer_ReceivedData(TcpSession session, NetPackage netPackage, string rawText)
{
Console.WriteLine("收到自: " + session.RemoteIPEndPoint + ": " + rawText);
HJ212_2017 hj = new HJ212_2017();
if (hj.DecodeData(rawText))
{
var body = JsonConvert.SerializeObject(hj.CP);
var entity = JsonConvert.DeserializeObject<Model.HJ212>(body);
entity.deviceMN = hj.DATA_HEAD["MN"];
//校验通过,开始入库
await _hj212Service.Add(entity, session.RemoteIPEndPoint.ToString());
}
}
private void OnNetServer_ExceptionCaught(Exception ex)
{
Console.WriteLine("Error in NetServer" + ex);
}
byte[] CallCRC(byte[] data)
{
string ccc = Convert.ToString(getCrc(data), 16).PadLeft(4, '0');
return Encoding.ASCII.GetBytes(ccc.ToUpper());
}
private int getCrc(byte[] data)
{
int high;
int flag;
// 16位寄存器所有数位均为1
int wcrc = 0xffff;
for (int i = 0; i < data.Length; i++)
{
// 16 位寄存器的高位字节
high = wcrc >> 8;
// 取被校验串的一个字节与 16 位寄存器的高位字节进行“异或”运算
wcrc = high ^ data[i];
for (int j = 0; j < 8; j++)
{
flag = wcrc & 0x0001;
// 把这个 16 寄存器向右移一位
wcrc = wcrc >> 1;
// 若向右(标记位)移出的数位是 1,则生成多项式 1010 0000 0000 0001 和这个寄存器进行“异或”运算
if (flag == 1)
wcrc ^= 0xa001;
}
}
return wcrc;
}
}
}

View File

@ -0,0 +1,110 @@
using langguanApi.Extensions.AutoDI;
using langguanApi.Model;
using langguanApi.Model.Dto;
using System.Linq.Expressions;
namespace langguanApi.Service
{
[ServiceInjection(InjectionType.Transient)]
public class Hj212Service : BaseService<Model.HJ212>
{
private DeviceService _deviceSerive;
public Hj212Service(IConfiguration config, DeviceService deviceSerive) : base(config, nameof(Model.HJ212))
{
_deviceSerive = deviceSerive;
}
/// <summary>
/// 新加数据
/// </summary>
/// <param name="hJ212"></param>
/// <param name="deviceIp"></param>
/// <returns></returns>
public async Task Add(Model.HJ212 hJ212, string deviceIp)
{
//先判断当前设备是否存在
await _deviceSerive.Add(new DeviceDto()
{
deviceMN = hJ212.deviceMN,
Ip = deviceIp,
lat = hJ212.lat,
lng = hJ212.lng,
state = 1
});
await base.CreateAsync(hJ212);
}
/// <summary>
/// 最近10个小时的数据
/// </summary>
/// <param name="hours"></param>
/// <returns></returns>
public async Task<List<Model.HJ212>> GetViewTop(int hours = -10)
{
var date = DateTime.Now.AddHours(-8).AddHours(hours);
Expression<Func<Model.HJ212, bool>> exp = filter => filter.CreateDateTime >= date;
var result = (await base.GetListWithExp(exp)).ToList();
return result;
}
/// <summary>
/// 按设备号查询数据
/// </summary>
/// <param name="deviceMn"></param>
/// <returns></returns>
public async Task<object>GetViewByDeviceMn(string deviceMn)
{
Expression<Func<Model.HJ212, bool>> exp = filter => filter.deviceMN == deviceMn;
var result = (await base.GetListWithExp(exp)).OrderByDescending(s => s.CreateDateTime).Take(60).ToList();
List<columnView> list = new List<columnView>();
var temp = result.Select(s => new
{
s.a34001,
s.a34002,
s.a34004,
hour = s.CreateDateTime.AddHours(8).ToString("yyyy-MM-dd HH:mm")
}).ToList();
temp.GroupBy(g => new { g.hour }).ToList().ForEach(s =>
{
var v1 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34001);
var v2 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34002);
var v3 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34004);
list.Add(new columnView() { hour = s.Key.hour, type = "a34001", value = v1 });
list.Add(new columnView() { hour = s.Key.hour, type = "a34002", value = Math.Round(v2, 2) });
list.Add(new columnView() { hour = s.Key.hour, type = "a34004", value = Math.Round(v3, 2) });
});
return list;
}
/// <summary>
/// 实时的数据
/// </summary>
/// <returns></returns>
public async Task<List<columnView>> Realtime()
{
Expression<Func<Model.HJ212, bool>> exp = filter => true;
var result = (await base.GetListWithExp(exp)).OrderByDescending(s => s.CreateDateTime)
.Take(60).OrderBy(s => s.CreateDateTime).ToList();
List<columnView> list = new List<columnView>();
var temp = result.Select(s => new
{
s.a34001,
s.a34002,
s.a34004,
hour = s.CreateDateTime.AddHours(8).ToString("yyyy-MM-dd HH:mm")
}).ToList();
temp.GroupBy(g => new { g.hour }).ToList().ForEach(s =>
{
var v1 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34001);
var v2 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34002);
var v3 = temp.Where(m => m.hour == s.Key.hour).Sum(t => t.a34004);
list.Add(new columnView() { hour = s.Key.hour, type = "a34001", value = v1 });
list.Add(new columnView() { hour = s.Key.hour, type = "a34002", value = Math.Round(v2, 2) });
list.Add(new columnView() { hour = s.Key.hour, type = "a34004", value = Math.Round(v3, 2) });
});
return list;
}
}
}

View File

@ -0,0 +1,70 @@
using langguanApi.Common.Redis;
using langguanApi.Common;
using langguanApi.Extensions.AutoDI;
using langguanApi.Model;
using System.Linq.Expressions;
namespace langguanApi.Service
{
/// <summary>
/// HomeService
/// </summary>
[ServiceInjection(InjectionType.Scoped)]
public class HomeService
{
private DeviceService _deviceService;
private Hj212Service _hj212Service;
private readonly IConfiguration _configuration;
private CacheManager _cacheManager;
private readonly WeatherService _weatherService;
/// <summary>
/// HomeService
/// </summary>
/// <param name="device"></param>
/// <param name="hj212Service"></param>
public HomeService(DeviceService device, Hj212Service hj212Service,
IConfiguration configuration, CacheManager cacheManager, WeatherService weatherService)
{
_deviceService = device;
_hj212Service = hj212Service;
_configuration = configuration;
_cacheManager = cacheManager;
_weatherService = weatherService;
}
/// <summary>
/// view
/// </summary>
/// <returns></returns>
public async Task<ApiResult> View()
{
var devices = await _deviceService.GetAsync();
var ariQuality = "";
Expression<Func<Model.HJ212, bool>> filter = exp => true;
var Realtime = await _hj212Service.Realtime();
var GetViewTop = await _hj212Service.GetViewTop();
// 获取天气信息缓存1小时如果不存在则调用WeatherService获取
Func<Task<object>> getWeatherFunc = async () => await _weatherService.GetWeather();
var weather = await _cacheManager.GetConvertVale(RedisKeylist.Weather, getWeatherFunc, 60 * 60);
return new ApiResult
{
code = 0,
data = new
{
home = new
{
center = new
{
lon = _configuration.GetValue<double>("Home:Center:Lon"),
lat = _configuration.GetValue<double>("Home:Center:Lat"),
},
title = _configuration.GetValue<string>("Home:Title"),
},
devices,
ariQuality,
Realtime,
GetViewTop
}
};
}
}
}

View File

@ -0,0 +1,84 @@
using langguanApi.Extensions.AutoDI;
using System.Net.NetworkInformation;
namespace langguanApi.Service
{
/// <summary>
/// ping service
/// </summary>
public class PingService
{
private DeviceService _deviceSerive;
/// <summary>
///
/// </summary>
/// <param name="deviceSerive"></param>
public PingService(DeviceService deviceSerive)
{
_deviceSerive = deviceSerive;
}
/// <summary>
///
/// </summary>
public void CreatTask()
{
//5分钟执行一次
Timer myTimer = new Timer(new TimerCallback(Execute), null, 2000, 300000);
// Timer myTimer = new Timer(new TimerCallback(Execute), "ping service", 2000, 10000);
}
/// <summary>
///
/// </summary>
/// <param name="b"></param>
public async void Execute(object b)
{
var deviceList = await _deviceSerive.GetAsync();
if (deviceList.Any())
{
foreach (var item in deviceList)
{
if (!string.IsNullOrEmpty(item.Ip))
{
var ip = item.Ip.Split(":")[0];
var res = await PingIp(ip);
item.state = res == true ? 1 : 0;
await _deviceSerive.UpdateAsync(item.Id, item);
}
}
}
Console.WriteLine("{0} ping running.", (string)b);
}
/// <summary>
/// ping
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public async Task<bool> PingIp(string ip)
{
try
{
//Ping 实例对象;
Ping pingSender = new Ping();
PingReply pingReply = await pingSender.SendPingAsync(ip);
if (pingReply.Status == IPStatus.Success)
{
return true;
}
}
catch (Exception)
{
return false;
}
return false;
}
}
}

View File

@ -0,0 +1,140 @@
using Newtonsoft.Json;
namespace langguanApi.Service
{
public class WeatherService
{
private IHttpClientFactory _httpClientFactory;
private IConfiguration _configuration;
private ILogger<WeatherService> _logger;
public WeatherService(IHttpClientFactory httpClientFactory,
IConfiguration configuration, ILogger<WeatherService> logger)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
_logger=logger;
}
/// <summary>
/// 爬气象局的天气数据%
/// </summary>
/// <returns></returns>
public async Task<object> GetWeather()
{
try
{
var client = _httpClientFactory.CreateClient();
var resp = await client.GetAsync(_configuration.GetSection("Weather").Value);
if (resp.IsSuccessStatusCode)
{
var data = await resp.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<Root>(data);
return new
{
location = result?.data.location.name,
result?.data.now.precipitation,
result?.data.now.temperature,
result?.data.now.pressure,
result?.data.now.humidity,
result?.data.now.windDirection,
result?.data.now.windDirectionDegree,
result?.data.now.windSpeed,
result?.data.now.windScale,
};
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
return null;
}
public class Location
{
/// <summary>
/// 54511
/// </summary>
public string id { get; set; }
/// <summary>
/// 北京
/// </summary>
public string name { get; set; }
/// <summary>
/// 中国, 北京, 北京
/// </summary>
public string path { get; set; }
}
public class Now
{
/// <summary>
/// Precipitation
/// </summary>
public double precipitation { get; set; }
/// <summary>
/// Temperature
/// </summary>
public double temperature { get; set; }
/// <summary>
/// Pressure
/// </summary>
public double pressure { get; set; }
/// <summary>
/// Humidity
/// </summary>
public double humidity { get; set; }
/// <summary>
/// 东北风
/// </summary>
public string windDirection { get; set; }
/// <summary>
/// WindDirectionDegree
/// </summary>
public double windDirectionDegree { get; set; }
/// <summary>
/// WindSpeed
/// </summary>
public double windSpeed { get; set; }
/// <summary>
/// 微风
/// </summary>
public string windScale { get; set; }
}
/// <summary>
///
/// </summary>
public class Data
{
/// <summary>
/// Location
/// </summary>
public Location location { get; set; }
/// <summary>
/// Now
/// </summary>
public Now now { get; set; }
/// <summary>
/// Alarm
/// </summary>
public List<object> alarm { get; set; }
/// <summary>
/// 2024/01/15 10:05
/// </summary>
public DateTime lastUpdate { get; set; }
}
public class Root
{
/// <summary>
/// success
/// </summary>
public string msg { get; set; }
/// <summary>
/// Code
/// </summary>
public int code { get; set; }
/// <summary>
/// Data
/// </summary>
public Data data { get; set; }
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,26 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MongoDBConn": "mongodb://admin:adminn@101.43.201.20:8017",
"DBName": "lg"
},
"Redis": {
"Server": "101.43.201.20:6379,password=Aa123,abortConnect =false",
"Key": "tdss",
"Index": 5
},
"Weather": "https://weather.cma.cn/api/now/54511", //,
"Home": {
"Title": "鄂托克旗新航焦化有限公司",
"Center": {
"lat": 39.4716613,
"lon": 107.1413332
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<!--生成时包含xml文件-->
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>D:\work\langguanApi\langguanApi.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IceCoffee.FastSocket" Version="1.0.3" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.27" />
<PackageReference Include="MongoDB.Bson" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
</Project>