diff --git a/apps/dgiot/src/utils/dgiot_datetime.erl b/apps/dgiot/src/utils/dgiot_datetime.erl index d5815cbc..23a76340 100644 --- a/apps/dgiot/src/utils/dgiot_datetime.erl +++ b/apps/dgiot/src/utils/dgiot_datetime.erl @@ -318,12 +318,14 @@ timestamp_to_datetime(Timestamp) -> calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}))). last_month(Count) -> - EndTime = dgiot_datetime:nowstamp(), - {{Year, Month, _Day}, {_Hour, _Minute, _Second}} = calendar:local_time(), + {{Year, Month, Day}, {_Hour, _Minute, _Second}} = calendar:local_time(), + EndTime = dgiot_datetime:localtime_to_unixtime({{Year, Month, Day}, {23, 59, 59}}), StartTime = dgiot_datetime:localtime_to_unixtime({{Year, Month, 1}, {0, 0, 0}}), last_month(StartTime, EndTime, Count - 1). + last_month(StartTime, EndTime, 0) -> {StartTime, EndTime}; + last_month(StartTime, EndTime, Count) -> {{Year, Month, _Day}, {_Hour, _Minute, _Second}} = dgiot_datetime:unixtime_to_localtime(StartTime), {NewYear, NewMonth} = diff --git a/apps/dgiot_device/priv/swagger/swagger_tdengine.json b/apps/dgiot_device/priv/swagger/swagger_tdengine.json index 7fb5e11a..93738dfa 100644 --- a/apps/dgiot_device/priv/swagger/swagger_tdengine.json +++ b/apps/dgiot_device/priv/swagger/swagger_tdengine.json @@ -196,6 +196,27 @@ "summary": "获取当前设备时序数据图表", "description": "获取当前设备数据图表,支持折线图,柱状图,饼图等", "parameters": [ + { + "in": "query", + "name": "style", + "description": "图标类型", + "default": "line", + "required": true, + "type": "string", + "enum": [ + "amis_table", + "line", + "echart_category" + ] + }, + { + "in": "query", + "name": "month_count", + "description": "月份数量", + "default": "1", + "required": false, + "type": "number" + }, { "in": "path", "name": "deviceid", @@ -270,7 +291,7 @@ "last" ], "default": "last", - "required": true, + "required": false, "type": "string" } ], diff --git a/apps/dgiot_device/src/handler/dgiot_tdengine_handler.erl b/apps/dgiot_device/src/handler/dgiot_tdengine_handler.erl index 80114ebf..83d88413 100644 --- a/apps/dgiot_device/src/handler/dgiot_tdengine_handler.erl +++ b/apps/dgiot_device/src/handler/dgiot_tdengine_handler.erl @@ -129,13 +129,21 @@ do_request(get_device_deviceid, #{<<"deviceid">> := DeviceId} = Args, #{<<"sessi end; %% TDengine 概要: 获取设备历史数据图表 描述:获取设备历史数据图表 -do_request(get_echart_deviceid, #{<<"deviceid">> := DeviceId} = Args, #{<<"sessionToken">> := SessionToken} = _Context, _Req) -> +do_request(get_echart_deviceid, #{<<"deviceid">> := DeviceId,<<"style">> := Style} = Args, #{<<"sessionToken">> := SessionToken} = _Context, _Req) -> case dgiot_product_tdengine:get_channel(SessionToken) of {error, Error} -> {error, Error}; {ok, Channel} -> case dgiot_parse:get_object(<<"Device">>, DeviceId) of {ok, #{<<"objectId">> := DeviceId, <<"product">> := #{<<"objectId">> := ProductId}}} -> - dgiot_device_echart:get_echart_data(Channel, ProductId, DeviceId, Args); + case Style of + <<"amis_table">> -> + dgiot_device_echart:get_data_by_month(Channel, ProductId, DeviceId, Args); + <<"echart_category">> -> + dgiot_device_echart:get_data_by_echart_category(Channel, ProductId, DeviceId, Args); + _ -> + dgiot_device_echart:get_echart_data(Channel, ProductId, DeviceId, Args) + + end; _ -> {error, <<"not find device">>} end diff --git a/apps/dgiot_device/src/utils/dgiot_device_echart.erl b/apps/dgiot_device/src/utils/dgiot_device_echart.erl index a0de9e7f..f9a96461 100644 --- a/apps/dgiot_device/src/utils/dgiot_device_echart.erl +++ b/apps/dgiot_device/src/utils/dgiot_device_echart.erl @@ -21,6 +21,7 @@ -include_lib("dgiot_tdengine/include/dgiot_tdengine.hrl"). -export([get_echart_data/4]). +-export([get_data_by_month/4,get_data_by_echart_category/4, get_keys/2,get_table/2]). get_echart_data(Channel, ProductId, DeviceId, Args) -> Query = maps:without([<<"productid">>, <<"deviceid">>], Args), @@ -91,3 +92,195 @@ get_echart(ProductId, Results, Names, Interval) -> ?LOG(debug, "Child ~p", [Child]), #{<<"columns">> => Columns, <<"rows">> => Rows, <<"child">> => Child}. + +%%判断目标keys是否累计并根据结果设置Function +%% 遍历产品keys和目标keys得到目标keys是否累计 +%%根据是否累计将keys分到sum和last +%%针对sum和last分别配置参数并调用history函数 +%%调用history +%%get_data_by_month(Channel, ProductId, DeviceId,Args) +get_data_by_month(Channel, ProductId, DeviceId, Args) -> +%% io:format("~s ~p Channel = ~p , ProductId = ~p, DeviceId = ~p ~n",[?FILE,?LINE,Channel, ProductId, DeviceId]), + case dgiot_data:get({tdengine_os, Channel}) of + <<"windows">> -> + pass; + _ -> +%% io:format("~s ~p here ~n",[?FILE,?LINE]), +%% 由月份获得起止时间 + {ok,Count} = maps:find(<<"month_count">>,Args), + {StartTime, EndTime} = dgiot_datetime:last_month(Count), +%% 取得key并分割转为list + {ok, K} = maps:find(<<"keys">>,Args), + Keys = re:split(K,","), +%% 由key提取其accu属性并生成sql命令 + Res = case dgiot_product:lookup_prod(ProductId) of + {ok, Product} -> +%% io:format("~s ~p Product =~p , Keys = ~p ~n",[?FILE,?LINE,Product,Keys]), + get_keys(Product, Keys); + _ -> + error + end, +%% io:format("~s ~p Res = ~p~n",[?FILE,?LINE,Res]), + {ok,Sql} = maps:find(<<"sql">>,Res), + {ok,Names} = maps:find(<<"names">>,Res), +%% 配置参数 + TableName = ?Table(DeviceId), + Interval = <<"1d">>, + %%传入参数获得结果 + case dgiot_device_tdengine:get_history_data2(Sql, Channel, TableName, Interval, ProductId, StartTime, EndTime) of +%% 判断结果并转换格式 + {ok, #{<<"results">> := Results}} -> +%% io:format("~s ~p Results = ~p ~n",[?FILE,?LINE,Results]), + Tabledata = get_table(Results,Names), +%% io:format("~s ~p Tabledata = ~p ~n",[?FILE,?LINE,Tabledata]), + {ok,Tabledata}; + _ -> + {ok, #{<<"code">> => 400, <<"msg">> => <<"no data">>}} + end + + + end. + +get_keys(#{<<"thing">> := #{<<"properties">> := Properties}}, [<<"*">>]) -> + lists:foldl(fun(X, Acc) -> +%% io:format("~s ~p Acc = ~p ~n",[?FILE,?LINE,Acc]), + case X of + #{<<"identifier">> := Identifier, <<"isaccumulate">> := true,<<"name">> := Name,<<"identifier">> := Key} -> + case Acc of + #{<<"sql">> := Sql,<<"names">> :=Names } -> +%% io:format("~s ~p Key = ~p ~n",[?FILE,?LINE,Key]), + #{<<"sql">> => <>,<<"names">> => Names#{<> => <>}}; + _ -> +%% io:format("~s ~p Key = ~p ~n",[?FILE,?LINE,Key]), + #{<<"sql">> => <<" sum(", Identifier/binary, ")">>,<<"names">> => #{<> => Name/binary}} + end; + #{<<"identifier">> := Identifier, <<"isaccumulate">> := false,<<"name">> := Name,<<"identifier">> := Key} -> + case Acc of + #{<<"sql">> := Sql,<<"names">> :=Names } -> +%% io:format("~s ~p Key = ~p ~n",[?FILE,?LINE,Key]), + #{<<"sql">> => <>,<<"names">> => Names#{<> => <>}}; + _ -> +%% io:format("~s ~p Key = ~p ~n",[?FILE,?LINE,Key]), +%% io:format("~s ~p Name = ~p ~n",[?FILE,?LINE,Name]), + #{<<"sql">> => <<" last(", Identifier/binary, ")">>,<<"names">> => #{<> => <>}} + end + end + end, #{}, Properties); + +get_keys(#{<<"thing">> := #{<<"properties">> := Properties}}, Keys) -> + lists:foldl(fun(X, Acc) -> + case X of + #{<<"identifier">> := Identifier, <<"isaccumulate">> := true, <<"name">> := Name, <<"identifier">> := Key} -> + case lists:member(Identifier, Keys) of + true -> + case Acc of + #{<<"sql">> := Sql,<<"names">> :=Names } -> + {ok, Sql} = maps:find(<<"sql">>, Acc), + {ok, Names} = maps:find(<<"names">>, Acc), + #{<<"sql">> => <>, <<"names">> => Names#{<> => <>}}; + _ -> + #{<<"sql">> => <<" sum(", Identifier/binary, ")">>, <<"names">> => #{<> => <>}} + end; + false -> + Acc + end; + + #{<<"identifier">> := Identifier, <<"isaccumulate">> := false, <<"name">> := Name, <<"identifier">> := Key} -> + + case lists:member(Identifier, Keys) of + true -> + case Acc of + #{<<"sql">> := Sql,<<"names">> :=Names } -> + {ok, Sql} = maps:find(<<"sql">>, Acc), + {ok, Names} = maps:find(<<"names">>, Acc), + #{<<"sql">> => <>, <<"names">> => Names#{<> => <>}}; + _ -> + + #{<<"sql">> => <<" last(", Identifier/binary, ")">>, <<"names">> => #{<> => <>}} + end; + false -> Acc + end + + end + end, #{}, Properties). + +get_table(Results,Names) -> + Count = string:len(Results), + + TableData = lists:foldl(fun(X, Acc) -> + Res = maps:fold(fun(K, V, Init) -> + case K of + <<"createdat">> -> + Init#{<<"时间"/utf8>> => V}; + _ -> + case binary:match(K, <<"last">>) of + {0, 4} -> + Last_Key = binary:part(K, 5, byte_size(K) - 6), + case maps:find(<>, Names) of + {ok, Name} -> + Init#{<> => V}; + error -> + Init#{<> => V} + end; + _ -> + case binary:match(K, <<"sum">>) of + {0, 3} -> + Sum_Key = binary:part(K, 4, byte_size(K) - 5), + case maps:find(<>, Names) of + {ok, Name1} -> + Init#{<> => V}; + error -> + Init#{<> => V} + end; + _ -> + Init#{<> => V} + end + end + end + end, #{}, X), + Acc ++ [Res] + end, [], Results), + #{<<"status">> => 0, <<"msg">> => <<"ok">>, <<"data">> => #{<<"counts">> => Count ,<<"rows">> => TableData}}. + + +get_data_by_echart_category(Channel, ProductId, DeviceId, Args) -> + %% io:format("~s ~p Channel = ~p , ProductId = ~p, DeviceId = ~p ~n",[?FILE,?LINE,Channel, ProductId, DeviceId]), + case dgiot_data:get({tdengine_os, Channel}) of + <<"windows">> -> + pass; + _ -> +%% io:format("~s ~p here ~n",[?FILE,?LINE]), +%% 由月份获得起止时间 + {ok,Count} = maps:find(<<"month_count">>,Args), + {StartTime, EndTime} = dgiot_datetime:last_month(Count), +%% 取得key并分割转为list + {ok, K} = maps:find(<<"keys">>,Args), + Keys = re:split(K,","), +%% 由key提取其accu属性并生成sql命令 + Res = case dgiot_product:lookup_prod(ProductId) of + {ok, Product} -> +%% io:format("~s ~p Product =~p , Keys = ~p ~n",[?FILE,?LINE,Product,Keys]), + get_keys(Product, Keys); + _ -> + error + end, +%% io:format("~s ~p Res = ~p~n",[?FILE,?LINE,Res]), + {ok,Sql} = maps:find(<<"sql">>,Res), + {ok,Names} = maps:find(<<"names">>,Res), +%% 配置参数 + TableName = ?Table(DeviceId), + Interval = <<"1d">>, + %%传入参数获得结果 + case dgiot_device_tdengine:get_history_data2(Sql, Channel, TableName, Interval, ProductId, StartTime, EndTime) of +%% 判断结果并转换格式 + {ok, #{<<"results">> := Results}} -> +%% io:format("~s ~p Results = ~p ~n",[?FILE,?LINE,Results]), + Tabledata = get_table(Results,Names), +%% io:format("~s ~p Tabledata = ~p ~n",[?FILE,?LINE,Tabledata]), + {ok,Tabledata}; + _ -> + {ok, #{<<"code">> => 400, <<"msg">> => <<"no data">>}} + end + + + end. diff --git a/apps/dgiot_device/src/utils/dgiot_device_tdengine.erl b/apps/dgiot_device/src/utils/dgiot_device_tdengine.erl index 4f738e52..9ac3e9d1 100644 --- a/apps/dgiot_device/src/utils/dgiot_device_tdengine.erl +++ b/apps/dgiot_device/src/utils/dgiot_device_tdengine.erl @@ -22,6 +22,7 @@ -export([get_device/3, get_device/4, get_device/5]). -export([get_history_data/3, get_realtime_data/3]). +-export([get_history_data2/7]). %% #{<<"keys">> => <<"last_row(*)">>, <<"limit">> => 1} 查询td最新的一条device get_device(ProductId, DevAddr, Query) -> @@ -146,3 +147,15 @@ get_realtime_data(Channel, TableName, Query) -> end end). +get_history_data2(Order, Channel, TableName, Interval, ProductId, StartTime, _EndTime) -> +%% io:format("~s ~p Order= ~p, Channel= ~p, TableName= ~p, TableName= ~p,~n Interval= ~p, ProductId= ~p, ~n StartTime= ~p, EndTime =~p. ~n",[?FILE,?LINE,Order, Channel, TableName, TableName, Interval, ProductId, StartTime, _EndTime]), + dgiot_tdengine:transaction(Channel, + fun(Context) -> + Database = ProductId, + DB = dgiot_tdengine_select:format_db(?Database(Database)), + BinStartTime = dgiot_utils:to_binary(StartTime), + Tail = <<" where createdat >= ", BinStartTime/binary, " INTERVAL(", Interval/binary, ") ", ";">>, + Sql = <<"SELECT ", Order/binary, " FROM ", DB/binary, TableName/binary, Tail/binary>>, + ?LOG(error, "Sql ~s", [Sql]), + dgiot_tdengine_pool:run_sql(Context#{<<"channel">> => Channel}, execute_query, Sql) + end). diff --git a/dgiot_install.sh b/dgiot_install.sh index e587ace2..d0946f56 100644 --- a/dgiot_install.sh +++ b/dgiot_install.sh @@ -1486,9 +1486,9 @@ dgiot_shell # set parameters by default value deployType=single # [single | cluster | devops | ci] domain_name="prod.iotn2n.com" # [prod.iotn2n.com | your_domain_name] -software="dgiot_n183" # [dgiot_n183| dgiot_n] +software="dgiot_n184" # [dgiot_n184| dgiot_n] plugin="dgiot" # [dgiot | dgiot_your_plugin] -dgiotmd5="7c410d76293b2e44d50da1e9cabff99c" # [dgiotmd5] +dgiotmd5="963afd492685c5c5cd14a52b072f17b4" # [dgiotmd5] pg_eip="changeyourip" # [datanode_eip] pg_auth='changeyourpassword' # [pg_auth]