parent
d8c21e58b2
commit
23033f4ae5
@ -1,16 +0,0 @@
|
||||
*.bak
|
||||
*.suo
|
||||
*.db
|
||||
*.user
|
||||
.vs/
|
||||
obj
|
||||
Obj
|
||||
bin
|
||||
Bin
|
||||
debug
|
||||
Debug
|
||||
release
|
||||
Release
|
||||
Logs
|
||||
logs
|
||||
node_modules
|
@ -1,20 +0,0 @@
|
||||
using Infrastructure.Application;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace SPService.Applicaiton.Models
|
||||
{
|
||||
[Display(Name = "指令")]
|
||||
public class EditGatewayModel : EditModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "编号")]
|
||||
public string Sn { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "IP")]
|
||||
public string IP { get; set; }
|
||||
|
||||
[Display(Name = "启用")]
|
||||
public string Enable { get; set; }
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System.Linq;
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using IoTShared.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DataController : CrudController<Data, DataSearchModel, EditDataModel, EditDataModel>
|
||||
{
|
||||
private readonly AjaxController _ajax;
|
||||
|
||||
public DataController(IRepository<Data> repo, AjaxController ajax) : base(repo)
|
||||
{
|
||||
this._ajax = ajax;
|
||||
}
|
||||
|
||||
public override IQueryable<Data> Query(DataSearchModel model, IQueryable<Data> query)
|
||||
{
|
||||
ViewData.SelectList(o => model.NodeId, () => this._ajax.GetNodeSelectList(model.NodeId));
|
||||
ViewData.SelectList(o => model.DeviceId, () => this._ajax.GetDeviceSelectList(model.NodeId.Value, model.DeviceId), model.NodeId.HasValue);
|
||||
return query.WhereIf(model.NodeId.HasValue, o => o.Device.NodeId == model.NodeId.Value)
|
||||
.WhereIf(model.DeviceId.HasValue, o => o.DeviceId == model.DeviceId.Value)
|
||||
.WhereIf(!string.IsNullOrEmpty(model.Keyword), o => o.Name.Contains(model.Keyword));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DeviceController : CrudController<Device, DeviceSearchMode, EditDeviceModel, EditDeviceModel>
|
||||
{
|
||||
public DeviceController(IRepository<Device> repo) : base(repo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace UserCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public HomeController()
|
||||
{
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
@{
|
||||
ViewData["IsHomePage"] = true;
|
||||
}
|
||||
<h1>首页</h1>
|
@ -1,52 +0,0 @@
|
||||
<section class="sidebar" style="height: auto;">
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
<li class="@GetClass("Home")"><a href="@Url.Action("Index","Home")"><i class="fa fa-circle-o"></i><span>首页</span></a></li>
|
||||
<li class="@GetClass("Configuration")"><a href="@Url.Action("Index","Configuration")"><i class="fa fa-circle-o"></i><span>网站配置</span></a></li>
|
||||
<li class="treeview @GetClass("User","Role","Permission")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>权限管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("User")"><a href="@Url.Action("Index","User")"><i class="fa fa-circle-o"></i><span>用户管理</span></a></li>
|
||||
<li class="@GetClass("Role")"><a href="@Url.Action("Index","Role")"><i class="fa fa-circle-o"></i><span>角色管理</span></a></li>
|
||||
<li class="@GetClass("Permission")"><a href="@Url.Action("Index","Permission")"><i class="fa fa-circle-o"></i><span>权限管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="treeview @GetClass("Node","Device","Data","Api","Parameter","Sence","Command")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>设备管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("Node")"><a href="@Url.Action("Index","Node")"><i class="fa fa-circle-o"></i><span>节点管理</span></a></li>
|
||||
<li class="@GetClass("Device")"><a href="@Url.Action("Index","Device")"><i class="fa fa-circle-o"></i><span>设备管理</span></a></li>
|
||||
<li class="@GetClass("Data")"><a href="@Url.Action("Index","Data")"><i class="fa fa-circle-o"></i><span>数据管理</span></a></li>
|
||||
<li class="@GetClass("Api")"><a href="@Url.Action("Index","Api")"><i class="fa fa-circle-o"></i><span>接口管理</span></a></li>
|
||||
<li class="@GetClass("Parameter")"><a href="@Url.Action("Index","Parameter")"><i class="fa fa-circle-o"></i><span>参数管理</span></a></li>
|
||||
<li class="@GetClass("Sence")"><a href="@Url.Action("Index","Sence")"><i class="fa fa-circle-o"></i><span>场景管理</span></a></li>
|
||||
<li class="@GetClass("Command")"><a href="@Url.Action("Index","Command")"><i class="fa fa-circle-o"></i><span>命令管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
@functions{
|
||||
public string GetClass(params string[] controllers)
|
||||
{
|
||||
if (controllers.Select(o => o.ToLower()).Contains(this.ViewContext.RouteData.Values["controller"].ToString().ToLower()))
|
||||
{
|
||||
if (controllers.Length > 1)
|
||||
{
|
||||
return "active open";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<script>
|
||||
function clear() {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
$(arguments[i]).find('option').not('[value=""]').remove();
|
||||
}
|
||||
}
|
||||
function update(url, id) {
|
||||
$.getJSON(url, function (data) {
|
||||
$.each(data, function (i, v) {
|
||||
$(id).append('<option value="' + v.Value + '">' + v.Text + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
$(function () {
|
||||
$('#NodeId').change(function () {
|
||||
var id = $(this).find(':selected').val();
|
||||
clear('#DeviceId');
|
||||
if (id) {
|
||||
var url = '@Url.Action("GetDeviceJson", "Ajax")?parentId=' + encodeURI(id);
|
||||
update(url,'#DeviceId');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,7 +0,0 @@
|
||||
@inherits Infrastructure.Web.Mvc.Razor.MyRazorPage<TModel>
|
||||
@using Infrastructure.Application
|
||||
@using Infrastructure.Extensions
|
||||
@using Infrastructure.Data
|
||||
@using Application.Domain.Entities
|
||||
@using Application.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,3 +0,0 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace FBeeService.Controllers
|
||||
{
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly IRepository<Device> _deviceRepo;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly DeviceService _deviceService;
|
||||
|
||||
public HomeController(IHttpClientFactory httpClientFactory,
|
||||
DeviceService deviceService,
|
||||
IRepository<Device> deviceRepo)
|
||||
{
|
||||
this._deviceRepo = deviceRepo;
|
||||
this._httpClientFactory = httpClientFactory;
|
||||
this._deviceService = deviceService;
|
||||
}
|
||||
|
||||
#region ui
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
var list = this._deviceRepo.ReadOnlyTable()
|
||||
.Include(o => o.Data)
|
||||
.Where(o => o.Info.DeviceType == DeviceType.Gateway)
|
||||
.OrderBy(o => o.Number)
|
||||
.ToList();
|
||||
return View(list);
|
||||
}
|
||||
|
||||
public IActionResult Gateway(string sn)
|
||||
{
|
||||
var list = this._deviceRepo.ReadOnlyTable()
|
||||
.Include(o => o.Data)
|
||||
.Where(o => o.GatewayNumber == sn)
|
||||
.OrderBy(o => o.CategoryNumber)
|
||||
.ToList();
|
||||
return View(list);
|
||||
}
|
||||
|
||||
#endregion ui
|
||||
|
||||
#region IR
|
||||
|
||||
[SwaggerOperation("版本")]
|
||||
[HttpGet]
|
||||
[Route("/ir/version")]
|
||||
public ApiResponse Version([SwaggerParameter("网关Id")]string sn, [SwaggerParameter("设备Id")]string id)
|
||||
{
|
||||
try
|
||||
{
|
||||
this._deviceService.XA70080(sn, id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
return ApiResponse.AsyncSuccess();
|
||||
}
|
||||
|
||||
[Route("/ir/test")]
|
||||
public ApiResponse IRControl([SwaggerParameter("网关Id")]string sn, [SwaggerParameter("设备Id")]string id, byte type, ushort code)
|
||||
{
|
||||
try
|
||||
{
|
||||
this._deviceService.XA70082(sn, id, type, code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
return ApiResponse.AsyncSuccess();
|
||||
}
|
||||
|
||||
[Route("/ir/study")]
|
||||
public ApiResponse IRStudy([SwaggerParameter("网关Id")]string sn, [SwaggerParameter("设备Id")]string id, byte type, ushort code)
|
||||
{
|
||||
try
|
||||
{
|
||||
this._deviceService.XA70083(sn, id, type, code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
return ApiResponse.AsyncSuccess();
|
||||
}
|
||||
|
||||
[SwaggerOperation("版本")]
|
||||
[HttpGet]
|
||||
[Route("/ir/control")]
|
||||
public ApiResponse IRControl([SwaggerParameter("网关Id")]string sn, [SwaggerParameter("设备Id")]string id, int power, int pattern, int temperature, int direction, int wind)
|
||||
{
|
||||
try
|
||||
{
|
||||
var keyCode = power == 1 ? 1 : power + pattern + temperature + direction + wind;
|
||||
this._deviceService.XA70082(sn, id, 0x01, (ushort)keyCode);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
return ApiResponse.AsyncSuccess();
|
||||
}
|
||||
|
||||
#endregion IR
|
||||
|
||||
#region tools
|
||||
|
||||
private string GetApiJson(string prefix)
|
||||
{
|
||||
var url = new UriBuilder
|
||||
{
|
||||
Host = Request.Host.Host,
|
||||
Port = Request.Host.Port ?? 80,
|
||||
Path = "/swagger/v1/swagger.json"
|
||||
}.ToString();
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
var result = hc.GetStringAsync(url).Result;
|
||||
var json = JsonConvert.DeserializeObject(result) as JObject;
|
||||
var paths = json.Properties().FirstOrDefault(o => o.Name == "paths").Value as JObject;
|
||||
var names = paths.Properties().Select(o => o.Name).ToList();
|
||||
foreach (var item in names)
|
||||
{
|
||||
if (!item.StartsWith(prefix))
|
||||
{
|
||||
paths.Remove(item);
|
||||
}
|
||||
}
|
||||
var realResult = JsonConvert.SerializeObject(json);
|
||||
return realResult;
|
||||
}
|
||||
|
||||
#endregion tools
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Infrastructure.Application;
|
||||
using Infrastructure.Configuration;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Hosting;
|
||||
using Microsoft.AspNetCore;
|
||||
|
||||
namespace FBeeService
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = "localhost";
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.Run<Startup>(new List<EFConfigurationValue> {
|
||||
new EFConfigurationValue { Id = "openapi.name", Value= "v1" },
|
||||
new EFConfigurationValue { Id = "openapi.title", Value= "fbee api" },
|
||||
new EFConfigurationValue { Id = "openapi.version", Value= "1.0" },
|
||||
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
|
||||
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
|
||||
new EFConfigurationValue { Id = "email:host", Value= "nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:port", Value= "25"},
|
||||
new EFConfigurationValue { Id = "email:user", Value= "admin@nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:password", Value= "aA123456"},
|
||||
new EFConfigurationValue { Id = "server.ip", Value= "" },
|
||||
new EFConfigurationValue { Id = "server.urls", Value= "http://*:8009" },
|
||||
new EFConfigurationValue { Id = "notify:enabled", Value= "false"},
|
||||
new EFConfigurationValue { Id = "notify:host", Value= $"{host}:8001"},
|
||||
new EFConfigurationValue { Id = "timer.seconds", Value="600"},
|
||||
new EFConfigurationValue { Id = "connectId", Value= Guid.NewGuid().ToBase62() },
|
||||
new EFConfigurationValue { Id = "node.number", Value= "所属节点编号" },
|
||||
//
|
||||
new EFConfigurationValue { Id = "name", Value= "FBeeService服务"},
|
||||
new EFConfigurationValue { Id = "logo", Value= "/images/logo.png",Type= InputType.ImageUrl},
|
||||
new EFConfigurationValue { Id = "copyright", Value= "Copyright © {now} Company. All rights reserved",Type= InputType.Html}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:8009/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"OnvifService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://127.0.0.1:8009/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using IoT.Shared.Infrastructure;
|
||||
using IoT.UI.Shard;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FBeeService
|
||||
{
|
||||
public class Startup : IoTServiceStartup
|
||||
{
|
||||
public Startup(IConfiguration configuration, IHostingEnvironment env) : base(configuration, env)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ClientService>();
|
||||
services.AddSingleton<DeviceService>();
|
||||
base.ConfigureServices(services);
|
||||
}
|
||||
|
||||
public override void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
base.Configure(app, env, loggerFactory);
|
||||
app.ApplicationServices.GetService<DeviceService>().Start();
|
||||
app.ApplicationServices.GetService<ClientService>().Start();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
@model List<Device>
|
||||
@{
|
||||
ViewBag.HideBread = true;
|
||||
}
|
||||
<div class="box">
|
||||
<a class="btn btn-primary cmd" href="/Gateway/Refresh">查询所有网关</a>
|
||||
</div>
|
||||
<div class="box">
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
<th>Ip地址</th>
|
||||
<th>启用</th>
|
||||
<th>用户名</th>
|
||||
<th>密码</th>
|
||||
<th>查询网关设备</th>
|
||||
<th>查看</th>
|
||||
</tr>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>@item.Number</td>
|
||||
<td>@item.Ip</td>
|
||||
<td>@Html.DisplayFor(o => item.Enable)</td>
|
||||
<td>@item.UserName</td>
|
||||
<td>@item.Password</td>
|
||||
<td><a class="btn btn-primary cmd" href="/Gateway/X9d?gateway=@item.Number">查询网关信息</a></td>
|
||||
<td><a class="btn btn-primary cmd" href="/Gateway/X81?gateway=@item.Number">查询网关设备</a></td>
|
||||
<td><a href="/Home/Gateway?sn=@item.Number">查看设备</a></td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</div>
|
@ -1,26 +0,0 @@
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="@GetClass("Home")">
|
||||
<a href="@Url.Action("Index","Home")">
|
||||
首页
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/swagger/index.html">
|
||||
Open API
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@functions{
|
||||
public string GetClass(params string[] controllers)
|
||||
{
|
||||
if (controllers.Select(o => o.ToLower()).Contains(this.ViewContext.RouteData.Values["controller"].ToString().ToLower()))
|
||||
{
|
||||
if (controllers.Length > 1)
|
||||
{
|
||||
return "active open";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
@inherits Infrastructure.Web.Mvc.Razor.MyRazorPage<TModel>
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Infrastructure.Application
|
||||
@using Infrastructure.Web
|
||||
@using Infrastructure.Web.DataAnnotations
|
||||
@using Infrastructure.Extensions
|
||||
@using Infrastructure.Data
|
||||
@using Application.Domain.Entities
|
||||
@using Application.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,3 +0,0 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"UseMiniProfiler": false
|
||||
}.
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0-beta.108",
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"database.mysql.connection": "Server=127.0.0.1;Port=3306;Database=data;Uid=root;Pwd=root;",
|
||||
"database.sqlite.connection": "Data Source=data.db"
|
||||
},
|
||||
"AppSettings": {
|
||||
"database": "sqlite",
|
||||
"UseCookieSessionStore": false
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 3.5 KiB |
@ -1,16 +0,0 @@
|
||||
*.bak
|
||||
*.suo
|
||||
*.db
|
||||
*.user
|
||||
.vs
|
||||
obj
|
||||
Obj
|
||||
bin
|
||||
Bin
|
||||
debug
|
||||
Debug
|
||||
release
|
||||
Release
|
||||
Logs
|
||||
logs
|
||||
node_modules
|
@ -1,70 +0,0 @@
|
||||
using Infrastructure.Application;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ONVIFService.Applicaiton.Models
|
||||
{
|
||||
[Display(Name = "摄像头")]
|
||||
public class EditCameraModel : EditModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "编号")]
|
||||
public string Number { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "设备地址")]
|
||||
public string DeviceUrl { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "码流")]
|
||||
public string Profiles { get; set; }
|
||||
|
||||
[Display(Name = "流地址")]
|
||||
public string StreamUri { get; set; }
|
||||
|
||||
[Display(Name = "截图地址")]
|
||||
public string SnapshotUri { get; set; }
|
||||
|
||||
[Display(Name = "控制台地址")]
|
||||
public string PtzAddress { get; set; }
|
||||
|
||||
[Display(Name = "缩放支持")]
|
||||
public bool Ptz3DZoomSupport { get; set; }
|
||||
|
||||
[Display(Name = "需验证")]
|
||||
public bool NeedAuth { get; set; }
|
||||
|
||||
[Display(Name = "已验证")]
|
||||
public bool HasAuth { get; set; }
|
||||
|
||||
[Display(Name = "用户名")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
[Display(Name = "密码")]
|
||||
public string Password { get; set; }
|
||||
|
||||
public string Rtmp1 { get; set; }
|
||||
public string Flv1 { get; set; }
|
||||
public string Hls1 { get; set; }
|
||||
public string Rtmp2 { get; set; }
|
||||
public string Flv2 { get; set; }
|
||||
public string Hls2 { get; set; }
|
||||
|
||||
[Display(Name = "启用")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
[Display(Name = "推流")]
|
||||
public bool Publish { get; set; }
|
||||
|
||||
[Display(Name = "自定义参数")]
|
||||
public bool UseCustomArguments { get; set; }
|
||||
|
||||
[Display(Name = "自定义参数")]
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[Display(Name = "自定义ffmpeg")]
|
||||
public bool UseCustomFile { get; set; }
|
||||
|
||||
[Display(Name = "ffmpeg")]
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System.Linq;
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using IoTShared.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DataController : CrudController<Data, DataSearchModel, EditDataModel, EditDataModel>
|
||||
{
|
||||
private readonly AjaxController _ajax;
|
||||
|
||||
public DataController(IRepository<Data> repo, AjaxController ajax) : base(repo)
|
||||
{
|
||||
this._ajax = ajax;
|
||||
}
|
||||
|
||||
public override IQueryable<Data> Query(DataSearchModel model, IQueryable<Data> query)
|
||||
{
|
||||
ViewData.SelectList(o => model.NodeId, () => this._ajax.GetNodeSelectList(model.NodeId));
|
||||
ViewData.SelectList(o => model.DeviceId, () => this._ajax.GetDeviceSelectList(model.NodeId.Value, model.DeviceId), model.NodeId.HasValue);
|
||||
return query.WhereIf(model.NodeId.HasValue, o => o.Device.NodeId == model.NodeId.Value)
|
||||
.WhereIf(model.DeviceId.HasValue, o => o.DeviceId == model.DeviceId.Value)
|
||||
.WhereIf(!string.IsNullOrEmpty(model.Keyword), o => o.Name.Contains(model.Keyword));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DeviceController : CrudController<Device, DeviceSearchMode, EditDeviceModel, EditDeviceModel>
|
||||
{
|
||||
public DeviceController(IRepository<Device> repo) : base(repo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace UserCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public HomeController()
|
||||
{
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
@{
|
||||
ViewData["IsHomePage"] = true;
|
||||
}
|
||||
<h1>首页</h1>
|
@ -1,52 +0,0 @@
|
||||
<section class="sidebar" style="height: auto;">
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
<li class="@GetClass("Home")"><a href="@Url.Action("Index","Home")"><i class="fa fa-circle-o"></i><span>首页</span></a></li>
|
||||
<li class="@GetClass("Configuration")"><a href="@Url.Action("Index","Configuration")"><i class="fa fa-circle-o"></i><span>网站配置</span></a></li>
|
||||
<li class="treeview @GetClass("User","Role","Permission")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>权限管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("User")"><a href="@Url.Action("Index","User")"><i class="fa fa-circle-o"></i><span>用户管理</span></a></li>
|
||||
<li class="@GetClass("Role")"><a href="@Url.Action("Index","Role")"><i class="fa fa-circle-o"></i><span>角色管理</span></a></li>
|
||||
<li class="@GetClass("Permission")"><a href="@Url.Action("Index","Permission")"><i class="fa fa-circle-o"></i><span>权限管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="treeview @GetClass("Node","Device","Data","Api","Parameter","Sence","Command")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>设备管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("Node")"><a href="@Url.Action("Index","Node")"><i class="fa fa-circle-o"></i><span>节点管理</span></a></li>
|
||||
<li class="@GetClass("Device")"><a href="@Url.Action("Index","Device")"><i class="fa fa-circle-o"></i><span>设备管理</span></a></li>
|
||||
<li class="@GetClass("Data")"><a href="@Url.Action("Index","Data")"><i class="fa fa-circle-o"></i><span>数据管理</span></a></li>
|
||||
<li class="@GetClass("Api")"><a href="@Url.Action("Index","Api")"><i class="fa fa-circle-o"></i><span>接口管理</span></a></li>
|
||||
<li class="@GetClass("Parameter")"><a href="@Url.Action("Index","Parameter")"><i class="fa fa-circle-o"></i><span>参数管理</span></a></li>
|
||||
<li class="@GetClass("Sence")"><a href="@Url.Action("Index","Sence")"><i class="fa fa-circle-o"></i><span>场景管理</span></a></li>
|
||||
<li class="@GetClass("Command")"><a href="@Url.Action("Index","Command")"><i class="fa fa-circle-o"></i><span>命令管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
@functions{
|
||||
public string GetClass(params string[] controllers)
|
||||
{
|
||||
if (controllers.Select(o => o.ToLower()).Contains(this.ViewContext.RouteData.Values["controller"].ToString().ToLower()))
|
||||
{
|
||||
if (controllers.Length > 1)
|
||||
{
|
||||
return "active open";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<script>
|
||||
function clear() {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
$(arguments[i]).find('option').not('[value=""]').remove();
|
||||
}
|
||||
}
|
||||
function update(url, id) {
|
||||
$.getJSON(url, function (data) {
|
||||
$.each(data, function (i, v) {
|
||||
$(id).append('<option value="' + v.Value + '">' + v.Text + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
$(function () {
|
||||
$('#NodeId').change(function () {
|
||||
var id = $(this).find(':selected').val();
|
||||
clear('#DeviceId');
|
||||
if (id) {
|
||||
var url = '@Url.Action("GetDeviceJson", "Ajax")?parentId=' + encodeURI(id);
|
||||
update(url,'#DeviceId');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,7 +0,0 @@
|
||||
@inherits Infrastructure.Web.Mvc.Razor.MyRazorPage<TModel>
|
||||
@using Infrastructure.Application
|
||||
@using Infrastructure.Extensions
|
||||
@using Infrastructure.Data
|
||||
@using Application.Domain.Entities
|
||||
@using Application.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,3 +0,0 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Infrastructure.Data;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
|
||||
namespace ONVIFService.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly IRepository<Device> _cameraRepo;
|
||||
private readonly DeviceService _onvifService;
|
||||
|
||||
public HomeController(DeviceService onvifService, IRepository<Device> cameraRepo)
|
||||
{
|
||||
this._cameraRepo = cameraRepo;
|
||||
this._onvifService = onvifService;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
var model = this._cameraRepo.ReadOnlyTable().Include(o => o.Data).ToList();
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,518 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Models;
|
||||
using IoT.Shared.Infrastructure;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class DeviceService : BaseDeviceService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, (Device camera, Process local, Process remote)> _list = new ConcurrentDictionary<string, (Device camera, Process local, Process remote)>();
|
||||
private readonly IHostingEnvironment _env;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IOnvifDeviceManagement _onvifDeviceManagement;
|
||||
|
||||
public DeviceService(IServiceProvider applicationServices, IConfiguration configuration, IHostingEnvironment env, IHttpClientFactory httpClientFactory)
|
||||
: base(applicationServices, configuration)
|
||||
{
|
||||
this._env = env;
|
||||
this._httpClientFactory = httpClientFactory;
|
||||
this._onvifDeviceManagement = new OnvifDeviceManagement(httpClientFactory);
|
||||
}
|
||||
|
||||
#region impl interface
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
this._tokenSource.Cancel();
|
||||
foreach (var item in this._list.Keys.ToList())
|
||||
{
|
||||
this.Remove(item);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion impl interface
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
try
|
||||
{
|
||||
Search();
|
||||
Notify();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
|
||||
public void Search()
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = this._onvifDeviceManagement.Discovery();
|
||||
foreach (var ipCamera in list)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ipCamera.Id) || string.IsNullOrEmpty(ipCamera.DeviceUrl))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Console.WriteLine(ipCamera.DeviceUrl);
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var deviceInfoNumber = "onvifcamera";
|
||||
var deviceInfoRepo = scope.ServiceProvider.GetService<IRepository<DeviceInfo>>();
|
||||
var deviceInfo = deviceInfoRepo.Table().FirstOrDefault(o => o.Number == deviceInfoNumber);
|
||||
if (deviceInfo == null)
|
||||
{
|
||||
deviceInfo = new DeviceInfo
|
||||
{
|
||||
Number = deviceInfoNumber,
|
||||
Name = "ONVIF摄像头",
|
||||
DeviceType = DeviceType.Gateway,
|
||||
ApiJson = this.GetApiJson("/Camera/")
|
||||
};
|
||||
deviceInfoRepo.Add(deviceInfo);
|
||||
deviceInfoRepo.SaveChanges();
|
||||
this.SendDeviceInfo(deviceInfo);
|
||||
}
|
||||
var deviceRepo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
var device = deviceRepo.Table().Include(o => o.Data).FirstOrDefault(o => o.Number == ipCamera.Id);
|
||||
if (device == null)
|
||||
{
|
||||
device = new Device
|
||||
{
|
||||
Name = "摄像头",
|
||||
Number = ipCamera.Id,
|
||||
Icon = "camera",
|
||||
CategoryNumber = "10",
|
||||
InfoNumber = deviceInfoNumber,
|
||||
InfoId = deviceInfo.Id
|
||||
};
|
||||
device.AddorUpdateData("mainrtmp", $"rtmp://{this._configuration["stream.rtmp"]}/live/main{ipCamera.Id}", DeviceDataType.String, "主码流rtmp");
|
||||
device.AddorUpdateData("mainflv", $"http://{this._configuration["stream.flv"]}/live/main{ipCamera.Id}.flv", DeviceDataType.String, "主码流flv");
|
||||
device.AddorUpdateData("mainhls", $"http://{this._configuration["stream.hls"]}/live/main{ipCamera.Id}.m3u8", DeviceDataType.String, "主码流hls");
|
||||
device.AddorUpdateData("subrtmp", $"rtmp://{this._configuration["stream.rtmp"]}/live/sub{ipCamera.Id}", DeviceDataType.String, "子码流rtmp");
|
||||
device.AddorUpdateData("subflv", $"http://{this._configuration["stream.flv"]}/live/sub{ipCamera.Id}.flv", DeviceDataType.String, "子码流flv");
|
||||
device.AddorUpdateData("subhls", $"http://{this._configuration["stream.hls"]}/live/sub{ipCamera.Id}.m3u8", DeviceDataType.String, "子码流hls");
|
||||
device.AddorUpdateData("ffmpeg.file", this._configuration["ffmpeg.file"], DeviceDataType.String, "ffmpeg.file", hidden: true);
|
||||
device.AddorUpdateData("ffmpeg.args", this._configuration["ffmpeg.args"], DeviceDataType.String, "ffmpeg.args", hidden: true);
|
||||
device.AddorUpdateData("CustomFile", "", DeviceDataType.String, "自定义ffmpeg路径", hidden: true);
|
||||
device.ConnectId = this._configuration["connectId"];
|
||||
device.NodeNumber = this._configuration["node.number"];
|
||||
deviceRepo.Add(device);
|
||||
deviceRepo.SaveChanges();
|
||||
this.SendDevice(device);
|
||||
}
|
||||
var profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl);
|
||||
var needAuth = false;
|
||||
var hasAuth = false;
|
||||
if (profiles == "")
|
||||
{
|
||||
needAuth = true;
|
||||
device.UserName = device.UserName ?? this._configuration["camera.usr"];
|
||||
device.Password = device.Password ?? this._configuration["camera.pwd"];
|
||||
profiles = this._onvifDeviceManagement.GetProfiles(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password);
|
||||
if (profiles == "")
|
||||
{
|
||||
hasAuth = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasAuth = true;
|
||||
ipCamera.GetProfilesXml = profiles;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ipCamera.GetProfilesXml = profiles;
|
||||
}
|
||||
ipCamera.ParseProfiles();
|
||||
|
||||
if (needAuth)
|
||||
{
|
||||
ipCamera.MainStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.First().Token);
|
||||
ipCamera.MainSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.First().Token);
|
||||
ipCamera.SubStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.Last().Token);
|
||||
ipCamera.SubSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, device.UserName, device.Password, ipCamera.Profiles.Last().Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipCamera.MainStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.First().Token);
|
||||
ipCamera.MainSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.First().Token);
|
||||
ipCamera.SubStreamUriXml = this._onvifDeviceManagement.GetStreamUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.Last().Token);
|
||||
ipCamera.SubSnapshotUriXml = this._onvifDeviceManagement.GetSnapshotUri(ipCamera.DeviceUrl, ipCamera.MediaUrl, ipCamera.Profiles.Last().Token);
|
||||
}
|
||||
ipCamera.ParseStreamUri();
|
||||
ipCamera.ParseSnapshotUri();
|
||||
device.AddorUpdateData("NeedAuth", needAuth ? "是" : "否", DeviceDataType.String, "需认证");
|
||||
device.AddorUpdateData("HasAuth", hasAuth ? "是" : "否", DeviceDataType.String, "已认证");
|
||||
device.AddorUpdateData("DeviceUrl", ipCamera.DeviceUrl, DeviceDataType.String, "设备地址");
|
||||
device.AddorUpdateData("PtzAddress", ipCamera.PTZAddress, DeviceDataType.String, "云台地址");
|
||||
device.AddorUpdateData("Ptz3DZoomSupport", ipCamera.Ptz3DZoomSupport ? "是" : "否", DeviceDataType.String, "缩放支持");
|
||||
device.AddorUpdateData("MainToken", ipCamera.Profiles.First().Token, DeviceDataType.String, "主码流Token");
|
||||
device.AddorUpdateData("SubToken", ipCamera.Profiles.Last().Token, DeviceDataType.String, "子码流Token");
|
||||
device.AddorUpdateData("MainStreamUri", ipCamera.MainStreamUri, DeviceDataType.String, "主码流地址");
|
||||
device.AddorUpdateData("MainSnapshotUri", ipCamera.MainSnapshotUri, DeviceDataType.String, "主码流截图地址");
|
||||
device.AddorUpdateData("SubStreamUri", ipCamera.SubStreamUri, DeviceDataType.String, "子码流地址");
|
||||
device.AddorUpdateData("SubSnapshotUri", ipCamera.SubSnapshotUri, DeviceDataType.String, "子码流截图地址");
|
||||
deviceRepo.SaveChanges();
|
||||
this.SendDevice(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
|
||||
public void Notify()
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
var cameras = repo.ReadOnlyTable().Include(o => o.Data).Where(o => o.Enable).ToList();
|
||||
foreach (var key in this._list.Keys)
|
||||
{
|
||||
var camera = cameras.FirstOrDefault(o => o.Number == key);
|
||||
var remove = false;
|
||||
if (!camera.Enable)
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "是" && camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "否")
|
||||
{
|
||||
remove = true;
|
||||
}
|
||||
if (remove)
|
||||
{
|
||||
this.Remove(key);
|
||||
}
|
||||
}
|
||||
foreach (var camera in cameras)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (camera.Enable)
|
||||
{
|
||||
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "否" || camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是")
|
||||
{
|
||||
this.Publish(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Publish(Device camera)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this._list.Any(o => o.Key == camera.Number))
|
||||
{
|
||||
this.Add(camera);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(string key)
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
var camera = repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == key);
|
||||
if (camera != null && camera.Enable)// && camera.Publish && (!camera.NeedAuth || (camera.NeedAuth && camera.HasAuth)))
|
||||
{
|
||||
if (camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "否" || camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是")
|
||||
{
|
||||
this.Add(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Device camera)
|
||||
{
|
||||
if (this._list.Any(o => o.Key == camera.Number))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var needAuth = camera.Data.FirstOrDefault(o => o.Key == "NeedAuth").Value == "是";
|
||||
var hasAuth = camera.Data.FirstOrDefault(o => o.Key == "HasAuth").Value == "是";
|
||||
var mainStreamUri = camera.Data.FirstOrDefault(o => o.Key == "MainStreamUri").Value;
|
||||
var mainRtspUrl = $"rtsp://{(needAuth ? $"{camera.UserName}:{camera.Password}@" : "")}{mainStreamUri.Substring(7)}";
|
||||
var subStreamUri = camera.Data.FirstOrDefault(o => o.Key == "SubStreamUri").Value;
|
||||
var subRtspUrl = $"rtsp://{(needAuth ? $"{camera.UserName}:{camera.Password}@" : "")}{subStreamUri.Substring(7)}";
|
||||
var fileName = $"ffmpeg-{Helper.Instance.GetRunTime()}{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "")}";
|
||||
var file = Path.Combine(this._env.WebRootPath, fileName);
|
||||
var mainRtmp = camera.Data.FirstOrDefault(o => o.Key == "mainrtmp").Value;
|
||||
var subRtmp = camera.Data.FirstOrDefault(o => o.Key == "subrtmp").Value;
|
||||
var customFile = camera.GetData("CustomFile")?.Value;
|
||||
if (!string.IsNullOrEmpty(customFile))
|
||||
{
|
||||
file = customFile;
|
||||
}
|
||||
Console.WriteLine(file);
|
||||
var arguments = camera.Data.FirstOrDefault(o => o.Key == "ffmpeg.args").Value;
|
||||
Process main = null, sub = null;
|
||||
if (!string.IsNullOrEmpty(mainStreamUri))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(mainRtmp))
|
||||
{
|
||||
main = this.SetProcess(file, string.Format(arguments, Environment.ProcessorCount, mainRtspUrl, mainRtmp));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(subRtmp))
|
||||
{
|
||||
sub = this.SetProcess(file, string.Format(arguments, Environment.ProcessorCount, subRtspUrl, subRtmp));
|
||||
}
|
||||
}
|
||||
if (this._list.TryAdd(camera.Number, (camera, main, sub)))
|
||||
{
|
||||
Console.WriteLine($"add {camera.Number} to list");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (main != null)
|
||||
{
|
||||
this.CloseProcess(main);
|
||||
this.CloseProcess(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
var item = this._list[key];
|
||||
this.CloseProcess(item.local);
|
||||
this.CloseProcess(item.remote);
|
||||
if (this._list.TryRemove(key, out item))
|
||||
{
|
||||
Console.WriteLine($"remove {key} from list");
|
||||
}
|
||||
}
|
||||
|
||||
private Process SetProcess(string file, string arguments)
|
||||
{
|
||||
Console.WriteLine(file);
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
WorkingDirectory = this._env.WebRootPath,
|
||||
FileName = file,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardError = true
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
};
|
||||
process.Exited += (s, e) =>
|
||||
{
|
||||
var _process = s as Process;
|
||||
Console.WriteLine($"list:{_list.Count},exit:{_process.ExitCode},args:{arguments}");
|
||||
if (_process != null)
|
||||
{
|
||||
Thread.Sleep(10 * 1000);
|
||||
_process.CancelErrorRead();
|
||||
_process.Start();
|
||||
_process.BeginErrorReadLine();
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += (s, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
//Console.WriteLine(e.Data);
|
||||
if (e.Data.IndexOf("forcing output") > -1)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
}
|
||||
};
|
||||
Console.WriteLine(arguments);
|
||||
process.Start();
|
||||
process.BeginErrorReadLine();
|
||||
return process;
|
||||
}
|
||||
|
||||
private void CloseProcess(Process process)
|
||||
{
|
||||
if (process != null)
|
||||
{
|
||||
process.EnableRaisingEvents = false;
|
||||
try
|
||||
{
|
||||
process.Kill();
|
||||
process.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetOnoce(string deviceUrl)
|
||||
{
|
||||
var message = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
||||
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
||||
<GetDeviceInformation xmlns=""http://www.onvif.org/ver10/device/wsdl""></GetDeviceInformation>
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{Template.GetDeviceInformationAction}\"");
|
||||
var task = hc.PostAsync(deviceUrl, new StringContent(message));
|
||||
var result = task.Result.Headers.WwwAuthenticate;
|
||||
return Regex.Match(result.ToString(), "nonce=\"([^\"]+)\"").Groups[1].Value;
|
||||
}
|
||||
|
||||
private string RequestXml(string url, string action, string body, string userName, string password, string onoce)
|
||||
{
|
||||
var nonce_b = Convert.FromBase64String(onoce);
|
||||
var now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");
|
||||
var creationtime_b = Encoding.ASCII.GetBytes(now);
|
||||
var password_b = Encoding.ASCII.GetBytes(password);
|
||||
var concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
|
||||
Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
|
||||
Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
|
||||
Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
|
||||
var sha = new SHA1CryptoServiceProvider();
|
||||
var pdresult = sha.ComputeHash(concatenation_b);
|
||||
var passworddigest = Convert.ToBase64String(pdresult);
|
||||
var message = string.Format(Template.AuthTemplate, userName, passworddigest, Convert.ToBase64String(nonce_b), now, body);
|
||||
var result = SoapRequest(url, action, message);
|
||||
return result;
|
||||
}
|
||||
|
||||
private string SoapRequest(string url, string action, string message)
|
||||
{
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{action}\"");
|
||||
var task = hc.PostAsync(url, new StringContent(message));
|
||||
var result = task.Result.Content.ReadAsStringAsync().Result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void ZoomIn(string id, float speed)
|
||||
{
|
||||
this.Move(id, speed, 0, 0);
|
||||
}
|
||||
|
||||
public void ZoomOut(string id, float speed)
|
||||
{
|
||||
this.Move(id, -speed, 0, 0);
|
||||
}
|
||||
|
||||
public void Up(string id, float speed)
|
||||
{
|
||||
this.Move(id, 0, 0, speed);
|
||||
}
|
||||
|
||||
public void Right(string id, float speed)
|
||||
{
|
||||
this.Move(id, 0, speed, 0);
|
||||
}
|
||||
|
||||
public void Down(string id, float speed)
|
||||
{
|
||||
this.Move(id, 0, 0, -speed);
|
||||
}
|
||||
|
||||
public void Left(string id, float speed)
|
||||
{
|
||||
this.Move(id, 0, -speed, 0);
|
||||
}
|
||||
|
||||
public void Stop(string id)
|
||||
{
|
||||
var camera = this.GetCamera(id);
|
||||
if (camera != null)
|
||||
{
|
||||
var ptzAddress = camera.GetDataValue("PtzAddress");
|
||||
if (!string.IsNullOrEmpty(ptzAddress))
|
||||
{
|
||||
var deviceUrl = camera.GetDataValue("DeviceUrl");
|
||||
RequestXml(ptzAddress, Template.StopAction, String.Format(Template.StopMessage, camera.GetDataValue("MainToken"), true, true), camera.UserName, camera.Password, GetOnoce(deviceUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(string id, float zx, float px, float py)
|
||||
{
|
||||
var camera = this.GetCamera(id);
|
||||
if (camera != null)
|
||||
{
|
||||
var ptzAddress = camera.GetDataValue("PtzAddress");
|
||||
if (!string.IsNullOrEmpty(ptzAddress))
|
||||
{
|
||||
var deviceUrl = camera.GetDataValue("DeviceUrl");
|
||||
RequestXml(ptzAddress, Template.ContinuousMoveAction, String.Format(Template.ContinuousMoveMessage, camera.GetDataValue("MainToken"), zx, px, py), camera.UserName, camera.Password, GetOnoce(deviceUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ScreenShot(string id)
|
||||
{
|
||||
var camera = this.GetCamera(id);
|
||||
var url = camera.GetDataValue("SnapshotUri");
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
if (camera.GetDataValue("NeedAuth") == "否")
|
||||
{
|
||||
return hc.GetByteArrayAsync(url).Result;
|
||||
}
|
||||
return hc.GetByteDigest(url, camera.UserName, camera.Password);
|
||||
}
|
||||
|
||||
private Device GetCamera(string number)
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
return repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public interface IOnvifDeviceManagement
|
||||
{
|
||||
List<IPCamera> Discovery();
|
||||
|
||||
string GetCapabilities(string deviceUrl);
|
||||
|
||||
string GetProfiles(string deviceUrl, string mediaUrl);
|
||||
|
||||
string GetProfiles(string deviceUrl, string mediaUrl, string userName, string password);
|
||||
|
||||
string GetStreamUri(string deviceUrl, string mediaUrl, string token);
|
||||
|
||||
string GetStreamUri(string deviceUrl, string mediaUrl, string userName, string password, string token);
|
||||
|
||||
string GetSnapshotUri(string deviceUrl, string mediaUrl, string token);
|
||||
|
||||
string GetSnapshotUri(string deviceUrl, string mediaUrl, string userName, string password, string token);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class IPCamera
|
||||
{
|
||||
public string DiscoveryXml { get; set; }
|
||||
public string GetCapabilitiesXml { get; set; }
|
||||
public string DeviceUrl { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string MediaUrl { get; set; }
|
||||
public string GetProfilesXml { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string PTZAddress { get; set; }
|
||||
public bool Ptz3DZoomSupport { get; set; }
|
||||
public List<Profile> Profiles { get; set; } = new List<Profile>();
|
||||
public string MainStreamUriXml { get; set; }
|
||||
public string MainSnapshotUriXml { get; set; }
|
||||
public string SubStreamUriXml { get; set; }
|
||||
public string SubSnapshotUriXml { get; set; }
|
||||
public string MainStreamUri { get; set; }
|
||||
public string SubStreamUri { get; set; }
|
||||
public string MainSnapshotUri { get; set; }
|
||||
public string SubSnapshotUri { get; set; }
|
||||
|
||||
public void ParseDiscovery()
|
||||
{
|
||||
var doc = XDocument.Parse(this.DiscoveryXml);
|
||||
this.DeviceUrl = doc.Descendants().FirstOrDefault(o => o.Name.LocalName == "XAddrs").Value.Split(' ')[0];
|
||||
this.Id = doc.Descendants()
|
||||
.FirstOrDefault(o => o.Name.LocalName == "EndpointReference").Elements()
|
||||
.FirstOrDefault(o => o.Name.LocalName == "Address").Value.Replace("urn:uuid:", "").Replace("-", "");
|
||||
}
|
||||
|
||||
public void ParseCapabilities()
|
||||
{
|
||||
var doc = XDocument.Parse(this.GetCapabilitiesXml);
|
||||
this.MediaUrl = doc.Descendants().FirstOrDefault(o => o.Name.LocalName == "Media").Elements().FirstOrDefault(o => o.Name.LocalName == "XAddr").Value;
|
||||
this.PTZAddress = doc.Descendants().FirstOrDefault(o => o.Name.LocalName == "PTZ")?.Elements().FirstOrDefault(o => o.Name.LocalName == "XAddr")?.Value;
|
||||
this.Ptz3DZoomSupport = string.IsNullOrWhiteSpace(this.PTZAddress) ? false : true;
|
||||
}
|
||||
|
||||
public void ParseProfiles()
|
||||
{
|
||||
var doc = XDocument.Parse(this.GetProfilesXml);
|
||||
foreach (var item in doc.Descendants().Where(o => o.Name.LocalName == "Profiles"))
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
Token = item.Attribute("token").Value,
|
||||
Name = item.Elements().FirstOrDefault(o => o.Name.LocalName == "Name").Value
|
||||
};
|
||||
var videoEncoderConfiguration = item.Elements().FirstOrDefault(o => o.Name.LocalName == "VideoEncoderConfiguration");
|
||||
profile.Encoding = videoEncoderConfiguration.Elements().FirstOrDefault(o => o.Name.LocalName == "Encoding").Value;
|
||||
var resolution = videoEncoderConfiguration.Elements().FirstOrDefault(o => o.Name.LocalName == "Resolution");
|
||||
profile.Width = Convert.ToInt32(resolution.Elements().FirstOrDefault(o => o.Name.LocalName == "Width").Value);
|
||||
profile.Height = Convert.ToInt32(resolution.Elements().FirstOrDefault(o => o.Name.LocalName == "Height").Value);
|
||||
this.Profiles.Add(profile);
|
||||
}
|
||||
}
|
||||
|
||||
public void ParseStreamUri()
|
||||
{
|
||||
this.MainStreamUri = WebUtility.HtmlDecode(this.RegexMatch(this.MainStreamUriXml, @"[^<>]*", @"<tt:Uri>", @"</tt:Uri>"));
|
||||
this.SubStreamUri = WebUtility.HtmlDecode(this.RegexMatch(this.SubStreamUriXml, @"[^<>]*", @"<tt:Uri>", @"</tt:Uri>"));
|
||||
}
|
||||
|
||||
public void ParseSnapshotUri()
|
||||
{
|
||||
this.MainSnapshotUri = WebUtility.HtmlDecode(this.RegexMatch(this.MainSnapshotUriXml, @"[^<>]*", @"<tt:Uri>", @"</tt:Uri>"));
|
||||
this.SubSnapshotUri = WebUtility.HtmlDecode(this.RegexMatch(this.SubSnapshotUriXml, @"[^<>]*", @"<tt:Uri>", @"</tt:Uri>"));
|
||||
}
|
||||
|
||||
private string RegexMatch(string input, string pattern, string prefix, string suffix)
|
||||
{
|
||||
return Regex.Match(input, $"(?<={prefix}){pattern}(?={suffix})").Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Infrastructure.Extensions;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class OnvifDeviceManagement : IOnvifDeviceManagement
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly object thisLock = new object();
|
||||
|
||||
public OnvifDeviceManagement(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
this._httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
public List<IPCamera> Discovery()
|
||||
{
|
||||
Console.WriteLine("search onvif devices...");
|
||||
var list = new ConcurrentBag<string>();
|
||||
var ips = NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
|
||||
.Select(nic => nic.GetIPProperties().UnicastAddresses)
|
||||
.SelectMany(o => o.ToList())
|
||||
.Select(o => o.Address)
|
||||
.Where(o => o.AddressFamily == AddressFamily.InterNetwork)
|
||||
.ToList();
|
||||
foreach (var ip in ips)
|
||||
{
|
||||
Console.WriteLine($"search:{ip}");
|
||||
lock (thisLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
using (var client = new UdpClient(new IPEndPoint(ip, 0)))
|
||||
{
|
||||
var probeMessage = string.Format(Template.GetServiceRequestTemplage, Guid.NewGuid());
|
||||
var message = Encoding.UTF8.GetBytes(probeMessage);
|
||||
client.Send(message, message.Length, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 3702));
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var ep = new IPEndPoint(IPAddress.Any, 3702);
|
||||
while (!tokenSource.IsCancellationRequested)
|
||||
{
|
||||
if (client.Available > 0)
|
||||
{
|
||||
var buffer = client.Receive(ref ep);
|
||||
var result = Encoding.UTF8.GetString(buffer);
|
||||
if (!list.Any(o => o == result))
|
||||
{
|
||||
list.Add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}, tokenSource.Token);
|
||||
Thread.Sleep(1000);
|
||||
tokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
var cameras = new List<IPCamera>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
var camera = new IPCamera { DiscoveryXml = item };
|
||||
try
|
||||
{
|
||||
camera.ParseDiscovery();
|
||||
camera.GetCapabilitiesXml = GetCapabilities(camera.DeviceUrl);
|
||||
camera.ParseCapabilities();
|
||||
cameras.Add(camera);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
return cameras;
|
||||
}
|
||||
|
||||
public string GetCapabilities(string deviceUrl)
|
||||
{
|
||||
return SoapRequest(deviceUrl, Template.GetCapabilitiesAction, Template.GetCapabilitiesMessage);
|
||||
}
|
||||
|
||||
public string GetProfiles(string deviceUrl, string mediaUrl)
|
||||
{
|
||||
return SoapRequest(mediaUrl, Template.GetProfilesAction, string.Format(Template.Templage, Template.GetProfilesMessageBody));
|
||||
}
|
||||
|
||||
public string GetProfiles(string deviceUrl, string mediaUrl, string userName, string password)
|
||||
{
|
||||
return RequestXml(mediaUrl, Template.GetProfilesAction, Template.GetProfilesMessageBody, userName, password, GetOnoce(deviceUrl));
|
||||
}
|
||||
|
||||
public string GetStreamUri(string deviceUrl, string mediaUrl, string token)
|
||||
{
|
||||
return SoapRequest(mediaUrl, Template.GetStreamUriAction, string.Format(Template.Templage, String.Format(Template.GetStreamUriMessage, token)));
|
||||
}
|
||||
|
||||
public string GetStreamUri(string deviceUrl, string mediaUrl, string userName, string password, string token)
|
||||
{
|
||||
return RequestXml(mediaUrl, Template.GetStreamUriAction, String.Format(Template.GetStreamUriMessage, token), userName, password, GetOnoce(deviceUrl));
|
||||
}
|
||||
|
||||
public string GetSnapshotUri(string deviceUrl, string mediaUrl, string token)
|
||||
{
|
||||
return SoapRequest(mediaUrl, Template.GetSnapshotUriAction, string.Format(Template.Templage, String.Format(Template.GetSnapshotUriMessage, token)));
|
||||
}
|
||||
|
||||
public string GetSnapshotUri(string deviceUrl, string mediaUrl, string userName, string password, string token)
|
||||
{
|
||||
return RequestXml(mediaUrl, Template.GetSnapshotUriAction, String.Format(Template.GetSnapshotUriMessage, token), userName, password, GetOnoce(deviceUrl));
|
||||
}
|
||||
|
||||
private string SoapRequest(string url, string action, string message)
|
||||
{
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{action}\"");
|
||||
var task = hc.PostAsync(url, new StringContent(message));
|
||||
var result = task.Result;
|
||||
var content = result.Content.ReadAsStringAsync().Result;
|
||||
return result.StatusCode == HttpStatusCode.OK ? content : "";
|
||||
}
|
||||
|
||||
private string RequestXml(string url, string action, string body, string userName, string password, string onoce)
|
||||
{
|
||||
var nonce_b = Convert.FromBase64String(onoce);
|
||||
var now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddThh:mm:ss.fffZ");
|
||||
var creationtime_b = Encoding.ASCII.GetBytes(now);
|
||||
var password_b = Encoding.ASCII.GetBytes(password);
|
||||
var concatenation_b = new byte[nonce_b.Length + creationtime_b.Length + password_b.Length];
|
||||
Buffer.BlockCopy(nonce_b, 0, concatenation_b, 0, nonce_b.Length);
|
||||
Buffer.BlockCopy(creationtime_b, 0, concatenation_b, nonce_b.Length, creationtime_b.Length);
|
||||
Buffer.BlockCopy(password_b, 0, concatenation_b, nonce_b.Length + creationtime_b.Length, password_b.Length);
|
||||
var sha = new SHA1CryptoServiceProvider();
|
||||
var pdresult = sha.ComputeHash(concatenation_b);
|
||||
var passworddigest = Convert.ToBase64String(pdresult);
|
||||
var message = string.Format(Template.AuthTemplate, userName, passworddigest, Convert.ToBase64String(nonce_b), now, body);
|
||||
var result = SoapRequest(url, action, message);
|
||||
return result;
|
||||
}
|
||||
|
||||
private string GetOnoce(string deviceUrl)
|
||||
{
|
||||
var message = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
||||
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
||||
<GetDeviceInformation xmlns=""http://www.onvif.org/ver10/device/wsdl""></GetDeviceInformation>
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
var hc = this._httpClientFactory.CreateClient();
|
||||
hc.DefaultRequestHeaders.Add("ContentType", $"application/soap+xml; charset=utf-8; action=\"{Template.GetDeviceInformationAction}\"");
|
||||
var task = hc.PostAsync(deviceUrl, new StringContent(message));
|
||||
var result = task.Result.Headers.WwwAuthenticate;
|
||||
return Regex.Match(result.ToString(), "nonce=\"([^\"]+)\"").Groups[1].Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class Template
|
||||
{
|
||||
public const string GetServiceRequestTemplage = @"<s:Envelope
|
||||
xmlns:s=""http://www.w3.org/2003/05/soap-envelope""
|
||||
xmlns:a=""http://schemas.xmlsoap.org/ws/2004/08/addressing"">
|
||||
<s:Header>
|
||||
<a:Action s:mustUnderstand=""1"">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>
|
||||
<a:MessageID>urn:uuid:{0}</a:MessageID>
|
||||
<a:ReplyTo>
|
||||
<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
|
||||
</a:ReplyTo>
|
||||
<a:To s:mustUnderstand=""1"">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>
|
||||
</s:Header>
|
||||
<s:Body>
|
||||
<Probe
|
||||
xmlns=""http://schemas.xmlsoap.org/ws/2005/04/discovery"">
|
||||
<d:Types
|
||||
xmlns:d=""http://schemas.xmlsoap.org/ws/2005/04/discovery""
|
||||
xmlns:dp0=""http://www.onvif.org/ver10/device/wsdl"">dp0:Device
|
||||
</d:Types>
|
||||
</Probe>
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
|
||||
public const string GetCapabilitiesAction = "http://www.onvif.org/ver10/device/wsdl/GetCapabilities";
|
||||
|
||||
public const string GetCapabilitiesMessage = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
||||
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
||||
<GetCapabilities xmlns=""http://www.onvif.org/ver10/device/wsdl"">
|
||||
<Category>All</Category>
|
||||
</GetCapabilities>
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
|
||||
public const string GetProfilesAction = "http://www.onvif.org/ver10/media/wsdlGetProfiles/";
|
||||
public const string GetProfilesMessageBody = @"<GetProfiles xmlns=""http://www.onvif.org/ver10/media/wsdl""></GetProfiles>";
|
||||
|
||||
public const string GetStreamUriAction = "http://www.onvif.org/ver10/media/wsdl/GetStreamUri";
|
||||
|
||||
public const string GetStreamUriMessage = @"<GetStreamUri xmlns=""http://www.onvif.org/ver10/media/wsdl"">
|
||||
<StreamSetup>
|
||||
<Stream xmlns=""http://www.onvif.org/ver10/schema"">RTP-Unicast</Stream>
|
||||
<Transport xmlns=""http://www.onvif.org/ver10/schema"">
|
||||
<Protocol>RTSP</Protocol>
|
||||
</Transport>
|
||||
</StreamSetup>
|
||||
<ProfileToken>{0}</ProfileToken>
|
||||
</GetStreamUri>";
|
||||
|
||||
public const string GetDeviceInformationAction = "http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation";
|
||||
|
||||
public const string Templage = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
||||
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
||||
{0}
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
|
||||
public const string AuthTemplate = @"<s:Envelope xmlns:s=""http://www.w3.org/2003/05/soap-envelope"">
|
||||
<s:Header>
|
||||
<Security xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" s:mustUnderstand=""1"">
|
||||
<UsernameToken>
|
||||
<Username>{0}</Username>
|
||||
<Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">{1}</Password>
|
||||
<Nonce EncodingType=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"">{2}</Nonce>
|
||||
<Created xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">{3}</Created>
|
||||
</UsernameToken>
|
||||
</Security>
|
||||
</s:Header>
|
||||
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
||||
{4}
|
||||
</s:Body>
|
||||
</s:Envelope>";
|
||||
|
||||
public const string GetSnapshotUriAction = "http://www.onvif.org/ver10/media/wsdl/GetSnapshotUri";
|
||||
|
||||
public const string GetSnapshotUriMessage = @"<GetSnapshotUri xmlns=""http://www.onvif.org/ver10/media/wsdl"">
|
||||
<ProfileToken>{0}</ProfileToken>
|
||||
</GetSnapshotUri>";
|
||||
|
||||
public const string ContinuousMoveAction = "http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove";
|
||||
|
||||
public const string ContinuousMoveMessage = @"<ContinuousMove xmlns=""http://www.onvif.org/ver20/ptz/wsdl"">
|
||||
<ProfileToken>{0}</ProfileToken>
|
||||
<Velocity>
|
||||
<Zoom xmlns=""http://www.onvif.org/ver10/schema"" x=""{1}""></Zoom>
|
||||
<PanTilt x=""{2}"" y=""{3}"" xmlns=""http://www.onvif.org/ver10/schema""></PanTilt>
|
||||
</Velocity>
|
||||
</ContinuousMove>";
|
||||
|
||||
public const string StopAction = "http://www.onvif.org/ver20/ptz/wsdl/Stop";
|
||||
public const string StopMessage = @"<Stop xmlns=""http://www.onvif.org/ver20/ptz/wsdl""><ProfileToken>{0}</ProfileToken><PanTilt>true</PanTilt><Zoom>true</Zoom></Stop>";
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
using Infrastructure.Application;
|
||||
using Infrastructure.Configuration;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Hosting;
|
||||
using Microsoft.AspNetCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = "localhost";
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.Run<Startup>(new List<EFConfigurationValue> {
|
||||
new EFConfigurationValue { Id = "openapi.title", Value= "web api" },
|
||||
new EFConfigurationValue { Id = "openapi.version", Value= "1.0" },
|
||||
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
|
||||
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
|
||||
new EFConfigurationValue { Id = "email:host", Value= "nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:port", Value= "25"},
|
||||
new EFConfigurationValue { Id = "email:user", Value= "admin@nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:password", Value= "aA123456"},
|
||||
new EFConfigurationValue { Id = "server.urls", Value= "http://*:8004" },
|
||||
new EFConfigurationValue { Id = "notify:enabled", Value= "false"},
|
||||
new EFConfigurationValue { Id = "notify:host", Value= $"{host}:8001"},
|
||||
new EFConfigurationValue { Id = "timer.seconds", Value="600"},
|
||||
new EFConfigurationValue { Id = "connectId", Value= Guid.NewGuid().ToBase62() },
|
||||
new EFConfigurationValue { Id = "node.number", Value= "所属节点编号" },
|
||||
new EFConfigurationValue { Id = "onvif.timer", Value="1"},
|
||||
new EFConfigurationValue { Id = "onvif.speed", Value="0.2"},
|
||||
new EFConfigurationValue { Id = "camera.usr", Value="admin"},
|
||||
new EFConfigurationValue { Id = "camera.pwd", Value="lg123456"},
|
||||
new EFConfigurationValue { Id = "stream.rtmp", Value=host},
|
||||
new EFConfigurationValue { Id = "stream.flv", Value=$"{host}:8080"},
|
||||
new EFConfigurationValue { Id = "stream.hls", Value=$"{host}:8080"},
|
||||
new EFConfigurationValue { Id = "ffmpeg.args", Value=" -y -threads {0} -rtsp_transport tcp -use_wallclock_as_timestamps 1 -stimeout 3000000 -i \"{1}\" -fflags +genpts -c copy -f flv \"{2}\""},
|
||||
new EFConfigurationValue { Id = "ffmpeg.file", Value="/usr/ffmpeg-rkmp/bin/ffmpeg"},
|
||||
//
|
||||
new EFConfigurationValue { Id = "name", Value= "ONVIF服务"},
|
||||
new EFConfigurationValue { Id = "logo", Value= "/images/logo.png",Type= InputType.ImageUrl},
|
||||
new EFConfigurationValue { Id = "copyright", Value= "Copyright © {now} Company. All rights reserved",Type= InputType.Html}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:8004/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"OnvifService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://127.0.0.1:8004/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using IoT.Shared.Infrastructure;
|
||||
using IoT.UI.Shard;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ONVIFService
|
||||
{
|
||||
public class Startup : IoTServiceStartup
|
||||
{
|
||||
public Startup(IConfiguration configuration, IHostingEnvironment env) : base(configuration, env)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ClientService>();
|
||||
services.AddSingleton<DeviceService>();
|
||||
base.ConfigureServices(services);
|
||||
}
|
||||
|
||||
public override void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
base.Configure(app, env, loggerFactory);
|
||||
app.ApplicationServices.GetService<DeviceService>().Start();
|
||||
app.ApplicationServices.GetService<ClientService>().Start();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="@GetClass("Home")">
|
||||
<a href="@Url.Action("Index","Home")">
|
||||
首页
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/swagger/index.html">
|
||||
Open API
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@functions{
|
||||
public string GetClass(params string[] controllers)
|
||||
{
|
||||
if (controllers.Select(o => o.ToLower()).Contains(this.ViewContext.RouteData.Values["controller"].ToString().ToLower()))
|
||||
{
|
||||
if (controllers.Length > 1)
|
||||
{
|
||||
return "active open";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
@inherits Infrastructure.Web.Mvc.Razor.MyRazorPage<TModel>
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Infrastructure.Application
|
||||
@using Infrastructure.Web
|
||||
@using Infrastructure.Web.DataAnnotations
|
||||
@using Infrastructure.Extensions
|
||||
@using Infrastructure.Data
|
||||
@using Application.Domain.Entities
|
||||
@using Application.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,3 +0,0 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0-beta.108",
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"database.mysql.connection": "Server=127.0.0.1;Port=3306;Database=iotnode;Uid=root;Pwd=root;",
|
||||
"database.sqlite.connection": "Data Source=data.db"
|
||||
},
|
||||
"AppSettings": {
|
||||
"database": "sqlite",
|
||||
"UseCookieSessionStore": false
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,52 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>flvjsdemo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<input id="url" type="text" value="http://192.168.3.2:8080/live/b57e867ae29d11b483864cbd8fd0f747.flv" placeholder="url" style="width:80%;" /><button id="btn">播放</button>
|
||||
</div>
|
||||
<video id="videoElement" muted controls autoplay> style="width:80%;"></video>
|
||||
<script>
|
||||
var flvPlayer;
|
||||
document.getElementById('btn').addEventListener('click', function () {
|
||||
if (flvjs.isSupported()) {
|
||||
var videoElement = document.getElementById('videoElement');
|
||||
if (flvPlayer) {
|
||||
flvPlayer.unload();
|
||||
flvPlayer.detachMediaElement();
|
||||
flvPlayer.destroy();
|
||||
flvPlayer = null;
|
||||
}
|
||||
flvPlayer = flvjs.createPlayer({
|
||||
type: 'flv',
|
||||
url: document.getElementById('url').value,
|
||||
isLive: true,
|
||||
cors: true
|
||||
}, {
|
||||
isLive: true,
|
||||
fixAudioTimestampGap: false,
|
||||
enableWorker: true,
|
||||
enableStashBuffer: false,
|
||||
stashInitialSize: 1,
|
||||
//lazyLoad: false,
|
||||
//lazyLoadMaxDuration: 1,
|
||||
//lazyLoadRecoverDuration: 1,
|
||||
deferLoadAfterSourceOpen: false,
|
||||
//autoCleanupMaxBackwardDuration: 1,
|
||||
//autoCleanupMinBackwardDuration: 1,
|
||||
//statisticsInfoReportInterval: 1,
|
||||
});
|
||||
flvPlayer.attachMediaElement(videoElement);
|
||||
flvPlayer.load();
|
||||
}
|
||||
else {
|
||||
alert('不支持flv格式');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script src="/lib/flv.js/flv.min.js"></script>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
@ -1,16 +0,0 @@
|
||||
*.bak
|
||||
*.suo
|
||||
*.db
|
||||
*.user
|
||||
.vs/
|
||||
obj
|
||||
Obj
|
||||
bin
|
||||
Bin
|
||||
debug
|
||||
Debug
|
||||
release
|
||||
Release
|
||||
Logs
|
||||
logs
|
||||
node_modules
|
@ -1,15 +0,0 @@
|
||||
using Infrastructure.Domain;
|
||||
|
||||
namespace Application.Domain.Entities
|
||||
{
|
||||
public class Button : BaseEntity
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string SerialPort { get; set; }
|
||||
public int Baud { get; set; }
|
||||
public int Data { get; set; }
|
||||
public int Partity { get; set; }
|
||||
public int StopBits { get; set; }
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Infrastructure.Application;
|
||||
|
||||
namespace SPService.Applicaiton.Models
|
||||
{
|
||||
[Display(Name = "指令")]
|
||||
public class EditButtonModel : EditModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "消息")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "串口")]
|
||||
public string SerialPort { get; set; }
|
||||
|
||||
[Required]
|
||||
[Display(Name = "波特率")]
|
||||
public int Baud { get; set; } = 9600;
|
||||
|
||||
[Required]
|
||||
[Display(Name = "数据位")]
|
||||
public int Data { get; set; } = 8;
|
||||
|
||||
[Required]
|
||||
[Display(Name = "停止位")]
|
||||
public int StopBits { get; set; } = 0;
|
||||
|
||||
[Required]
|
||||
[Display(Name = "校验位")]
|
||||
public int Partity { get; set; } = 0;
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System.Linq;
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using IoTShared.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DataController : CrudController<Data, DataSearchModel, EditDataModel, EditDataModel>
|
||||
{
|
||||
private readonly AjaxController _ajax;
|
||||
|
||||
public DataController(IRepository<Data> repo, AjaxController ajax) : base(repo)
|
||||
{
|
||||
this._ajax = ajax;
|
||||
}
|
||||
|
||||
public override IQueryable<Data> Query(DataSearchModel model, IQueryable<Data> query)
|
||||
{
|
||||
ViewData.SelectList(o => model.NodeId, () => this._ajax.GetNodeSelectList(model.NodeId));
|
||||
ViewData.SelectList(o => model.DeviceId, () => this._ajax.GetDeviceSelectList(model.NodeId.Value, model.DeviceId), model.NodeId.HasValue);
|
||||
return query.WhereIf(model.NodeId.HasValue, o => o.Device.NodeId == model.NodeId.Value)
|
||||
.WhereIf(model.DeviceId.HasValue, o => o.DeviceId == model.DeviceId.Value)
|
||||
.WhereIf(!string.IsNullOrEmpty(model.Keyword), o => o.Name.Contains(model.Keyword));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IoTCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class DeviceController : CrudController<Device, DeviceSearchMode, EditDeviceModel, EditDeviceModel>
|
||||
{
|
||||
private readonly IConfiguration _cfg;
|
||||
private readonly IRepository<product> _productRepo;
|
||||
|
||||
public DeviceController(IConfiguration cfg, IRepository<product> productRepo, IRepository<Device> repo) : base(repo)
|
||||
{
|
||||
this._cfg = cfg;
|
||||
this._productRepo = productRepo;
|
||||
}
|
||||
|
||||
public override IActionResult Add()
|
||||
{
|
||||
var model = new EditDeviceModel
|
||||
{
|
||||
CategoryNumber = "20",
|
||||
InfoNumber = "serialport",
|
||||
ConnectId = this._cfg["ConnectId"],
|
||||
Number = Guid.NewGuid().ToBase62(),
|
||||
NodeNumber = this._cfg["node.number"]
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
public override void ToEntity(EditDeviceModel model, Device entity)
|
||||
{
|
||||
if (!this.repo.ReadOnlyTable().Any(o => o.Id == model.Id))
|
||||
{
|
||||
entity.ProductId = this._productRepo.ReadOnlyTable().First().Id;
|
||||
entity.AddorUpdateData("SerialPort", "", DeviceDataType.String, "串口", hidden: true);
|
||||
entity.AddorUpdateData("Baud", "9600", DeviceDataType.Int, "波特率", hidden: true);
|
||||
entity.AddorUpdateData("Partity", "0", DeviceDataType.Int, "校验位", hidden: true);
|
||||
entity.AddorUpdateData("DataBits", "8", DeviceDataType.Int, "数据位", hidden: true);
|
||||
entity.AddorUpdateData("StopBits", "1", DeviceDataType.Int, "停止位", hidden: true);
|
||||
entity.AddorUpdateData("Buttons", new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("测试按键", "11111111") }.ToJson(), DeviceDataType.SelectList, "按键");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace UserCenter.Areas.Admin.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Area(nameof(Admin))]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public HomeController()
|
||||
{
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
@{
|
||||
ViewData["IsHomePage"] = true;
|
||||
}
|
||||
<h1>首页</h1>
|
@ -1,52 +0,0 @@
|
||||
<section class="sidebar" style="height: auto;">
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
<li class="@GetClass("Home")"><a href="@Url.Action("Index","Home")"><i class="fa fa-circle-o"></i><span>首页</span></a></li>
|
||||
<li class="@GetClass("Configuration")"><a href="@Url.Action("Index","Configuration")"><i class="fa fa-circle-o"></i><span>网站配置</span></a></li>
|
||||
<li class="treeview @GetClass("User","Role","Permission")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>权限管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("User")"><a href="@Url.Action("Index","User")"><i class="fa fa-circle-o"></i><span>用户管理</span></a></li>
|
||||
<li class="@GetClass("Role")"><a href="@Url.Action("Index","Role")"><i class="fa fa-circle-o"></i><span>角色管理</span></a></li>
|
||||
<li class="@GetClass("Permission")"><a href="@Url.Action("Index","Permission")"><i class="fa fa-circle-o"></i><span>权限管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="treeview @GetClass("Node","Device","Data","Api","Parameter","Scene","Command")">
|
||||
<a href="javascript:;" class="dropdown-toggle">
|
||||
<i class="fa fa-list"></i>
|
||||
<span>设备管理</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="@GetClass("Node")"><a href="@Url.Action("Index","Node")"><i class="fa fa-circle-o"></i><span>节点管理</span></a></li>
|
||||
<li class="@GetClass("Device")"><a href="@Url.Action("Index","Device")"><i class="fa fa-circle-o"></i><span>设备管理</span></a></li>
|
||||
<li class="@GetClass("Data")"><a href="@Url.Action("Index","Data")"><i class="fa fa-circle-o"></i><span>数据管理</span></a></li>
|
||||
<li class="@GetClass("Api")"><a href="@Url.Action("Index","Api")"><i class="fa fa-circle-o"></i><span>接口管理</span></a></li>
|
||||
<li class="@GetClass("Parameter")"><a href="@Url.Action("Index","Parameter")"><i class="fa fa-circle-o"></i><span>参数管理</span></a></li>
|
||||
<li class="@GetClass("Scene")"><a href="@Url.Action("Index","Scene")"><i class="fa fa-circle-o"></i><span>场景管理</span></a></li>
|
||||
<li class="@GetClass("Command")"><a href="@Url.Action("Index","Command")"><i class="fa fa-circle-o"></i><span>命令管理</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
@functions{
|
||||
public string GetClass(params string[] controllers)
|
||||
{
|
||||
if (controllers.Select(o => o.ToLower()).Contains(this.ViewContext.RouteData.Values["controller"].ToString().ToLower()))
|
||||
{
|
||||
if (controllers.Length > 1)
|
||||
{
|
||||
return "active open";
|
||||
}
|
||||
return "active";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<script>
|
||||
function clear() {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
$(arguments[i]).find('option').not('[value=""]').remove();
|
||||
}
|
||||
}
|
||||
function update(url, id) {
|
||||
$.getJSON(url, function (data) {
|
||||
$.each(data, function (i, v) {
|
||||
$(id).append('<option value="' + v.Value + '">' + v.Text + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
$(function () {
|
||||
$('#NodeId').change(function () {
|
||||
var id = $(this).find(':selected').val();
|
||||
clear('#DeviceId');
|
||||
if (id) {
|
||||
var url = '@Url.Action("GetDeviceJson", "Ajax")?parentId=' + encodeURI(id);
|
||||
update(url,'#DeviceId');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,7 +0,0 @@
|
||||
@inherits Infrastructure.Web.Mvc.Razor.MyRazorPage<TModel>
|
||||
@using Infrastructure.Application
|
||||
@using Infrastructure.Extensions
|
||||
@using Infrastructure.Data
|
||||
@using Application.Domain.Entities
|
||||
@using Application.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,3 +0,0 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SPService.Applicaiton.Models;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace SerialPortService.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly IRepository<Button> _cameraRepo;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly DeviceService _spService;
|
||||
|
||||
public HomeController(IHttpClientFactory httpClientFactory, DeviceService spService, IRepository<Button> cameraRepo)
|
||||
{
|
||||
this._cameraRepo = cameraRepo;
|
||||
this._httpClientFactory = httpClientFactory;
|
||||
this._spService = spService;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View(new EditButtonModel { Name = "test" });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult Index(EditButtonModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var button = new Button().From(model);
|
||||
this._spService.ExecInternal(button.SerialPort, button.Baud, button.Data, button.Partity, button.StopBits, button.Message);
|
||||
ViewBag.Result = "success";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
ModelState.AddModelError("", ex.Message);
|
||||
}
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
using Application.Domain.Entities;
|
||||
using Application.Models;
|
||||
using Infrastructure.Data;
|
||||
using Infrastructure.Extensions;
|
||||
using IoT.Shared.Infrastructure;
|
||||
using IoT.Shared.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using RJCP.IO.Ports;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SerialPortService
|
||||
{
|
||||
public class DeviceService : BaseDeviceService
|
||||
{
|
||||
public DeviceService(IServiceProvider applicationServices, IConfiguration configuration)
|
||||
: base(applicationServices, configuration)
|
||||
{
|
||||
}
|
||||
|
||||
#region impl interface
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var productNumber = "serialport";
|
||||
var productRepo = scope.ServiceProvider.GetService<IRepository<Product>>();
|
||||
var product = productRepo.Table().FirstOrDefault(o => o.Number == productNumber);
|
||||
if (product == null)
|
||||
{
|
||||
product = new Product
|
||||
{
|
||||
Number = productNumber,
|
||||
Name = "串口",
|
||||
ApiJson = this.GetApiJson("/SerialPort/")
|
||||
};
|
||||
OpenApiService.UpdateApi(product);
|
||||
productRepo.Add(product);
|
||||
productRepo.SaveChanges();
|
||||
}
|
||||
}
|
||||
});
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Notify();
|
||||
}
|
||||
|
||||
#endregion impl interface
|
||||
|
||||
public void Exec(string id, string code)
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
var device = repo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == id);
|
||||
var port = device.GetDataValue("SerialPort");
|
||||
var baud = Convert.ToInt32(device.GetDataValue("Baud"));
|
||||
var dataBits = Convert.ToInt32(device.GetDataValue("DataBits"));
|
||||
var partity = Convert.ToInt32(device.GetDataValue("Partity"));
|
||||
var stopBits = Convert.ToInt32(device.GetDataValue("StopBits"));
|
||||
var buttonsValue = device.Data.FirstOrDefault(o => o.Key == "Buttons").Value;
|
||||
var buttons = buttonsValue.FromJson<List<KeyValuePair<string, string>>>();
|
||||
var message = buttons.FirstOrDefault(o => o.Key == code).Value;
|
||||
this.ExecInternal(port, baud, dataBits, partity, stopBits, message);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecInternal(string port, int baud, int dataBits, int partity, int stopBits, string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
using (var sp = new SerialPortStream(port, baud, dataBits, (RJCP.IO.Ports.Parity)partity, (RJCP.IO.Ports.StopBits)stopBits))
|
||||
{
|
||||
sp.Open();
|
||||
var bytes = message.HexToBytes();
|
||||
sp.Write(bytes, 0, bytes.Length);
|
||||
sp.Flush();
|
||||
sp.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var sp = new SerialDevice(port, (BaudRate)baud, (System.IO.Ports.Parity)partity, dataBits, (System.IO.Ports.StopBits)stopBits))
|
||||
{
|
||||
sp.Open();
|
||||
var bytes = message.HexToBytes();
|
||||
sp.Write(bytes);
|
||||
sp.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.PrintStack();
|
||||
}
|
||||
}
|
||||
|
||||
public void Notify()
|
||||
{
|
||||
using (var scope = _applicationServices.CreateScope())
|
||||
{
|
||||
var repo = scope.ServiceProvider.GetService<IRepository<Device>>();
|
||||
var devices = repo.ReadOnlyTable().Include(o => o.Product).Include(o => o.Node).ToList();
|
||||
foreach (var device in devices)
|
||||
{
|
||||
var deviceDto = device.To<EditDeviceModel>();
|
||||
deviceDto.ProductNumber = device.Product.Number;
|
||||
deviceDto.NodeNumber = device.Node.Number;
|
||||
this.SendToServer(Methods.EditDeviceResponse, deviceDto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Infrastructure.Application;
|
||||
using Infrastructure.Configuration;
|
||||
using Infrastructure.Extensions;
|
||||
using Infrastructure.Web.Hosting;
|
||||
using Microsoft.AspNetCore;
|
||||
|
||||
namespace SerialPortService
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = "localhost";
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.Run<Startup>(new List<EFConfigurationValue> {
|
||||
new EFConfigurationValue { Id = "openapi.name", Value= "v1" },
|
||||
new EFConfigurationValue { Id = "openapi.title", Value= "web api" },
|
||||
new EFConfigurationValue { Id = "openapi.version", Value= "1.0" },
|
||||
new EFConfigurationValue { Id = "security:key", Value= "111111111111111111111111"},
|
||||
new EFConfigurationValue { Id = "security:iv", Value= "11111111"},
|
||||
new EFConfigurationValue { Id = "email:host", Value= "nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:port", Value= "25"},
|
||||
new EFConfigurationValue { Id = "email:user", Value= "admin@nbaxp.com"},
|
||||
new EFConfigurationValue { Id = "email:password", Value= "aA123456"},
|
||||
new EFConfigurationValue { Id = "server.ip", Value= "" },
|
||||
new EFConfigurationValue { Id = "server.urls", Value= "http://*:8007" },
|
||||
new EFConfigurationValue { Id = "notify:enabled", Value= "false"},
|
||||
new EFConfigurationValue { Id = "notify:host", Value= $"{host}:8001"},
|
||||
new EFConfigurationValue { Id = "timer.seconds", Value="600"},
|
||||
new EFConfigurationValue { Id = "connectId", Value= Guid.NewGuid().ToBase62() },
|
||||
new EFConfigurationValue { Id = "node.number", Value= "节点编号" },
|
||||
//
|
||||
new EFConfigurationValue { Id = "name", Value= "SerialPort服务"},
|
||||
new EFConfigurationValue { Id = "logo", Value= "/images/logo.png",Type= InputType.ImageUrl},
|
||||
new EFConfigurationValue { Id = "copyright", Value= "Copyright © {now} Company. All rights reserved",Type= InputType.Html}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:8007/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"OnvifService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://127.0.0.1:8007/",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue