You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iot/projects/IoTCenter/Controllers/AppController.cs

574 lines
23 KiB

using Application.Domain.Entities;
using Application.Models;
using Infrastructure.Data;
using Infrastructure.Extensions;
using Infrastructure.Jwt;
using Infrastructure.Web;
using IoTCenter.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using Vibrant.InfluxDB.Client;
using Vibrant.InfluxDB.Client.Rows;
namespace IoTCenter.Controllers
{
[Device]
public class AppController : Controller
{
private readonly IHostEnvironment _env;
private readonly IConfiguration _configuration;
private readonly IJwtHelper _jwtHelper;
private readonly IRepository<Category> _categoryRepo;
private readonly IRepository<Product> _productRepo;
private readonly IRepository<Node> _nodeRepo;
private readonly IRepository<Scene> _sceneRepo;
private readonly IRepository<SceneCommand> _sceneCommandRepo;
private readonly IRepository<Command> _commandRepo;
private readonly IRepository<Device> _deviceRepo;
private readonly IRepository<LiveRecord> _liveRecordRepo;
private readonly IHubContext<IoTCenterHub> _hub;
public AppController(
IHostEnvironment env,
IConfiguration configuration,
IJwtHelper jwtHelper,
IRepository<Category> categoryRepo,
IRepository<Product> productRepo,
IRepository<Node> nodeRepo,
IRepository<Scene> sceneRepo,
IRepository<SceneCommand> sceneCommandRepo,
IRepository<Command> commandRepo,
IRepository<Device> deviceRepo,
IRepository<LiveRecord> liveRecordRepo,
IHubContext<IoTCenterHub> hub)
{
this._env = env;
this._configuration = configuration;
this._jwtHelper = jwtHelper;
this._categoryRepo = categoryRepo;
this._productRepo = productRepo;
this._nodeRepo = nodeRepo;
this._sceneRepo = sceneRepo;
this._sceneCommandRepo = sceneCommandRepo;
this._commandRepo = commandRepo;
this._deviceRepo = deviceRepo;
this._liveRecordRepo = liveRecordRepo;
this._hub = hub;
}
public IActionResult GetProducts(string token)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var model = new
{
Products = this._productRepo.ReadOnlyTable().Select(o => new
{
o.Id,
o.Number,
o.Name,
o.Image,
DeviceCount = o.Devices.Count()
}).ToList(),
Scenes = this._sceneRepo.ReadOnlyTable().Where(o => o.NodeId == null).ToList()
};
return Json(model);
}
public IActionResult GetNodes(string token)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var model = this._nodeRepo.ReadOnlyTable()
.Include(o => o.Scenes)
.OrderBy(o => o.DisplayOrder)
.ThenBy(o => o.Name)
.Select(o => new
{
o.Id,
o.Number,
o.Name,
o.Image,
o.DisplayOrder,
o.Scenes,
DeviceCount = o.Devices.Count
})
.ToList();
return Json(model);
}
public IActionResult GetNode(string token, string number)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var model = this._nodeRepo.ReadOnlyTable()
.Include(o => o.Scenes)
.Include(o => o.Devices)
.ThenInclude(o => o.Data)
.Include(o => o.Devices)
.ThenInclude(o => o.Commands)
.FirstOrDefault(o => o.Number == number);
return Json(model);
}
public IActionResult GetProduct(string token, string number)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var model = this._productRepo.ReadOnlyTable()
.Include(o => o.Devices)
.ThenInclude(o => o.Data)
.Include(o => o.Devices)
.ThenInclude(o => o.Node)
.FirstOrDefault(o => o.Number == number);
return Json(model);
}
public IActionResult GetDevice(string token, string number)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var model = this._deviceRepo.ReadOnlyTable()
.Include(o => o.Data)
.Include(o => o.Product)
.ThenInclude(o => o.Apis)
.ThenInclude(o => o.Parameters)
.Include(o => o.Commands)
.FirstOrDefault(o => o.Number == number);
return Json(model);
}
public IActionResult GetTemplate(string token, string number)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var node = _nodeRepo.ReadOnlyTable().FirstOrDefault(o => o.Number == number);
var template = string.IsNullOrEmpty(token) ? node.Template : node.MobileTemplate;
if (!string.IsNullOrEmpty(template))
{
return Content(System.IO.File.ReadAllText(Path.Combine(this._env.ContentRootPath, "wwwroot", template)));
}
else
{
return Content("");
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public IActionResult ExecApi(string token, string connectionId, string number, string method)
{
try
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
CallApi(connectionId, number, method);
return Json(ApiResponse.AsyncSuccess());
}
catch (Exception ex)
{
ex.PrintStack();
return Json(ApiResponse.Error(ex));
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public IActionResult ExecApiAll(string token, string connectionId, string method, string query, List<string> numbers)
{
try
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
foreach (var number in numbers)
{
this.CallApi(connectionId, number, method);
}
return Json(ApiResponse.AsyncSuccess());
}
catch (Exception ex)
{
ex.PrintStack();
return Json(ApiResponse.Error(ex));
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public IActionResult ExecCommand(string token, string connectionId, Guid id)
{
try
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var command = this._commandRepo.ReadOnlyTable().Include(o => o.Device).ThenInclude(o => o.Node).FirstOrDefault(o => o.Id == id);
this._hub.ServerToClient(Methods.ExecCommand, command.Id, command.Device.Node.Number, connectionId);
return Json(ApiResponse.AsyncSuccess());
}
catch (Exception ex)
{
ex.PrintStack();
return Json(ApiResponse.Error(ex));
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public IActionResult ExecScene(string token, string connectionId, Guid id)
{
try
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var scene = this._sceneRepo.ReadOnlyTable().Include(o => o.Node).FirstOrDefault(o => o.Id == id);
if (scene.NodeId != null)
{
this._hub.ServerToClient(Methods.ExecSceneRequest, id, scene.Node.Number, connectionId);
}
return Json(ApiResponse.AsyncSuccess());
}
catch (Exception ex)
{
ex.PrintStack();
return Json(ApiResponse.Error(ex));
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
public IActionResult ExecGlobalScene(string token, string connectionId, Guid id)
{
try
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var commands = this._sceneCommandRepo.ReadOnlyTable()
.Include(o => o.Command).ThenInclude(o => o.Device).ThenInclude(o => o.Node)
.Where(o => o.SceneId == id)
.Select(o => o.Command)
.ToList();
foreach (var command in commands)
{
try
{
this._hub.ServerToClient(Methods.ExecCommand, command.Id, command.Device.Node.Number, connectionId);
}
catch (Exception ex)
{
ex.PrintStack();
}
}
return Json(ApiResponse.AsyncSuccess());
}
catch (Exception ex)
{
ex.PrintStack();
return Json(ApiResponse.Error(ex));
}
}
public IActionResult GetChartData(string token, string number, string time)
{
var userName = this.GetUserName(token);
if (string.IsNullOrEmpty(userName))
{
return Forbid();
}
var device = this._deviceRepo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == number);
var url = this._configuration["influxdb:url"];
var usr = this._configuration["influxdb:usr"];
var pwd = this._configuration["influxdb:pwd"];
var dbName = "iot";
var measurementName = "data";
var list = new List<object>();
var labels = new List<string>();
var hours = Convert.ToInt32(DateTime.Now.ToString("%z"));
using (var client = new InfluxClient(new Uri(url), usr, pwd))
{
var keys = device.Data.Where(o => o.Type == DeviceDataType.Int || o.Type == DeviceDataType.Float).Select(o => o.Key);
var fileds = String.Join(',', keys);
if (!string.IsNullOrEmpty(fileds))
{
var query = $"select {fileds} from {measurementName} where time>now()-{time} and DeviceNumber = '{device.Number}' limit 10000";
var result = client.ReadAsync<DynamicInfluxRow>(dbName, query).Result;
var rows = result.Results.FirstOrDefault()?
.Series.FirstOrDefault()?
.Rows;
foreach (var data in device.Data.Where(o => o.Type == DeviceDataType.Int || o.Type == DeviceDataType.Float))
{
list.Add(new
{
label = data.Name,
data = rows != null ? rows.Select(o => o.Fields.ContainsKey(data.Key) ? o.GetField(data.Key) : null).ToList() : new List<object>(),
backgroundColor = this.GetColor(data.Key),
fill = false
});
}
if (rows != null)
{
var format = time.StartsWith("1") ? "H:mm" : (time.StartsWith("7") ? "ddd" : "MMM-d");
labels = rows.Select(o => o.Timestamp.Value).Select(o => o.AddHours(hours).ToString(format, new CultureInfo("zh-CN"))).ToList();
}
}
var model = new
{
datasets = list,
labels = labels
};
return Json(model);
}
}
/************************************************************/
private void CallApi(string connectionId, string number, string method)
{
var device = this._deviceRepo.ReadOnlyTable().Include(o => o.Node).FirstOrDefault(o => o.Number == number);
if (device != null)
{
var query2 = string.Empty;
var parameters = Request.Method.ToUpper() == "GET" ? Request.Query.ToArray() : Request.Form.ToArray();
foreach (var item in parameters.Where(o => o.Key.ToLower() != "connectionid" && o.Key.ToLower() != "method"))
{
query2 = query2.SetParam(item.Key, item.Value);
}
foreach (var item in new string[] { "token", "connectionid", "method", "numbers[]" })
{
query2 = query2.RemoveParam(item);
}
query2 = query2.SetParam("number", number);
var message = $"{method}{query2}";
var group = device.Node.Number;
this._hub.ServerToClient(Methods.ExecApiRequest, message, group, connectionId);
}
}
private string GetColor(string key)
{
//var randomGen = new Random();
//var names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
//var randomColorName = names[randomGen.Next(names.Length)];
//var randomColor = Color.FromKnownColor(randomColorName);
//return randomColor.Name;
if (key == "Humidity")
{
return Color.FromKnownColor(KnownColor.Green).Name;
}
else if (key == "Electricity")
{
return Color.FromKnownColor(KnownColor.Red).Name;
}
else if (key == "Light")
{
return Color.FromKnownColor(KnownColor.Orange).Name;
}
return Color.FromKnownColor(KnownColor.DarkBlue).Name;
}
private string GetUserName(string token)
{
try
{
return User.Identity.IsAuthenticated ? User.Identity.Name : this._jwtHelper.GetPayload(token)["UserName"].ToString();
}
catch (Exception ex)
{
ex.PrintStack();
return null;
}
}
/************************************************************/
public IActionResult Data(Guid id, string time = "10m")
{
var device = this._deviceRepo.ReadOnlyTable().Include(o => o.Node).Include(o => o.Data).FirstOrDefault(o => o.Id == id);
var url = this._configuration["influxdb:url"];
var usr = this._configuration["influxdb:usr"];
var pwd = this._configuration["influxdb:pwd"];
var dbName = "iot";
var measurementName = "data";
var list = new List<object>();
using (var client = new InfluxClient(new Uri(url), usr, pwd))
{
var fileds = String.Join(',', device.Data
.Where(o => o.Type == DeviceDataType.Int || o.Type == DeviceDataType.Float)
.Select(o => o.Key));
var query = $"select {fileds} from {measurementName} where time>now()-{time} and DeviceNumber = '{device.Number}' limit 10000";
var result = client.ReadAsync<DynamicInfluxRow>(dbName, query).Result;
var rows = result.Results.FirstOrDefault()?
.Series.FirstOrDefault()?
.Rows;
var labels = rows?.Select(o => o.Timestamp.Value).Select(o => o.ToString("MM-dd HH:mm:ss")).ToList() ?? new List<string>();
foreach (var data in device.Data.Where(o => o.Type == DeviceDataType.Int || o.Type == DeviceDataType.Float))
{
list.Add(new
{
id = data.Key,
label = data.Name,
labels,
data = rows?.Select(o => o.GetField(data.Key)).ToList() ?? new List<object>()
});
}
}
return Json(list);
}
public IActionResult AllPowerOn(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "On", o => o.Name.Contains("开关") || o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllPowerOff(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "Off", o => o.Name.Contains("开关") || o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSwitchOn(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "On", o => o.Name.Contains("一路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSwitchOff(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "Off", o => o.Name.Contains("一路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSwitch3On(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "On", o => o.Name.Contains("三路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSwitch3Off(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "Off", o => o.Name.Contains("三路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSocketOn(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "On", o => o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult AllSocketOff(string connectionId, string[] nodes)
{
this.Power(connectionId, nodes, "Off", o => o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodePowerOn(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "On", o => o.Name.Contains("开关") || o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodePowerOff(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "Off", o => o.Name.Contains("开关") || o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSwitchOn(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "On", o => o.Name.Contains("一路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSwitchOff(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "Off", o => o.Name.Contains("一路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSwitch3On(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "On", o => o.Name.Contains("三路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSwitch3Off(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "Off", o => o.Name.Contains("三路开关"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSocketOn(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "On", o => o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
public IActionResult NodeSocketOff(string connectionId, string node)
{
this.Power(connectionId, new string[] { node }, "Off", o => o.Name.Contains("插座"));
return Json(ApiResponse.AsyncSuccess());
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:不捕获常规异常类型", Justification = "<挂起>")]
private void Power(string connectionId, string[] nodes, string command, Func<Device, bool> func)
{
var devices = this._deviceRepo.ReadOnlyTable()
.Include(o => o.Node)
.Include(o => o.Product.Apis)
.Where(o => nodes.Contains(o.Node.Number))
.Where(func)
.ToList();
foreach (var device in devices)
{
try
{
var api = device.Product.Apis.FirstOrDefault(o => o.Command == command);
var message = $"{api.Path}{api.Command}?number={device.Number}";
this._hub.Clients.Group(device.Node.Number).SendAsync(Methods.ServerToClient, Methods.ExecApiRequest, message, connectionId);
}
catch (Exception ex)
{
ex.PrintStack();
}
}
}
}
}