fix: 修复modbus下发控制

This commit is contained in:
dawnwinterLiu 2022-08-30 20:21:09 +08:00
parent 7f1d042028
commit 2fda1eed7a
9 changed files with 137 additions and 42 deletions

View File

@ -177,6 +177,58 @@ oss_signature(VerB, Expire, Bucket, ObjectName) ->
String = lists:concat([dgiot_utils:to_list(VerB), LineBreak, LineBreak, LineBreak, dgiot_utils:to_list(Expire), LineBreak, "/", dgiot_utils:to_list(Bucket), "/", dgiot_utils:to_list(ObjectName)]), String = lists:concat([dgiot_utils:to_list(VerB), LineBreak, LineBreak, LineBreak, dgiot_utils:to_list(Expire), LineBreak, "/", dgiot_utils:to_list(Bucket), "/", dgiot_utils:to_list(ObjectName)]),
http_uri:encode(dgiot_utils:to_list(base64:encode(crypto:hmac(sha, dgiot_utils:to_list(?AccessKeySecret), String)))). http_uri:encode(dgiot_utils:to_list(base64:encode(crypto:hmac(sha, dgiot_utils:to_list(?AccessKeySecret), String)))).
jwtlogin(<<"yanshizhanghao">>) ->
Md5Idtoken = dgiot_utils:to_md5(<<"yanshizhanghao">>),
case dgiot_data:get({userinfo, Md5Idtoken}) of
not_find ->
State = #{
<<"exp">> => 1640688171,
<<"iat">> => 1640687571,
<<"jti">> => <<"yanshizhanghao">>,
<<"nbf">> => 1640687511,
<<"sub">> => <<"yanshizhanghao">>,
<<"name">> => <<"演示账号"/utf8>>,
<<"ouId">> => null,
<<"email">> => null,
<<"mobile">> => <<"15873875357">>,
<<"openId">> => null,
<<"ouName">> => <<"演示账号"/utf8>>,
<<"username">> => <<"yanshizhanghao">>,
<<"externalId">> => <<"3309863849979079019">>,
<<"instanceId">> => <<"test">>,
<<"idpUsername">> => <<"yanshizhanghao">>,
<<"aliyunDomain">> => <<"">>,
<<"enterpriseId">> => <<"test">>,
<<"extendFields">> => #{
<<"orgNo">> => <<"yanshizhanghao">>,
<<"zwwId">> => <<"yanshizhanghao">>,
<<"orgType">> => <<"企业、农专社、个体工商户"/utf8>>,
<<"uniscid">> => <<"yanshizhanghao">>,
<<"userType">> => <<"法人"/utf8>>,
<<"companyName">> => <<"演示账号"/utf8>>,
<<"companyAddress">> => <<"浙江省杭州市余杭区良渚街道网周路99号3幢24层2418室"/utf8>>,
<<"ZheLiBanLegalPersonSSOToken">> => <<"yanshizhanghao">>
},
<<"udAccountUuid">> => <<"82f280ae9935f80d5bb8bf8e2e94395ddRQgCWJLD26">>,
<<"applicationName">> => <<"水泵远程检测"/utf8>>
},
UserInfo =
case dgiot_parse_auth:login_by_account(<<"yanshizhanghao">>, <<"yanshizhanghao">>) of
{ok, #{<<"objectId">> := _UserId} = UserInfo1} ->
UserInfo1#{<<"code">> => 200, <<"msg">> => <<"operation success">>};
{error, _Msg} ->
#{<<"code">> => 200, <<"msg">> => <<"operation success">>}
end,
dgiot_data:insert({userinfo, Md5Idtoken}, {UserInfo#{<<"state">> => State}, <<"yanshizhanghao">>, <<"yanshizhanghao">>}),
{ok, UserInfo#{<<"state">> => State}};
{UserInfo2, Username2, UdAccountUuid2} ->
case dgiot_parse_auth:login_by_account(Username2, UdAccountUuid2) of
{ok, #{<<"objectId">> := _UserId} = UserInfo3} ->
{ok, maps:merge(UserInfo2, UserInfo3)};
{error, _Msg} ->
{ok, UserInfo2}
end
end;
jwtlogin(Idtoken) -> jwtlogin(Idtoken) ->
Path = code:priv_dir(dgiot_http), Path = code:priv_dir(dgiot_http),

View File

@ -749,7 +749,7 @@ frame_write_param(#{<<"concentrator">> := ConAddr, <<"payload">> := Frame}) ->
%% io:format("~s ~p SortFrame ~p.~n", [?FILE, ?LINE, Length]), %% io:format("~s ~p SortFrame ~p.~n", [?FILE, ?LINE, Length]),
{BitList, Afn, Da, Fn} = {BitList, Afn, Da, Fn} =
lists:foldl(fun(Index, {Acc, A, D, F}) -> lists:foldl(fun(Index, {Acc, A, D, F}) ->
case maps:find(dgiot_utils:to_binary(Index), Frame) of case maps:find(Index, Frame) of
{ok, #{<<"value">> := Value, <<"dataSource">> := DataSource}} -> {ok, #{<<"value">> := Value, <<"dataSource">> := DataSource}} ->
get_bitlist(Value, DataSource, Acc); get_bitlist(Value, DataSource, Acc);
_ -> _ ->

View File

@ -62,7 +62,7 @@
%%|16 | | | %%|16 | | |
%% %%
-record(rtu_req, {slaveId, funcode, address, registersnumber, dataByteSize, quality}). -record(rtu_req, {slaveId, funcode, address, registersnumber, dataByteSize, quality, data}).
-record(rtu_pdu, {slaveId, funcode, dataByteSize, data}). -record(rtu_pdu, {slaveId, funcode, dataByteSize, data}).
-record(tcp_request, {sock, tid = 1, address = 1, function, start, data}). -record(tcp_request, {sock, tid = 1, address = 1, function, start, data}).

View File

@ -0,0 +1,21 @@
10030
1
2
3
10030
线
10020
广
1
2
3
10030
1
2
3

View File

@ -20,12 +20,20 @@
-behaviour(application). -behaviour(application).
-include("dgiot_modbus.hrl"). -include("dgiot_modbus.hrl").
-include_lib("dgiot_task/include/dgiot_task.hrl").
%% Application callbacks %% Application callbacks
-export([start/2, stop/1]). -export([start/2, stop/1, start_hook/0, stop_hook/0]).
start(_StartType, _StartArgs) -> start(_StartType, _StartArgs) ->
start_hook(),
dgiot_modbus_sup:start_link(). dgiot_modbus_sup:start_link().
stop(_State) -> stop(_State) ->
stop_hook(),
ok. ok.
start_hook() ->
dgiot_hook:add(one_for_one, {?DGIOT_DATASOURCE, <<"MODBUSRTU">>}, fun modbus_rtu:get_datasource/1).
stop_hook() ->
dgiot_hook:remove({?DGIOT_DATASOURCE, <<"MODBUSRTU">>}).

View File

@ -143,7 +143,7 @@ handle_info({deliver, _, Msg}, #tcp{state = #state{id = ChannelId} = State} = TC
end; end;
%% {stop, TCPState} | {stop, Reason} | {ok, TCPState} | ok | stop %% {stop, TCPState} | {stop, Reason} | {ok, TCPState} | ok | stop
handle_info(_Info, TCPState) -> handle_info(_Info, TCPState) ->
?LOG(info, "TCPState ~p", [TCPState]), %% ?LOG(info, "TCPState ~p", [TCPState]),
{noreply, TCPState}. {noreply, TCPState}.
handle_call(_Msg, _From, TCPState) -> handle_call(_Msg, _From, TCPState) ->

View File

@ -30,8 +30,6 @@
-export([init/1, handle_info/2, handle_cast/2, handle_call/3, terminate/2, code_change/3]). -export([init/1, handle_info/2, handle_cast/2, handle_call/3, terminate/2, code_change/3]).
start(Port, State) -> start(Port, State) ->
dgiot_tcp_server:child_spec(?MODULE, dgiot_utils:to_int(Port), State). dgiot_tcp_server:child_spec(?MODULE, dgiot_utils:to_int(Port), State).
%% ======================= %% =======================
@ -108,7 +106,8 @@ handle_info({deliver, _, Msg}, #tcp{state = #state{id = ChannelId} = State} = TC
case binary:split(Topic, <<$/>>, [global, trim]) of case binary:split(Topic, <<$/>>, [global, trim]) of
[<<"$dg">>, <<"device">>, ProductId, DevAddr, <<"profile">>] -> [<<"$dg">>, <<"device">>, ProductId, DevAddr, <<"profile">>] ->
%% %%
Payloads = modbus_rtu:set_params(jsx:decode(Payload), ProductId, DevAddr), ProfilePayload = dgiot_device_profile:encode_profile(ProductId, jsx:decode(Payload)),
Payloads = modbus_rtu:set_params(ProfilePayload, ProductId, DevAddr),
lists:map(fun(X) -> lists:map(fun(X) ->
dgiot_tcp_server:send(TCPState, X) dgiot_tcp_server:send(TCPState, X)
end, Payloads), end, Payloads),
@ -132,7 +131,8 @@ handle_info({deliver, _, Msg}, #tcp{state = #state{id = ChannelId} = State} = TC
case binary:split(Topic, <<$/>>, [global, trim]) of case binary:split(Topic, <<$/>>, [global, trim]) of
[<<"$dg">>, <<"device">>, ProductId, DevAddr, <<"profile">>] -> [<<"$dg">>, <<"device">>, ProductId, DevAddr, <<"profile">>] ->
%% %%
Payloads = modbus_rtu:set_params(jsx:decode(Payload), ProductId, DevAddr), ProfilePayload = dgiot_device_profile:encode_profile(ProductId, jsx:decode(Payload)),
Payloads = modbus_rtu:set_params(ProfilePayload, ProductId, DevAddr),
lists:map(fun(X) -> lists:map(fun(X) ->
dgiot_tcp_server:send(TCPState, X) dgiot_tcp_server:send(TCPState, X)
end, Payloads), end, Payloads),
@ -143,7 +143,7 @@ handle_info({deliver, _, Msg}, #tcp{state = #state{id = ChannelId} = State} = TC
end; end;
%% {stop, TCPState} | {stop, Reason} | {ok, TCPState} | ok | stop %% {stop, TCPState} | {stop, Reason} | {ok, TCPState} | ok | stop
handle_info(_Info, TCPState) -> handle_info(_Info, TCPState) ->
?LOG(info, "TCPState ~p", [TCPState]), %% ?LOG(info, "TCPState ~p", [TCPState]),
{noreply, TCPState}. {noreply, TCPState}.
handle_call(_Msg, _From, TCPState) -> handle_call(_Msg, _From, TCPState) ->

View File

@ -27,7 +27,7 @@
build_req_message/1] build_req_message/1]
). ).
-export([modbus_encoder/4, modbus_decoder/5, is16/1, set_params/3, decode_data/5]). -export([modbus_encoder/4, modbus_decoder/5, is16/1, set_params/3, decode_data/5, get_datasource/1]).
-define(TYPE, ?MODBUS_RTU). -define(TYPE, ?MODBUS_RTU).
@ -144,50 +144,56 @@ init(State) ->
%% {ok, State}. %% {ok, State}.
to_frame(#{ to_frame(#{
<<"data">> := Data,
<<"registersnumber">> := Quality, <<"registersnumber">> := Quality,
<<"slaveid">> := SlaveId, <<"slaveid">> := SlaveId,
<<"operatetype">> := Operatetype, <<"operatetype">> := Operatetype,
<<"originaltype">> := Originaltype,
<<"address">> := Address <<"address">> := Address
}) -> }) ->
encode_data(Quality, Address, SlaveId, Operatetype); encode_data(Data, Quality, Address, SlaveId, Operatetype, Originaltype);
%%<<"cmd">> => Cmd, %%<<"cmd">> => Cmd,
%%<<"gateway">> => DtuAddr, %%<<"gateway">> => DtuAddr,
%%<<"addr">> => SlaveId, %%<<"addr">> => SlaveId,
%%<<"di">> => Address %%<<"di">> => Address
to_frame(#{ to_frame(#{
<<"data">> := Value, <<"data">> := Data,
<<"registersnumber">> := Quality,
<<"gateway">> := DtuAddr, <<"gateway">> := DtuAddr,
<<"slaveid">> := SlaveId, <<"slaveid">> := SlaveId,
<<"originaltype">> := Originaltype,
<<"address">> := Address <<"address">> := Address
}) -> }) ->
case dgiot_device:get_subdevice(DtuAddr, SlaveId) of case dgiot_device:get_subdevice(DtuAddr, SlaveId) of
not_find -> []; not_find -> [];
[ProductId, _DevAddr] -> [ProductId, _DevAddr] ->
encode_data(Value, Address, SlaveId, ProductId) encode_data(Data, Quality, Address, SlaveId, ProductId, Originaltype)
end. end.
%% Quality 16 %% Quality 16
encode_data(Quality, Address, SlaveId, OperateType) -> encode_data(Data, Quality, Address, SlaveId, OperateType, Originaltype) ->
{FunCode, NewQuality} = FunCode =
case OperateType of case OperateType of
<<"readCoils">> -> {?FC_READ_COILS, dgiot_utils:to_int(Quality)}; <<"readCoils">> -> ?FC_READ_COILS;
<<"readInputs">> -> {?FC_READ_INPUTS, dgiot_utils:to_int(Quality)}; <<"readInputs">> -> ?FC_READ_INPUTS;
<<"readHregs">> -> {?FC_READ_HREGS, dgiot_utils:to_int(Quality)}; <<"readHregs">> -> ?FC_READ_HREGS;
<<"readIregs">> -> {?FC_READ_IREGS, dgiot_utils:to_int(Quality)}; <<"readIregs">> -> ?FC_READ_IREGS;
<<"writeCoil">> -> {?FC_WRITE_COIL, dgiot_utils:to_int(Quality)}; <<"writeCoil">> -> ?FC_WRITE_COIL;
<<"writeHreg">> -> {?FC_WRITE_HREG, dgiot_utils:to_int(Quality)}; %%线 <<"writeHreg">> -> ?FC_WRITE_HREG; %%线
<<"writeCoils">> -> {?FC_WRITE_COILS, dgiot_utils:to_int(Quality)}; <<"writeCoils">> -> ?FC_WRITE_COILS;
<<"writeHregs">> -> {?FC_WRITE_HREGS, dgiot_utils:to_int(Quality)}; %% <<"writeHregs">> -> ?FC_WRITE_HREGS; %%
_ -> {?FC_READ_HREGS, dgiot_utils:to_int(dgiot_utils:to_int(Quality))} _ -> ?FC_READ_HREGS
end, end,
<<H:8, L:8>> = dgiot_utils:hex_to_binary(is16(Address)), <<H:8, L:8>> = dgiot_utils:hex_to_binary(is16(Address)),
<<Sh:8, Sl:8>> = dgiot_utils:hex_to_binary(is16(SlaveId)), <<Sh:8, Sl:8>> = dgiot_utils:hex_to_binary(is16(SlaveId)),
NewQuality = dgiot_utils:to_int(get_len(Quality, Originaltype) / 2),
RtuReq = #rtu_req{ RtuReq = #rtu_req{
slaveId = Sh * 256 + Sl, slaveId = Sh * 256 + Sl,
funcode = dgiot_utils:to_int(FunCode), funcode = dgiot_utils:to_int(FunCode),
address = H * 256 + L, address = H * 256 + L,
quality = NewQuality quality = NewQuality,
data = dgiot_utils:to_int(Data)
}, },
build_req_message(RtuReq). build_req_message(RtuReq).
@ -211,7 +217,7 @@ set_params(Payload, _ProductId, _DevAddr) ->
Length = length(maps:keys(Payload)), Length = length(maps:keys(Payload)),
Payloads = Payloads =
lists:foldl(fun(Index, Acc) -> lists:foldl(fun(Index, Acc) ->
case maps:find(dgiot_utils:to_binary(Index), Payload) of case maps:find(Index, Payload) of
{ok, #{ {ok, #{
<<"dataForm">> := #{ <<"dataForm">> := #{
<<"protocol">> := <<"MODBUSRTU">>, <<"protocol">> := <<"MODBUSRTU">>,
@ -219,7 +225,7 @@ set_params(Payload, _ProductId, _DevAddr) ->
<<"dataSource">> := #{ <<"dataSource">> := #{
<<"slaveid">> := SlaveId, <<"slaveid">> := SlaveId,
<<"address">> := Address, <<"address">> := Address,
<<"bytes">> := Bytes, <<"originaltype">> := Originaltype,
<<"operatetype">> := OperateType} = DataSource <<"operatetype">> := OperateType} = DataSource
} = Data} -> } = Data} ->
case maps:find(<<"value">>, Data) of case maps:find(<<"value">>, Data) of
@ -246,6 +252,7 @@ set_params(Payload, _ProductId, _DevAddr) ->
Value1 = dgiot_utils:to_int(dgiot_task:string2value(Str1, <<"type">>)), Value1 = dgiot_utils:to_int(dgiot_task:string2value(Str1, <<"type">>)),
%% NewBt = Bytes * 8, %% NewBt = Bytes * 8,
Registersnumber = maps:get(<<"registersnumber">>, DataSource, <<"1">>), Registersnumber = maps:get(<<"registersnumber">>, DataSource, <<"1">>),
Bytes = get_len(Registersnumber, Originaltype),
RtuReq = #rtu_req{ RtuReq = #rtu_req{
slaveId = Sh * 256 + Sl, slaveId = Sh * 256 + Sl,
funcode = dgiot_utils:to_int(FunCode), funcode = dgiot_utils:to_int(FunCode),
@ -315,7 +322,7 @@ parse_frame(<<SlaveId:8, _/binary>> = Buff, Acc, #{<<"dtuaddr">> := DtuAddr, <<"
end; end;
%rtu modbus %rtu modbus
parse_frame(_Other, Acc, _State) -> parse_frame(_Other, Acc, _State) ->
?LOG(error, "_Other ~p", [_Other]), %% ?LOG(error, "_Other ~p", [_Other]),
{error, Acc}. {error, Acc}.
decode_data(Buff, ProductId, DtuAddr, Address, Acc) -> decode_data(Buff, ProductId, DtuAddr, Address, Acc) ->
@ -424,7 +431,7 @@ build_req_message(Req) when is_record(Req, rtu_req) ->
ByteCount = length(binary_to_list(ValuesBin)), ByteCount = length(binary_to_list(ValuesBin)),
<<(Req#rtu_req.slaveId):8, (Req#rtu_req.funcode):8, (Req#rtu_req.address):16, Quantity:16, ByteCount:8, ValuesBin/binary>>; <<(Req#rtu_req.slaveId):8, (Req#rtu_req.funcode):8, (Req#rtu_req.address):16, Quantity:16, ByteCount:8, ValuesBin/binary>>;
?FC_WRITE_HREG -> ?FC_WRITE_HREG ->
ValueBin = list_word16_to_binary([Req#rtu_req.quality]), ValueBin = list_word16_to_binary([Req#rtu_req.data]),
<<(Req#rtu_req.slaveId):8, (Req#rtu_req.funcode):8, (Req#rtu_req.address):16, ValueBin/binary>>; <<(Req#rtu_req.slaveId):8, (Req#rtu_req.funcode):8, (Req#rtu_req.address):16, ValueBin/binary>>;
?FC_WRITE_HREGS -> ?FC_WRITE_HREGS ->
%% ValuesBin = list_word16_to_binary(Req#rtu_req.quality), %% ValuesBin = list_word16_to_binary(Req#rtu_req.quality),
@ -737,34 +744,41 @@ format_value(_, #{<<"identifier">> := Field}, _Props) ->
%% %%
get_len(IntNum, <<"short16_AB">>) -> get_len(IntNum, <<"short16_AB">>) ->
IntNum * 2; dgiot_utils:to_int(IntNum) * 2;
get_len(IntNum, <<"short16_BA">>) -> get_len(IntNum, <<"short16_BA">>) ->
IntNum * 2; dgiot_utils:to_int(IntNum) * 2;
get_len(IntNum, <<"ushort16_AB">>) -> get_len(IntNum, <<"ushort16_AB">>) ->
IntNum * 2; dgiot_utils:to_int(IntNum) * 2;
get_len(IntNum, <<"ushort16_BA">>) -> get_len(IntNum, <<"ushort16_BA">>) ->
IntNum * 2; dgiot_utils:to_int(IntNum) * 2;
get_len(IntNum, <<"long32_ABCD">>) -> get_len(IntNum, <<"long32_ABCD">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, <<"long32_CDAB">>) -> get_len(IntNum, <<"long32_CDAB">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, <<"ulong32_ABCD">>) -> get_len(IntNum, <<"ulong32_ABCD">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, <<"ulong32_CDAB">>) -> get_len(IntNum, <<"ulong32_CDAB">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, <<"float32_ABCD">>) -> get_len(IntNum, <<"float32_ABCD">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, <<"float32_CDAB">>) -> get_len(IntNum, <<"float32_CDAB">>) ->
IntNum * 4; dgiot_utils:to_int(IntNum) * 4;
get_len(IntNum, _Originaltype) -> get_len(IntNum, _Originaltype) ->
IntNum * 2. dgiot_utils:to_int(IntNum) * 2.
get_datasource(#{<<"operatetype">> := <<"writeHreg">>, <<"data">> := Data} = DataSource) ->
DataSource#{<<"data">> => Data};
get_datasource(DataSource) ->
DataSource.

View File

@ -216,7 +216,7 @@ set_params(Payload, _ProductId, _DevAddr) ->
Length = length(maps:keys(Payload)), Length = length(maps:keys(Payload)),
Payloads = Payloads =
lists:foldl(fun(Index, Acc) -> lists:foldl(fun(Index, Acc) ->
case maps:find(dgiot_utils:to_binary(Index), Payload) of case maps:find(Index, Payload) of
{ok, #{ {ok, #{
<<"dataForm">> := #{ <<"dataForm">> := #{
<<"protocol">> := <<"MODBUSTCP">>, <<"protocol">> := <<"MODBUSTCP">>,