Merge branch 'master' of github.com:dgiot/dgiot

This commit is contained in:
U-JOHNLIU\jonhl 2024-02-22 14:36:34 +08:00
commit d3b4cb39fd
14 changed files with 1037 additions and 55 deletions

2
.gitignore vendored
View File

@ -96,6 +96,8 @@ apps/dgiot_viewx/
apps/dgiot_sec/
apps/dgiot_demo/
apps/dgiot_jingmao/
apps/dgiot_atom/
apps/dgiot_12184/
node_modules/
package-lock.json
erlang_ls.config

View File

@ -182,7 +182,7 @@ do_request(post_plugin_app, #{<<"Action">> := Action, <<"App">> := App}, _Contex
{200, #{<<"error">> => <<"license error">>}}
end;
%% iot_hub : dgiot_system_handler
%% iot_hub :
%% OperationId:post_station_data
%% :POST /iotapi/post_station_data
do_request(post_upgrade_plugin, #{<<"file">> := #{<<"filename">> := Filename, <<"fullpath">> := Fullpath}}, _Context, _Req) ->

View File

@ -3,7 +3,6 @@
![开源大赛.jpg](https://dgiot-1253666439.cos.ap-shanghai-fsi.myqcloud.com/kaiyuandasai.png)
<a href="https://www.bilibili.com/video/BV13B421z7NP/?spm_id_from=333.999.0.0"><img src="https://dgiot-1253666439.cos.ap-shanghai-fsi.myqcloud.com/dgiot_doc/bilibidasai.jpg" /></a>
### DGIOT物联网开源平台承办了工信部开放原子的开源大赛
@ -63,3 +62,4 @@
3可信接入与网络安全算法
4设备精细化能耗分析与优化

View File

@ -1,25 +1,127 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020 DGIOT Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-define(DEMO, <<"DEMO">>).
-define(ATOMGIT, <<"ATOMGIT">>).
-record(state, {
id,
env = #{},
search = <<"IP">>
devaddr = <<>>,
heartcount = 0,
regtype = <<>>,
head = "xxxxxx0eee",
len = 0,
app = <<>>,
product = <<>>,
deviceId = <<>>,
scale = 10,
temperature = 0,
env = <<>>,
dtutype = <<>>,
hb = 60,
maxaddr = 0
}).
%%
-define(SetTimeOutReSendTimes, 1000).
%%
-define(GetSceneDeviceTime, 1011).
%%
-define(UploadSceneDeviceTime, 1011).
%%
-define(SetSceneDeviceTime, 1012).
%%
-define(SceneDeviceTimeCalibration, 1013).
%%
-define(GetRtdDataInterval, 1061).
%%
-define(UploadRtdDataInterval, 1061).
%%
-define(SetRtdDataInterval, 1062).
%%
-define(GetMinuteDataInterval, 1063).
%%
-define(UploadMinuteDataInterval, 1063).
%%
-define(SetMinuteDataInterval, 1064).
%%
-define(SetSceneDevicePassword, 1072).
%%
-define(GetRtdData, 2011).
%%
-define(UploadRtdData, 2011).
%%
-define(StopRtdData, 2012).
%%
-define(GetDeviceRunState, 2021).
%%
-define(UploadDeviceRunState, 2021).
%%
-define(StopDeviceRunState, 2022).
%%
-define(GetDayData, 2031).
%%
-define(UploadDayData, 2031).
%%
-define(GetDeviceRunTimeDayData, 2041).
%%
-define(UploadDeviceRunTimeDayData, 2041).
%%
-define(GetMinuteData, 2051).
%%
-define(UploadMinuteData, 2051).
%%
-define(GetHourData, 2061).
%%
-define(UploadHourData, 2061).
%%
-define(UploadComputerPowerOnTime, 2081).
%%
-define(RangeCalibration, 3011).
%%
-define(TakeSampleImmediately, 3012).
%%/
-define(StartClear, 3013).
%%
-define(CompareSample, 3014).
%%
-define(LeaveSuperstandardSample, 3015).
%%
-define(UploadSuperstandardSample, 3015).
%%
-define(SetSampleTimeInterval, 3016).
%%
-define(GetSampleTimeInterval, 3017).
%%
-define(UploadSampleTimeInterval, 3017).
%%
-define(GetSampleTime, 3018).
%%
-define(UploadSampleTime, 3018).
%%
-define(GetSceneDeviceUUID, 3019).
%%
-define(UploadSceneDeviceUUID, 3019).
%%
-define(GetSceneDeviceInfo, 3020).
%%
-define(UploadSceneDeviceInfo, 3020).
%%
-define(SetSceneDeviceParam, 3021).
%%
-define(GetCycleData, 8051).
%%
-define(UploadCycleData, 8051).
%%
-define(RequestResponse, 9011).
%%
-define(ExecuteResponse, 9012).
%%
-define(NoticeResponse, 9013).
%%
-define(DataResponse, 9014).
%%
-define(HeartBeat, 9021).
%%commandType
-define(Request, 1). %%
-define(Upload, 2). %%
-define(Notice, 3). %%
-define(Other, 4). %%
-define(None, 5). %%

Binary file not shown.

View File

@ -1,10 +1,10 @@
{
"definitions": {},
"paths": {
"/demotest": {
"/atomgitapi": {
"post": {
"summary": "demo新增设备",
"description": "demo测试接口",
"summary": "atomgit接口",
"description": "atomgit接口",
"parameters": [
{
"in": "body",

View File

@ -1,5 +1,5 @@
{application, dgiot_atomgit,
[{description, "DGIOT DEMO"},
[{description, "DGIOT ATOMGIT"},
{vsn, "4.3.0"},
{registered, []},
{mod, {dgiot_atomgit_app, []}},

View File

@ -20,22 +20,89 @@
-include_lib("dgiot/include/logger.hrl").
-export([
demo_test/1
atomgitapi/1
, create_product/0
, create_device/3
, save_td/0
, query/0
]).
-define(APP, ?MODULE).
demo_test(#{<<"name">> := _Name, <<"devaddr">> := _Devaddr} = Args) ->
atomgitapi(#{<<"name">> := _Name, <<"devaddr">> := _Devaddr} = Args) ->
io:format("~s ~p Args = ~p.~n", [?FILE, ?LINE, Args]),
{ok, Args};
demo_test(Args) ->
atomgitapi(Args) ->
io:format("~s ~p Args = ~p.~n", [?FILE, ?LINE, Args]),
{error}.
error.
%%
create_product() ->
dgiot_product:create_product(#{
<<"name">> => <<"添加产品例子"/utf8>>,
<<"devType">> => <<"dgiot">>,
<<"category">> => #{<<"objectId">> => <<"5ca6049839">>, <<"__type">> => <<"Pointer">>, <<"className">> => <<"Category">>},
<<"desc">> => <<"atom test">>,
<<"config">> => #{<<"interval">> => -1},
<<"channel">> => #{},
<<"thing">> => #{},
<<"ACL">> => #{<<"role:开发者"/utf8>> => #{<<"read">> => true, <<"write">> => true}},
<<"nodeType">> => 0,
<<"productSecret">> => dgiot_utils:random()
}).
%%
create_device(ProductId, DTUMAC, DTUIP) ->
case dgiot_product:lookup_prod(ProductId) of
{ok, #{<<"ACL">> := Acl, <<"devType">> := DevType}} ->
dgiot_device:create_device(#{
<<"devaddr">> => DTUMAC,
<<"name">> => <<DevType/binary, "_", DTUMAC/binary>>,
<<"ip">> => DTUIP,
<<"isEnable">> => true,
<<"product">> => ProductId,
<<"ACL">> => Acl,
<<"status">> => <<"ONLINE">>,
<<"brand">> => DevType,
<<"devModel">> => DevType
});
_ ->
pass
end.
%% td库
save_td() ->
%% td
dgiot_task:save_td(<<"产品objectId">>, <<"设备地址">>, #{<<"物模型标识符"/utf8>> => <<"value">>}, #{}),
%% td
Sql = dgiot_tdengine:format_sql(<<"产品objectId">>, <<"设备地址">>, [#{<<"物模型标识符"/utf8>> => <<"value">>}]),
dgiot_tdengine_adapter:save_sql(<<"产品objectId">>, Sql).
%%
query() ->
%% Id查询产品详情
dgiot_parse:get_object(<<"Product">>, <<"产品id">>),
%%
dgiot_parse:query_object(<<"Product">>, #{<<"count">> => <<"objectId">>, <<"limit">> => 100, <<"where">> => #{}}),
%% Id查询设备详情
dgiot_parse:get_object(<<"Device">>, <<"设备id">>),
%%
case dgiot_parse:query_object(<<"Device">>, #{<<"count">> => <<"objectId">>, <<"limit">> => 100, <<"where">> => #{}}) of
{ok, #{<<"count">> := Count, <<"results">> := Results}} ->
io:format("~s ~p Count = ~p.~n", [?FILE, ?LINE, Count]),
%% count , results
%%
lists:foldl(fun(#{<<"objectId">> := DeviceId, <<"name">> := Name}, _) ->
%% objectId,
io:format("~s ~p DeviceId ~p => Name = ~p.~n", [?FILE, ?LINE, DeviceId, Name])
end, #{}, Results);
_ ->
pass
end.

View File

@ -21,7 +21,7 @@
-include_lib("dgiot/include/dgiot_socket.hrl").
-include_lib("dgiot/include/logger.hrl").
-include("dgiot_atomgit.hrl").
-define(TYPE, <<"CUSTOMER">>).
-define(TYPE, <<"ATOMGIT">>).
%% API
-export([start/2]).
@ -33,19 +33,31 @@
cType => ?TYPE,
type => ?PROTOCOL_CHL,
title => #{
zh => <<"demo测试通道"/utf8>>
zh => <<"ATOMGIT测试通道"/utf8>>
},
description => #{
zh => <<"demo测试通道"/utf8>>
zh => <<"ATOMGIT测试通道"/utf8>>
}
}).
%%
-params(#{
<<"port">> => #{
order => 1,
type => integer,
required => true,
default => 20660,
title => #{
zh => <<"端口"/utf8>>
},
description => #{
zh => <<"侦听端口"/utf8>>
}
},
<<"ico">> => #{
order => 102,
type => string,
required => false,
default => <<"/dgiot_file/shuwa_tech/zh/product/dgiot/channel/demo.jpg">>,
default => <<"/dgiot_file/shuwa_tech/zh/product/dgiot/channel/atomgit.jpg">>,
title => #{
en => <<"channel ICO">>,
zh => <<"通道ICO"/utf8>>
@ -62,12 +74,26 @@ start(ChannelId, ChannelArgs) ->
dgiot_channelx:add(?TYPE, ChannelId, ?MODULE, ChannelArgs).
%%
init(?TYPE, ChannelId, Args) ->
init(?TYPE, ChannelId, #{
<<"port">> := Port,
<<"product">> := Products
} = Args) ->
{ProdcutId, App} =
case get_app(Products) of
[{ProdcutId1, App1} | _] ->
{ProdcutId1, App1};
[] ->
{<<>>, <<>>};
_ ->
{<<>>, <<>>}
end,
State = #state{
id = ChannelId,
env = Args
env = Args,
app = App,
product = ProdcutId
},
{ok, State, []}.
{ok, State, dgiot_atomgit_tcp:start(Port, State)}.
handle_init(State) ->
{ok, State}.
@ -77,9 +103,39 @@ handle_event(EventId, Event, State) ->
?LOG(error, "EventId ~p Event ~p", [EventId, Event]),
{ok, State}.
handle_message({dlink_properties_report, ProductId, DevAddr, Buff}, #state{id = ChannelId} = State) ->
dgiot_bridge:send_log(ChannelId, ProductId, "~s ~p ~p mqtt revice from ~p => ProductId ~p ", [?FILE, ?LINE, dgiot_datetime:format("YYYY-MM-DD HH:NN:SS"), Buff, ProductId]),
case dgiot_atomgit_decoder:parse_frame(Buff, []) of
{ok, [#{<<"devaddr">> := DevAddr} = Data | _]} ->
NewData = dgiot_dlink_proctol:parse_payload(ProductId, Data),
dgiot_bridge:send_log(ChannelId, ProductId, DevAddr, "~s ~p ~p revice from ~p~n save td => ProductId ~p DevAddr ~p ~ts ",
[?FILE, ?LINE, dgiot_datetime:format("YYYY-MM-DD HH:NN:SS"), Buff, ProductId, DevAddr, unicode:characters_to_list(dgiot_json:encode(NewData))]),
dgiot_task:save_td(ProductId, DevAddr, NewData, #{});
_ ->
pass
end,
{ok, State};
handle_message(_Message, State) ->
{ok, State}.
stop(_ChannelType, _ChannelId, _State) ->
ok.
get_app(Products) ->
lists:map(fun({ProdcutId, #{<<"ACL">> := Acl}}) ->
Predicate = fun(E) ->
case E of
<<"role:", _/binary>> -> true;
_ -> false
end
end,
App =
case lists:filter(Predicate, maps:keys(Acl)) of
[<<"role:", Name/binary>> | _] ->
Name;
_ ->
<<"dgiot">>
end,
{ProdcutId, App}
end, Products).

View File

@ -0,0 +1,74 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 DGIOT Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(dgiot_atomgit_tcp).
-author("stoneliu").
-include("dgiot_atomgit.hrl").
-include_lib("dgiot/include/dgiot_socket.hrl").
-include_lib("dgiot/include/logger.hrl").
-define(MAX_BUFF_SIZE, 1024).
-export([
start/2
]).
%% TCP callback
-export([init/1, handle_info/2, handle_cast/2, handle_call/3, terminate/2]).
start(Port, State) ->
dgiot_tcp_server:child_spec(?MODULE, dgiot_utils:to_int(Port), State).
init(#tcp{state = #state{id = ChannelId}} = TCPState) ->
case dgiot_bridge:get_products(ChannelId) of
{ok, _TYPE, _ProductIds} ->
{ok, TCPState};
{error, not_find} ->
{stop, not_find_channel}
end.
%%
handle_info({tcp, Buff}, #tcp{socket = Socket, state = #state{id = ChannelId, devaddr = <<>>, product = ProductId} = State} = TCPState) ->
DTUIP = dgiot_utils:get_ip(Socket),
DtuAddr = dgiot_utils:binary_to_hex(Buff),
DeviceId = dgiot_parse_id:get_deviceid(ProductId, DtuAddr),
dgiot_atomgit:create_device(ProductId, DtuAddr, DTUIP),
dgiot_bridge:send_log(ChannelId, ProductId, DtuAddr, "~s ~p DTU login DtuAddr:~p", [?FILE, ?LINE, DtuAddr]),
{noreply, TCPState#tcp{buff = <<>>, register = true, clientid = DeviceId, state = State#state{devaddr = DtuAddr, deviceId = DeviceId}}};
handle_info({tcp, Buff}, #tcp{state = #state{id = ChannelId, devaddr = Devaddr, product = ProductId} = _State} = TCPState) ->
dgiot_bridge:send_log(ChannelId, ProductId, "~s ~p ~p tcp revice from ~p => ProductId ~p ", [?FILE, ?LINE, dgiot_datetime:format("YYYY-MM-DD HH:NN:SS"), Buff, ProductId]),
case dgiot_atomgit_decoder:parse_frame(Buff, []) of
{ok, [#{<<"devaddr">> := Devaddr} = Data | _]} ->
NewData = dgiot_dlink_proctol:parse_payload(ProductId, Data),
dgiot_bridge:send_log(ChannelId, ProductId, Devaddr, "~s ~p ~p revice from ~p~n save td => ProductId ~p DevAddr ~p ~ts ", [?FILE, ?LINE, dgiot_datetime:format("YYYY-MM-DD HH:NN:SS"), Buff, ProductId, Devaddr, unicode:characters_to_list(dgiot_json:encode(NewData))]),
dgiot_task:save_td(ProductId, Devaddr, NewData, #{});
_O ->
pass
end,
{noreply, TCPState};
handle_info(_Info, TCPState) ->
{noreply, TCPState}.
handle_call(_Msg, _From, TCPState) ->
{reply, ok, TCPState}.
handle_cast(_Msg, TCPState) ->
{noreply, TCPState}.
terminate(_Reason, _TCPState) ->
ok.

View File

@ -21,19 +21,19 @@
%% API
-export([swagger_dahua/0]).
-export([swagger_atomgit/0]).
-export([handle/4]).
%% API描述
%%
%% :
%% 1. Metadata为map表示的JSON,
%% dgiot_http_server:bind(<<"/dahua>>, ?MODULE, [], Metadata)
%% dgiot_http_server:bind(<<"/atomgit>>, ?MODULE, [], Metadata)
%% 2. priv/swagger/
%% dgiot_http_server:bind(<<"/swagger_dahua.json">>, ?MODULE, [], priv)
swagger_dahua() ->
%% dgiot_http_server:bind(<<"/swagger_atomgit.json">>, ?MODULE, [], priv)
swagger_atomgit() ->
[
dgiot_http_server:bind(<<"/swagger_demo.json">>, ?MODULE, [], priv)
dgiot_http_server:bind(<<"/swagger_atomgit.json">>, ?MODULE, [], priv)
].
@ -79,8 +79,8 @@ handle(OperationID, Args, Context, Req) ->
%% System : demo测试接口 :demo测试接口
%% OperationId:post_demotest
%% :POST /iotapi/post_demotest
do_request(post_demotest, Args, _Context, _Req) ->
case dgiot_atomgit:demo_test(Args) of
do_request(post_atomgitapi, Args, _Context, _Req) ->
case dgiot_atomgit:atomgitapi(Args) of
{ok, Data} ->
{ok, #{<<"data">> => Data, <<"status">> => 0, <<"msg">> => <<"success">>}};
_ ->

View File

@ -0,0 +1,153 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 DGIOT Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(dgiot_atomgit_decoder).
-include_lib("dgiot_atomgit.hrl").
-include_lib("dgiot/include/logger.hrl").
-protocol([?ATOMGIT]).
-define(CRLF, "\r\n").
%% API
-export([parse_frame/2, to_frame/1]).
parse_frame(Buff, Opts) ->
parse_frame(Buff, [], Opts).
parse_frame(<<>>, Acc, _Opts) ->
{ok, Acc};
%% HJ 212-2017
%% 6.3
%% ASCII UTF-8 8 1
%% 4
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% | | | |
%------------------------------------------------------------------------------------------------------------------------
%% | | 2 | ## |
%-------------------------------------------------------------------------------------------------------------------------
%% | | 2 | ASCII 2550255 |
%-------------------------------------------------------------------------------------------------------------------------
%% | | 0 n 1024 | 6.3.2 3 |
%-------------------------------------------------------------------------------------------------------------------------
%% CRC | | 4 | CRC A |
%% | | | CRC |
%-------------------------------------------------------------------------------------------------------------------------
%% | | 2 | <CR><LF> |
%-------------------------------------------------------------------------------------------------------------------------
parse_frame(<<"##", Length:4/binary, Tail/binary>>, Acc, State) ->
Len = binary_to_integer(Length, 10),
{Rest1, Acc1} =
case Len > -1 andalso Len < 1025 of
true ->
case Tail of
<<UserZone:Len/binary, Crc:4/binary, ?CRLF, Rest/binary>> ->
CheckCrc = dgiot_atomgit_utils:crc16(UserZone),
case Crc of
CheckCrc ->
{Rest, Acc ++ [parse_userzone(UserZone, State)]};
_ ->
{<<>>, Acc}
end;
_ ->
{<<>>, Acc}
end;
_ ->
{<<>>, Acc}
end,
parse_frame(Rest1, Acc1, State);
parse_frame(<<_:8, Data/binary>> = _Rest, Acc, Opts) ->
parse_frame(Data, Acc, Opts).
%%6.3.2
%% 3 3 =
%% 3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%| | | | |
%|----------------------------------------------------------------------------------------------------------------------
%| QN | | 20 | :QN=YYYYMMDDhhmmsszzz |
%------------------------------------------------------------------------------------------------------------------------
%| ST | | 5 | ST=, 6.6.1 5 |
%|----------------------------------------------------------------------------------------------------------------------
%| CN | | 7 | CN=, 6.6.5 9 |
%|----------------------------------------------------------------------------------------------------------------------
%| 访 | | 9 | PW=访 |
%|----------------------------------------------------------------------------------------------------------------------|
%| | | | MN=MN EPC-96 |
%| | | | MN 24 0~9A~F |
%| | | | _______________________________________________________________ |
%| MN | | 27 | | EPC-96 | |
%| | | | |------------------------------------------------------------- | |
%| | | | | | | | | | |
%| | | | --------------------------------------------------------------- |
%| | | | | ( | 8 | 28 | 24 | 36 | |
%|----------------------------------------------------------------------------------------------------------------------|
%| | | | Flag= |
%| | | | |
%| | | | | V5 | V4 | V3 | V2 | V1 | V0 | D | A | |
%| | | | ------------------------------------------- |
%| | | 8 | V5~V0Bit000000 HJ/T 212-2005000001 |
%| Flag | 0-255| | |
%| | | | ABit1-0- |
%| | | | DBit1-, |
%| | | | 0- |
%| | | | Flag=7 |
%|----------------------------------------------------------------------------------------------------------------------|
%| PNUM | | 9 | PNUM , |
%|----------------------------------------------------------------------------------------------------------------------|
%| PNO | | 8 | PNO ,
%|----------------------------------------------------------------------------------------------------------------------|
%| CP | | 0n950| CP=&&&& 6.3.3 |
%|----------------------------------------------------------------------------------------------------------------------|
%%parse_userzone(<<"QN=",QN:17/binary,";ST=", ST:2/binary, ";CN=", CN:4/binary, ";PW=", PWD:6/binary, ";MN=", MN:24/binary, ";Flag=", Flag:2/binary, PNUM:9/binary, PNO:8/binary, ";CP=", CP/binary>>, _State) ->
%% ##0331QN=20240204193300000;ST=31;CN=2011;PW=123456;MN=60436377;Flag=4;CP=&&DataTime=20240204193300;a34004-Rtd=10,a34004-Flag=N;a34002-Rtd=12,a34002-Flag=N;a34001-Rtd=26,a34001-Flag=N;a01001-Rtd=1.8,a01001-Flag=N;a01002-Rtd=91.0,a01002-Flag=N;a01007-Rtd=3.9,a01007-Flag=N;a01008-Rtd=314.00,a01008-Flag=N;a01006-Rtd=102.36,a01006-Flag=N;&&7F80\r\n
parse_userzone(UserZone, _State) ->
lists:foldl(fun(X, Acc) ->
case X of
<<"MN=", Devaddr/binary>> ->
Acc#{<<"devaddr">> => Devaddr};
<<"CP=&&", CP/binary>> ->
Acc#{<<"CP">> => dgiot_atomgit_utils:get_cps(CP)};
_ ->
NewX =
case re:split(X, <<",">>) of
[First, _] ->
First;
_ ->
X
end,
case re:split(NewX, <<"=">>) of
[K, V] ->
Acc#{K => V};
_ -> Acc
end
end
end, #{}, re:split(UserZone, <<";">>)).
to_frame(#{<<"QN">> := QN, <<"ST">> := ST, <<"CN">> := CN, <<"PW">> := PW, <<"MN">> := MN, <<"Flag">> := Flag, <<"CP">> := CP, <<"PNUM">> := PNUM, <<"PNO">> := PNO}) ->
Rdata = <<"QN=", QN/binary, ";ST=", ST/binary, ";CN=", CN/binary, ";PW=", PW/binary, ";MN=", MN/binary,
";Flag=", Flag/binary, ";PNUM=", PNUM/binary, ";PNO=", PNO/binary, ";CP=&&", CP/binary, "&&">>,
Len = dgiot_atomgit_utils:get_len(Rdata),
Crc = dgiot_atomgit_utils:crc16(Rdata),
<<"##", Len/binary, Rdata/binary, Crc/binary, "\r\n">>;
to_frame(#{<<"QN">> := QN, <<"ST">> := ST, <<"CN">> := CN, <<"PW">> := PW, <<"MN">> := MN, <<"Flag">> := Flag, <<"CP">> := CP}) ->
Rdata = <<"QN=", QN/binary, ";ST=", ST/binary, ";CN=", CN/binary, ";PW=", PW/binary, ";MN=", MN/binary, ";Flag=", Flag/binary, ";CP=&&", CP/binary, "&&">>,
Len = dgiot_atomgit_utils:get_len(Rdata),
Crc = dgiot_atomgit_utils:crc16(Rdata),
<<"##", Len/binary, Rdata/binary, Crc/binary, "\r\n">>.

View File

@ -0,0 +1,361 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2020-2021 DGIOT Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http) ->%%www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(dgiot_atomgit_utils).
-include_lib("dgiot_atomgit.hrl").
-include_lib("dgiot/include/logger.hrl").
%% API
-export([
get_sys_type/1,
get_status_type/1,
get_result_type/1,
get_return_type/1,
get_len/1,
crc16/1,
get_cps/1,
getCommandType/1
]).
%%6.6.1.2
%% 5 0~9A~Z
%% 6612 线
%%---------------------------------------------------------------------------------------------------------------------------------------
%% 21
%% 22
%% 23
%% 24
%% 25
%% 26
%% 27
%% 31
%% 32
%% 33
%% 34
%% 35
%% 36
%% 37
%% 38
%% 39
%% 41
%% 51
%% 52
%% 91
%%---------------------------------------------------------------------------------------------------------------------------------------
get_sys_type(21) ->
<<"地表水质量监测"/utf8>>;
get_sys_type(22) ->
<<"空气质量监测"/utf8>>;
get_sys_type(23) ->
<<"声环境质量监测"/utf8>>;
get_sys_type(24) ->
<<"地下水质量监测"/utf8>>;
get_sys_type(25) ->
<<"土壤质量监测"/utf8>>;
get_sys_type(26) ->
<<"海水质量监测"/utf8>>;
get_sys_type(27) ->
<<"挥发性有机物监测"/utf8>>;
get_sys_type(31) ->
<<"大气环境污染源"/utf8>>;
get_sys_type(32) ->
<<"地表水体环境污染源"/utf8>>;
get_sys_type(33) ->
<<"地下水体环境污染源"/utf8>>;
get_sys_type(34) ->
<<"海洋环境污染源"/utf8>>;
get_sys_type(35) ->
<<"土壤环境污染源"/utf8>>;
get_sys_type(36) ->
<<"声环境污染源"/utf8>>;
get_sys_type(37) ->
<<"振动环境污染源"/utf8>>;
get_sys_type(38) ->
<<"放射性环境污染源"/utf8>>;
get_sys_type(39) ->
<<"工地扬尘污染源"/utf8>>;
get_sys_type(41) ->
<<"电磁环境污染源"/utf8>>;
get_sys_type(51) ->
<<"烟气排放过程监控"/utf8>>;
get_sys_type(52) ->
<<"污水排放过程监控"/utf8>>;
get_sys_type(91) ->
<<"系统交互"/utf8>>.
%%-------------------------------------------------------------------------------------
%%6.6.2
%% 6
%% 6
%%
%% 1
%% 2
%% 3
%% 4
%% 5
%% 6
%% 100
%%------------------------------------------------------------------------------------
get_result_type(1) ->
<<"执行成功">>;
get_result_type(2) ->
<<"执行失败,但不知道原因">>;
get_result_type(3) ->
<<"命令请求条件错误">>;
get_result_type(4) ->
<<"通讯超时">>;
get_result_type(5) ->
<<"系统繁忙不能执行">>;
get_result_type(6) ->
<<"系统故障">>;
get_result_type(100) ->
<<"没有数据">>;
get_result_type(_) ->
<<"可扩充">>.
%%6.6.3
%% 7
%% 7
%%1
%%2
%%3 PW
%%4 MN
%%5 ST
%%6 Flag
%%7 QN
%%8 CN
%%9 CRC
%%100
get_return_type(1) ->
<<"准备执行请求"/utf8>>;
get_return_type(2) ->
<<"请求被拒绝"/utf8>>;
get_return_type(3) ->
<<"PW 错误"/utf8>>;
get_return_type(4) ->
<<"MN 错误"/utf8>>;
get_return_type(5) ->
<<"ST 错误"/utf8>>;
get_return_type(6) ->
<<"Flag 错误"/utf8>>;
get_return_type(7) ->
<<"QN 错误"/utf8>>;
get_return_type(8) ->
<<"CN 错误"/utf8>>;
get_return_type(9) ->
<<"CRC 校验错误"/utf8>>;
get_return_type(100) ->
<<"未知错误"/utf8>>;
get_return_type(Type) ->
BinType = dgiot_utils:to_binary(Type),
<<"可扩充"/utf8, "_", BinType/binary>>.
%%6.6.4
%% 8
%% 8
%%N 线
%%F 线
%%M 线
%%S
%%D 线
%%C 线
%%T 线
%%B 线
get_status_type("N") ->
<<"在线监控(监测)仪器仪表工作正常"/utf8>>;
get_status_type("F") ->
<<"在线监控(监测)仪器仪表停运"/utf8>>;
get_status_type("M") ->
<<"在线监控(监测)仪器仪表处于维护期间产生的数据"/utf8>>;
get_status_type("S") ->
<<"手工输入的设定值"/utf8>>;
get_status_type("D") ->
<<"在线监控(监测)仪器仪表故障"/utf8>>;
get_status_type("C") ->
<<"在线监控(监测)仪器仪表处于校准状态"/utf8>>;
get_status_type("T") ->
<<"在线监控(监测)仪器仪表采样数值超过测量上限"/utf8>>;
get_status_type("B") ->
<<"在线监控(监测)仪器仪表与数采仪通讯异常"/utf8>>;
get_status_type(Type) ->
BinType = dgiot_utils:to_binary(Type),
<<"可扩充"/utf8, "_", BinType/binary>>.
%%6.6.5.2
%% 4 9
%% 9
%%
getCommandType(?SetTimeOutReSendTimes) ->
?Request;
%%
getCommandType(?GetSceneDeviceTime) ->
?Request;
%%
getCommandType(?SetSceneDeviceTime) ->
?Request;
%%
getCommandType(?SceneDeviceTimeCalibration) ->
?Notice;
%%
getCommandType(?GetRtdDataInterval) ->
?Request;
%%
getCommandType(?SetRtdDataInterval) ->
?Request;
%%
getCommandType(?GetMinuteDataInterval) ->
?Request;
%%
getCommandType(?SetMinuteDataInterval) ->
?Request;
%%
getCommandType(?SetSceneDevicePassword) ->
?Request;
%%
getCommandType(?GetRtdData) ->
?Request;
%%
getCommandType(?StopRtdData) ->
?Notice;
%%
getCommandType(?GetDeviceRunState) ->
?Request;
%%
getCommandType(?StopDeviceRunState) ->
?Request;
%%
getCommandType(?GetDayData) ->
?Request;
%%
getCommandType(?GetDeviceRunTimeDayData) ->
?Request;
%%
getCommandType(?GetMinuteData) ->
?Request;
%%
getCommandType(?GetHourData) ->
?Request;
%%
getCommandType(?UploadComputerPowerOnTime) ->
?Upload;
%%
getCommandType(?RangeCalibration) ->
?Request;
%%
getCommandType(?TakeSampleImmediately) ->
?Request;
%%/
getCommandType(?StartClear) ->
?Request;
%%
getCommandType(?CompareSample) ->
?Request;
%%
getCommandType(?LeaveSuperstandardSample) ->
?Request;
%%
getCommandType(?SetSampleTimeInterval) ->
?Request;
%%
getCommandType(?GetSampleTimeInterval) ->
?Request;
%%
getCommandType(?GetSampleTime) ->
?Request;
%%
getCommandType(?GetSceneDeviceUUID) ->
?Request;
%%
getCommandType(?GetSceneDeviceInfo) ->
?Request;
%%
getCommandType(?SetSceneDeviceParam) ->
?Request;
%%
getCommandType(?GetCycleData) ->
?Request;
%%
getCommandType(?RequestResponse) ->
?Other;
%%
getCommandType(?ExecuteResponse) ->
?Other;
%%
getCommandType(?NoticeResponse) ->
?Other;
%%
getCommandType(?DataResponse) ->
?Other;
%%
getCommandType(?HeartBeat) ->
?Other;
getCommandType(_) ->
?None.
get_len(Rdata) ->
Len = byte_size(Rdata),
list_to_binary(lists:flatten(io_lib:format("~4.10.0b", [Len]))).
%%CRC Cyclic Redundancy Check ANSI CRC16
%% CRC16
%%CRC16 CRC16
%% CRC16
%%CRC16
%%1) CRC16 0xFFFF
%%2)
%%3) CRC16 CRC16
%%4) CRC16
%%5) CRC16
%%6) 1CRC16 0xA001 CRC16
%%
%%7) 4~6 8
%%8)
%%9) 3~8
%%10) CRC16
%%
crc16(Buff) -> crc16(Buff, 16#FFFF).
crc16(<<>>, Crc) ->
list_to_binary(string:to_upper(lists:flatten(io_lib:format("~4.16.0b", [Crc]))));
crc16(<<B:8, Rest/binary>>, Crc) ->
NewCrc =
lists:foldl(fun(_, CrcRegister) ->
Check = CrcRegister band 16#0001,
New = CrcRegister bsr 1,
case Check of
1 ->
New bxor 16#A001;
0 ->
New
end
end, (Crc bsr 8) bxor B, lists:seq(1, 8)),
crc16(Rest, NewCrc).
get_cps(ParamCodes) ->
CP1 = re:replace(ParamCodes, <<"&&">>, <<"">>),
lists:foldl(fun(X, Acc) ->
case re:split(X, <<"=">>) of
[K, V] ->
Acc#{K => V};
_ -> Acc
end
end, #{}, re:split(CP1, ",")).

View File

@ -20,8 +20,85 @@
-include_lib("dgiot_bridge/include/dgiot_bridge.hrl").
-export([start/1, start/2, send/3, get_pnque_len/1, save_pnque/4, get_pnque/1, del_pnque/1, save_td/4, merge_cache_data/3, save_cache_data/2]).
-export([get_props/1, get_control/3, get_collection/4, get_calculated/2, get_instruct/2, get_storage/2, string2value/2, string2value/3]).
-export([get_props/1, get_control/3, get_collection/4, get_calculated/4, get_instruct/2, get_storage/2, string2value/2, string2value/3]).
-export([save_td_no_match/4]).
%%
-protocol_type(#{
cType => <<"TASKSTATISTICS">>,
type => <<"TASKSTATISTICS">>,
colum => 10,
title => #{
zh => <<"任务统计"/utf8>>
},
description => #{
zh => <<"任务统计"/utf8>>
}
}).
-params(#{
<<"type">> => #{
order => 1,
type => string,
required => true,
default => #{<<"value">> => <<"duration">>, <<"label">> => <<"时长累加"/utf8>>},
enum => [
#{<<"value">> => <<"duration">>, <<"label">> => <<"时长累加"/utf8>>},
#{<<"value">> => <<"frequency">>, <<"label">> => <<"次数累加"/utf8>>}
],
title => #{
zh => <<"条件"/utf8>>
},
description => #{
zh => <<"条件"/utf8>>
}
},
<<"key">> => #{
order => 2,
type => string,
required => true,
default => <<"key"/utf8>>,
title => #{
zh => <<"物模型标识符"/utf8>>
},
description => #{
zh => <<"统计的物模型标识符"/utf8>>
}
},
<<"comparetype">> => #{
order => 3,
type => string,
required => true,
default => #{<<"value">> => <<"EQ">>, <<"label">> => <<"等于"/utf8>>},
enum => [
#{<<"value">> => <<"LT">>, <<"label">> => <<"小于"/utf8>>},
#{<<"value">> => <<"LE">>, <<"label">> => <<"小于等于"/utf8>>},
#{<<"value">> => <<"GT">>, <<"label">> => <<"大于"/utf8>>},
#{<<"value">> => <<"GE">>, <<"label">> => <<"大于等于"/utf8>>},
#{<<"value">> => <<"EQ">>, <<"label">> => <<"等于"/utf8>>},
#{<<"value">> => <<"NE">>, <<"label">> => <<"不等于"/utf8>>}
],
title => #{
zh => <<"条件"/utf8>>
},
description => #{
zh => <<"条件"/utf8>>
}
},
<<"value">> => #{
order => 4,
type => string,
required => true,
default => <<"1">>,
title => #{
zh => <<""/utf8>>
},
description => #{
zh => <<"物模型比较值"/utf8>>
}
}
}).
start(ChannelId) ->
lists:map(fun(Y) ->
case Y of
@ -60,18 +137,108 @@ send(ProductId, DevAddr, Payload) ->
dgiot_client:send(ChannelId, DevAddr, Topic, Payload)
end.
%%
compare(KeyValue, <<"LT">>, Value) ->
KeyValue < Value;
compare(KeyValue, <<"LE">>, Value) ->
KeyValue =< Value;
compare(KeyValue, <<"GT">>, Value) ->
KeyValue > Value;
compare(KeyValue, <<"GE">>, Value) ->
KeyValue >= Value;
compare(KeyValue, <<"EQ">>, Value) ->
KeyValue == Value;
compare(KeyValue, <<"NE">>, Value) ->
KeyValue =/= Value;
compare(_, _, _) ->
false.
%%
%% select last(devaddr) as devaddr FROM _24b9b4bc50._1c9966755d;
get_last_value(ProductId, DevAddr, Identifier) ->
case dgiot_data:get({last_value, ProductId, DevAddr, Identifier}) of
not_find ->
case dgiot_tdengine:get_channel(ProductId) of
{ok, Channel} ->
dgiot_tdengine:transaction(Channel,
fun(Context) ->
DB = dgiot_tdengine:get_database(Channel, ProductId),
DeviceId = dgiot_parse_id:get_deviceid(ProductId, DevAddr),
Sql = <<"select last(", Identifier/binary, ") as ", Identifier/binary, " FROM ", DB/binary, "_", DeviceId/binary, ";">>,
case dgiot_tdengine_pool:run_sql(Context#{<<"channel">> => Channel}, execute_query, Sql) of
{ok, #{<<"results">> := [#{Identifier := Value} | _]}} when Value =/= null ->
dgiot_utils:to_int(Value);
_ ->
0
end
end);
_ ->
0
end;
Value ->
dgiot_utils:to_int(Value)
end.
%%
get_statistic(ProductId, DevAddr, Identifier, KeyValue, #{<<"type">> := <<"duration">>, <<"comparetype">> := Comparetype, <<"value">> := Value}, Acc) ->
Last_Value = get_last_value(ProductId, DevAddr, Identifier),
case compare(KeyValue, Comparetype, Value) of
true ->
Last_Value = get_last_value(ProductId, DevAddr, Identifier),
Time =
case dgiot_data:get({last_time, ProductId, DevAddr, Identifier}) of
{true, OldTime} ->
dgiot_datetime:now_secs() - OldTime;
_ ->
0
end,
dgiot_data:insert({last_time, ProductId, DevAddr, Identifier}, {true, dgiot_datetime:now_secs()}),
dgiot_data:insert({last_value, ProductId, DevAddr, Identifier}, Last_Value + Time),
Acc#{Identifier => Last_Value + Time};
_ ->
dgiot_data:insert({last_time, ProductId, DevAddr, Identifier}, {false, dgiot_datetime:now_secs()}),
Acc#{Identifier => Last_Value}
end;
%%
get_statistic(ProductId, DevAddr, Identifier, KeyValue, #{<<"type">> := <<"frequency">>, <<"comparetype">> := Comparetype, <<"value">> := Value}, Acc) ->
Num = get_last_value(ProductId, DevAddr, Identifier),
case compare(KeyValue, Comparetype, Value) of
true ->
dgiot_data:insert({last_value, ProductId, DevAddr, Identifier}, Num + 1),
Acc#{Identifier => Num + 1};
_ ->
Acc#{Identifier => Num}
end;
get_statistic(_, _, _, _, _, Acc) ->
Acc.
%%
get_calculated(Calculated, Props) ->
get_calculated(ProductId, DevAddr, Calculated, Props) ->
lists:foldl(fun(X, Acc) ->
case Acc of
error ->
Acc;
_ ->
case X of
#{<<"isaccumulate">> := true,
<<"isstorage">> := true,
<<"identifier">> := Identifier,
<<"dataForm">> := #{<<"strategy">> := <<"计算值"/utf8>>},
<<"dataSource">> := #{<<"key">> := Key} = DataSource
} ->
case maps:get(Key, Calculated, not_find) of
not_find ->
Acc;
KeyValue ->
get_statistic(ProductId, DevAddr, Identifier, dgiot_utils:to_int(KeyValue), DataSource, Acc)
end;
#{<<"isstorage">> := true,
<<"identifier">> := Identifier, <<"dataForm">> := #{
<<"strategy">> := <<"计算值"/utf8>>, <<"collection">> := Collection},
<<"dataType">> := #{<<"type">> := Type, <<"specs">> := Specs}} ->
<<"identifier">> := Identifier,
<<"dataForm">> := #{<<"strategy">> := <<"计算值"/utf8>>, <<"collection">> := Collection},
<<"dataType">> := #{<<"type">> := Type, <<"specs">> := Specs}
} ->
Str1 = maps:fold(fun(K, V, Acc2) ->
Str = re:replace(Acc2, dgiot_utils:to_list(<<"%%{", K/binary, "}">>), dgiot_utils:to_list(V), [global, {return, list}]),
re:replace(Str, "%{s}", dgiot_utils:to_list(V), [global, {return, list}])
@ -317,7 +484,7 @@ save_td(ProductId, DevAddr, Ack, _AppData) ->
%%
Collection = dgiot_task:get_collection(ProductId, [], CacheData, Props),
%%
AllData = dgiot_task:get_calculated(Collection, Props),
AllData = dgiot_task:get_calculated(ProductId, DevAddr, Collection, Props),
%%
Storage = dgiot_task:get_storage(AllData, Props),
case Interval > 0 of
@ -402,7 +569,7 @@ save_td_no_match(ProductId, DevAddr, Ack, AppData) ->
%%
Collection = dgiot_task:get_collection(ProductId, [], Ack, Props),
%%
Calculated = dgiot_task:get_calculated(Collection, Props),
Calculated = dgiot_task:get_calculated(ProductId, DevAddr, Collection, Props),
%%
Storage = dgiot_task:get_storage(Calculated, Props),
DeviceId = dgiot_parse_id:get_deviceid(ProductId, DevAddr),