v2.0 引用新一代Remoting,简化IoTZero架构
智能大石头 authored at 2024-06-20 23:03:45
8.32 KiB
ZeroIoT
using IoT.Data;
using NewLife;
using NewLife.Algorithms;
using NewLife.Cube;
using NewLife.Cube.Charts;
using NewLife.Cube.Extensions;
using NewLife.Cube.ViewModels;
using NewLife.Data;
using NewLife.Web;
using XCode;
using XCode.Membership;

namespace IoTZero.Areas.IoT.Controllers;

[IoTArea]
[Menu(0, false)]
public class DeviceDataController : EntityController<DeviceData>
{
    static DeviceDataController()
    {
        ListFields.RemoveField("Id");
        ListFields.AddListField("Value", null, "Kind");

        {
            var df = ListFields.GetField("Name") as ListField;
            //df.DisplayName = "主题";
            df.Url = "/IoT/DeviceData?deviceId={DeviceId}&name={Name}";
        }
        ListFields.TraceUrl("TraceId");
    }

    protected override IEnumerable<DeviceData> Search(Pager p)
    {
        var deviceId = p["deviceId"].ToInt(-1);
        var name = p["name"];

        var start = p["dtStart"].ToDateTime();
        var end = p["dtEnd"].ToDateTime();

        if (start.Year < 2000)
        {
            start = DateTime.Today;
            p["dtStart"] = start.ToString("yyyy-MM-dd");
            p["dtEnd"] = start.ToString("yyyy-MM-dd");
        }

        if (deviceId > 0 && p.PageSize == 20 && !name.IsNullOrEmpty() && !name.StartsWithIgnoreCase("raw-", "channel-")) p.PageSize = 14400;

        var list = DeviceData.Search(deviceId, name, start, end, p["Q"], p);

        // 单一设备绘制曲线
        if (list.Count > 0 && deviceId > 0)
        {
            var list2 = list.Where(e => !e.Name.StartsWithIgnoreCase("raw-", "channel-") && e.Value.ToDouble(-1) >= 0).OrderBy(e => e.Id).ToList();

            // 绘制曲线图
            if (list2.Count > 0)
            {
                var topics = list2.Select(e => e.Name).Distinct().ToList();
                var datax = list2.GroupBy(e => e.CreateTime).ToDictionary(e => e.Key, e => e.ToList());
                //var topics = list2.GroupBy(e => e.Topic).ToDictionary(e => e.Key, e => e.ToList());
                var chart = new ECharts
                {
                    Height = 400,
                };
                //chart.SetX(list2, _.CreateTime, e => e.CreateTime.ToString("mm:ss"));

                // 构建X轴
                var minT = datax.Keys.Min();
                var maxT = datax.Keys.Max();
                var step = p["sample"].ToInt(-1);
                if (step > 0)
                {
                    if (step <= 60)
                    {
                        minT = new DateTime(minT.Year, minT.Month, minT.Day, minT.Hour, minT.Minute, 0, minT.Kind);
                        maxT = new DateTime(maxT.Year, maxT.Month, maxT.Day, maxT.Hour, maxT.Minute, 0, maxT.Kind);
                    }
                    else
                    {
                        minT = new DateTime(minT.Year, minT.Month, minT.Day, minT.Hour, 0, 0, minT.Kind);
                        maxT = new DateTime(maxT.Year, maxT.Month, maxT.Day, maxT.Hour, 0, 0, maxT.Kind);
                        //step = 3600;
                    }
                    var times = new List<DateTime>();
                    for (var dt = minT; dt <= maxT; dt = dt.AddSeconds(step))
                    {
                        times.Add(dt);
                    }

                    if (step < 60)
                    {
                        chart.XAxis = new
                        {
                            data = times.Select(e => e.ToString("HH:mm:ss")).ToArray(),
                        };
                    }
                    else
                    {
                        chart.XAxis = new
                        {
                            data = times.Select(e => e.ToString("dd-HH:mm")).ToArray(),
                        };
                    }
                }
                else
                {
                    chart.XAxis = new
                    {
                        data = datax.Keys.Select(e => e.ToString("HH:mm:ss")).ToArray(),
                    };
                }
                chart.SetY("数值");

                var max = -9999.0;
                var min = 9999.0;
                var dps = DeviceProperty.FindAllByDeviceId(deviceId);
                var sample = new AverageSampling();
                //var sample = new LTTBSampling();
                foreach (var item in topics)
                {
                    var name2 = item;

                    // 使用属性名
                    var dp = dps.FirstOrDefault(e => e.Name == item);
                    if (dp != null && !dp.NickName.IsNullOrEmpty()) name2 = dp.NickName;

                    var series = new Series
                    {
                        Name = name2,
                        Type = "line",
                        //Data = tps2.Select(e => Math.Round(e.Value)).ToArray(),
                        Smooth = true,
                    };

                    if (step > 0)
                    {
                        //var minD = minT.Date.ToInt();
                        var tps = new List<TimePoint>();
                        foreach (var elm in datax)
                        {
                            // 可能该Topic在这个时刻没有数据,写入空
                            var v = elm.Value.FirstOrDefault(e => e.Name == item);
                            if (v != null)
                                tps.Add(new TimePoint { Time = v.CreateTime.ToInt(), Value = v.Value.ToDouble() });
                        }

                        var tps2 = sample.Process(tps.ToArray(), step);

                        series.Data = tps2.Select(e => Math.Round(e.Value, 2)).ToArray();

                        var m1 = tps2.Select(e => e.Value).Min();
                        if (m1 < min) min = m1;
                        var m2 = tps2.Select(e => e.Value).Max();
                        if (m2 > max) max = m2;
                    }
                    else
                    {
                        var list3 = new List<Object>();
                        foreach (var elm in datax)
                        {
                            // 可能该Topic在这个时刻没有数据,写入空
                            var v = elm.Value.FirstOrDefault(e => e.Name == item);
                            if (v != null)
                                list3.Add(v.Value);
                            else
                                list3.Add('-');
                        }
                        series.Data = list3;

                        var m1 = list3.Where(e => e + "" != "-").Select(e => e.ToDouble()).Min();
                        if (m1 < min) min = m1;
                        var m2 = list3.Where(e => e + "" != "-").Select(e => e.ToDouble()).Max();
                        if (m2 > max) max = m2;
                    }

                    // 单一曲线,显示最大最小和平均
                    if (topics.Count == 1)
                    {
                        name = name2;
                        series["markPoint"] = new
                        {
                            data = new[] {
                                new{ type="max",name="Max"},
                                new{ type="min",name="Min"},
                            }
                        };
                        series["markLine"] = new
                        {
                            data = new[] {
                                new{ type="average",name="Avg"},
                            }
                        };
                    }

                    // 降采样策略 lttb/average/max/min/sum
                    series["sampling"] = "lttb";
                    series["symbol"] = "none";

                    // 开启动画
                    series["animation"] = true;

                    chart.Add(series);
                }
                chart.SetTooltip();
                chart.YAxis = new
                {
                    name = "数值",
                    type = "value",
                    min = Math.Ceiling(min) - 1,
                    max = Math.Ceiling(max),
                };
                ViewBag.Charts = new[] { chart };

                // 减少数据显示,避免卡页面
                list = list.Take(100).ToList();

                var ar = Device.FindById(deviceId);
                if (ar != null) ViewBag.Title = topics.Count == 1 ? $"{name} - {ar}数据" : $"{ar}数据";
            }
        }

        return list;
    }
}