feat: device lookup

This commit is contained in:
AvantLiu 2022-01-24 14:21:38 +08:00
parent ef4b154746
commit 5a92781954
5 changed files with 98 additions and 38 deletions

View File

@ -49,22 +49,25 @@ post(Device) ->
Devaddr = maps:get(<<"devaddr">>, Device),
Product = maps:get(<<"product">>, Device),
ProductId = maps:get(<<"objectId">>, Product),
<<DeviceSecretdefult:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
DeviceSecret = maps:get(<<"deviceSecret">>, Device, DeviceSecretdefult),
Status =
case maps:get(<<"status">>, Device, <<"OFFLINE">>) of
<<"OFFLINE">> -> false;
_ -> true
end,
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), DeviceName, Devaddr, ProductId], node()}).
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), DeviceName, Devaddr, ProductId, DeviceSecret], node()}).
put(Device) ->
DeviceId = maps:get(<<"objectId">>, Device),
case lookup(DeviceId) of
{ok, {[Status, _, Acl, DeviceName, Devaddr, ProductId], Node}} ->
{ok, #{<<"status">> := Status, <<"acl">> := Acl,
<<"devaddr">> := Devaddr, <<"productid">> := ProductId, <<"devicesecret">> := DeviceSecret, <<"node">> := Node}} ->
case maps:find(<<"ACL">>, Device) of
error ->
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), Acl, DeviceName, Devaddr, ProductId], Node});
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), Acl, Devaddr, ProductId, DeviceSecret], Node});
{ok, _} ->
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), DeviceName, Devaddr, ProductId], Node})
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), Devaddr, ProductId, DeviceSecret], Node})
end;
_ ->
pass
@ -76,6 +79,8 @@ save(Device) ->
Devaddr = maps:get(<<"devaddr">>, Device),
Product = maps:get(<<"product">>, Device),
ProductId = maps:get(<<"objectId">>, Product),
<<DeviceSecretdefult:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
DeviceSecret = maps:get(<<"deviceSecret">>, Device, DeviceSecretdefult),
UpdatedAt =
case maps:get(<<"updatedAt">>, Device, dgiot_datetime:now_secs()) of
<<Data:10/binary, "T", Time:8/binary, _/binary>> ->
@ -87,7 +92,7 @@ save(Device) ->
<<"OFFLINE">> -> false;
_ -> true
end,
dgiot_mnesia:insert(DeviceId, {[Status, UpdatedAt, get_acl(Device), DeviceName, Devaddr, ProductId], node()}).
dgiot_mnesia:insert(DeviceId, {[Status, UpdatedAt, get_acl(Device), DeviceName, Devaddr, ProductId, DeviceSecret], node()}).
get_acl(Device) when is_map(Device) ->
ACL = maps:get(<<"ACL">>, Device, #{}),
@ -97,7 +102,7 @@ get_acl(Device) when is_map(Device) ->
get_acl(DeviceId) when is_binary(DeviceId) ->
case lookup(DeviceId) of
{ok, {[_, _, [Acl | _], _, _, _], _}} ->
{ok, #{<<"acl">> := Acl}} ->
BinAcl = atom_to_binary(Acl),
#{BinAcl => #{
<<"read">> => true,
@ -122,15 +127,17 @@ get_acl(_DeviceId) ->
online(DeviceId) ->
case lookup(DeviceId) of
{ok, {[Status, _Now, Acl, DeviceName, Devaddr, ProductId], Node}} ->
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs() + 72000, Acl, DeviceName, Devaddr, ProductId], Node});
{ok, #{<<"status">> := Status, <<"acl">> := Acl,
<<"devaddr">> := Devaddr, <<"productid">> := ProductId, <<"devicesecret">> := DeviceSecret, <<"node">> := Node}} ->
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs() + 72000, Acl, Devaddr, ProductId, DeviceSecret], Node});
_ -> pass
end.
offline(DeviceId) ->
case lookup(DeviceId) of
{ok, {[Status, Now, Acl, DeviceName, Devaddr, ProductId], Node}} ->
dgiot_mnesia:insert(DeviceId, {[Status, Now - 72000, Acl, DeviceName, Devaddr, ProductId], Node}),
{ok, #{<<"status">> := Status, <<"time">> := Now, <<"acl">> := Acl,
<<"devaddr">> := Devaddr, <<"productid">> := ProductId, <<"devicesecret">> := DeviceSecret, <<"node">> := Node}} ->
dgiot_mnesia:insert(DeviceId, {[Status, Now - 72000, Acl, Devaddr, ProductId, DeviceSecret], Node}),
offline_child(DeviceId);
_ -> pass
end.
@ -156,7 +163,7 @@ sync_parse(OffLine) ->
{_, DeviceId, V} = X,
Now = dgiot_datetime:now_secs(),
case V of
{[_, Last, Acl, DeviceName, Devaddr, ProductId], Node} when (Now - Last) < 0 ->
{[_, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < 0 ->
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
{ok, _R} ->
Productname =
@ -167,12 +174,12 @@ sync_parse(OffLine) ->
<<"">>
end,
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
dgiot_mnesia:insert(DeviceId, {[true, Now, Acl, DeviceName, Devaddr, ProductId], Node});
dgiot_mnesia:insert(DeviceId, {[true, Now, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
_ ->
pass
end,
timer:sleep(50);
{[true, Last, Acl, DeviceName, Devaddr, ProductId], Node} when (Now - Last) > OffLine ->
{[true, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) > OffLine ->
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"OFFLINE">>}) of
{ok, _R} ->
Productname =
@ -184,12 +191,12 @@ sync_parse(OffLine) ->
end,
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"下线"/utf8>>}, ['device_statuslog']),
dgiot_umeng:save_devicestatus(DeviceId, <<"OFFLINE">>),
dgiot_mnesia:insert(DeviceId, {[false, Last, Acl, DeviceName, Devaddr, ProductId], Node});
dgiot_mnesia:insert(DeviceId, {[false, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
_ ->
pass
end,
timer:sleep(50);
{[false, Last, Acl, DeviceName, Devaddr, ProductId], Node} when (Now - Last) < OffLine ->
{[false, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < OffLine ->
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
{ok, _R} ->
Productname =
@ -200,7 +207,7 @@ sync_parse(OffLine) ->
<<"">>
end,
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
dgiot_mnesia:insert(DeviceId, {[true, Last, Acl, DeviceName, Devaddr, ProductId], Node});
dgiot_mnesia:insert(DeviceId, {[true, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
_ ->
pass
end,
@ -216,8 +223,9 @@ lookup(DeviceId) ->
case dgiot_mnesia:lookup(DeviceId) of
{aborted, Reason} ->
{error, Reason};
{ok, [{mnesia, _K, V}]} ->
{ok, V};
{ok, [{mnesia, _K, {[Status, Time, Acl, Devaddr, ProductId, DeviceSecret], Node}}]} ->
{ok, #{<<"status">> => Status, <<"time">> => Time, <<"acl">> => Acl,
<<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"devicesecret">> => DeviceSecret, <<"node">> => Node}};
_ ->
{error, not_find}
end.
@ -349,6 +357,7 @@ create_device(#{
_R ->
{{Y, M, D}, {_, _, _}} = dgiot_datetime:local_time(),
Batch_name = dgiot_utils:to_list(Y) ++ dgiot_utils:to_list(M) ++ dgiot_utils:to_list(D),
<<DeviceSecret:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
NewDevice = Device#{
<<"location">> => maps:get(<<"location">>, Device, #{<<"__type">> => <<"GeoPoint">>, <<"longitude">> => 120.161324, <<"latitude">> => 30.262441}),
<<"basedata">> => maps:get(<<"basedata">>, Device, #{}),
@ -359,6 +368,7 @@ create_device(#{
<<"objectId">> => ProductId
},
<<"ACL">> => maps:without([<<"*">>], Acl),
<<"deviceSecret">> => DeviceSecret,
<<"detail">> => #{
<<"desc">> => Name,
<<"brand">> => Brand,
@ -422,7 +432,7 @@ get_online(DeviceId) ->
OffLine = dgiot_data:get({device, offline}),
Now = dgiot_datetime:now_secs(),
case lookup(DeviceId) of
{ok, {[_, Ts, _, _, _, _], _}} when Now - Ts < OffLine ->
{ok, #{<<"time">> := Ts}} when Now - Ts < OffLine ->
true;
_ ->
false
@ -497,7 +507,7 @@ get_url(AppName) ->
get_appname(DeviceId) ->
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, [Acl | _], _, _, _], _}} ->
{ok, #{<<"acl">> := Acl}} ->
BinAcl = atom_to_binary(Acl),
case BinAcl of
<<"role:", Name/binary>> ->
@ -511,12 +521,11 @@ get_appname(DeviceId) ->
save_log(DeviceId, Payload, Domain) ->
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, _, DeviceName, Devaddr, ProductId], _}} ->
{ok, #{<<"devaddr">> := Devaddr, <<"productid">> := ProductId}} ->
?MLOG(info, #{
<<"deviceid">> => DeviceId,
<<"devaddr">> => Devaddr,
<<"productid">> => ProductId,
<<"devicename">> => DeviceName,
<<"msg">> => Payload}, Domain);
_ ->
pass
@ -524,7 +533,7 @@ save_log(DeviceId, Payload, Domain) ->
sub_topic(DeviceId, Type) ->
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, _, _DeviceName, Devaddr, ProductId], _}} ->
{ok, #{<<"devaddr">> := Devaddr, <<"productid">> := ProductId}} ->
Topic = <<"thing/", ProductId/binary, "/", Devaddr/binary, "/", Type/binary>>,
dgiot_mqtt:subscribe(Topic);
_ -> pass

View File

@ -215,7 +215,7 @@ save_notification(Ruleid, DevAddr, Payload) ->
[ProductId, _] ->
DeviceId = dgiot_parse:get_deviceid(ProductId, DevAddr),
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, Acl, _, _, _], _}} ->
{ok, #{<<"acl">> := Acl}} ->
Requests =
lists:foldl(fun(X, Acc) ->
BinX = atom_to_binary(X),
@ -393,7 +393,7 @@ save_devicestatus(DeviceId, Status) ->
end,
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, Acl, _, Devaddr, ProductId], _}} ->
{ok, #{<<"acl">> := Acl, <<"devaddr">> := Devaddr, <<"productid">> := ProductId}} ->
Ruleid = <<ProductId/binary, "_status">>,
Productname =
case dgiot_parse:get_object(<<"Product">>, ProductId) of

View File

@ -27,7 +27,7 @@
build_req_message/1]
).
-export([modbus_encoder/4, modbus_decoder/5, is16/1, set_params/3]).
-export([modbus_encoder/4, modbus_decoder/5, is16/1, set_params/3, decode_data/4, decode_data/5]).
init(State) ->
State#{<<"req">> => [], <<"ts">> => dgiot_datetime:now_ms(), <<"interval">> => 300}.
@ -160,13 +160,6 @@ set_params(Basedata, ProductId, DevAddr) ->
quality = Value1
},
DeviceId = dgiot_parse:get_deviceid(ProductId, DevAddr),
DeviceName =
case dgiot_device:lookup(DeviceId) of
{ok, {[_, _, _, DeviceName1, _, _], _}} ->
DeviceName1;
_ ->
<<"">>
end,
Sessiontoken = maps:get(<<"sessiontoken">>, Basedata, <<"">>),
{Username, Acl} =
case dgiot_auth:get_session(Sessiontoken) of
@ -175,7 +168,12 @@ set_params(Basedata, ProductId, DevAddr) ->
_ ->
{<<"">>, #{}}
end,
?MLOG(info, #{<<"clientid">> => DeviceId, <<"username">> => Username, <<"status">> => <<"ONLINE">>, <<"ACL">> => Acl, <<"devaddr">> => DevAddr, <<"productid">> => ProductId, <<"devicename">> => DeviceName, <<"productname">> => Productname, <<"thingname">> => Name, <<"protocol">> => <<"modbus">>, <<"identifier">> => Identifier, <<"value">> => Value1}, ['device_operationlog']),
?MLOG(info, #{<<"clientid">> => DeviceId, <<"username">> => Username,
<<"status">> => <<"ONLINE">>, <<"ACL">> => Acl,
<<"devaddr">> => DevAddr, <<"productid">> => ProductId,
<<"productname">> => Productname, <<"thingname">> => Name,
<<"protocol">> => <<"modbus">>, <<"identifier">> => Identifier, <<"value">> => Value1},
['device_operationlog']),
Acc ++ [build_req_message(RtuReq)];
_ ->
Acc
@ -217,6 +215,16 @@ parse_frame(<<MbAddr:8, BadCode:8, ErrorCode:8, Crc:2/binary>> = Buff, Acc,
parse_frame(Buff, Acc, State)
end;
%% modbustcp
%% Buff = <<"000100000006011000000001">>,
parse_frame(<<_TransactionId:16, _ProtocolId:16, Size:16, _ResponseData:Size/bytes>> = Buff, Acc, #{<<"dtuproduct">> := ProductId, <<"dtuaddr">> := DtuAddr} = State) ->
case decode_data(Buff, ProductId, DtuAddr, Acc) of
{Rest1, Acc1} ->
parse_frame(Rest1, Acc1, State);
[Buff, Acc] ->
[Buff, Acc]
end;
%% dtu物模型的一个指标
parse_frame(<<SlaveId:8, _/binary>> = Buff, Acc, #{<<"dtuproduct">> := ProductId, <<"slaveId">> := SlaveId, <<"dtuaddr">> := DtuAddr, <<"address">> := Address} = State) ->
case decode_data(Buff, ProductId, DtuAddr, Address, Acc) of
@ -244,6 +252,9 @@ parse_frame(_Other, Acc, _State) ->
?LOG(error, "_Other ~p", [_Other]),
{error, Acc}.
decode_data(<<TransactionId:16, _ProtocolId:16, _Size1:16, Address:8, _FunCode:8, Data/binary>>, ProductId, _DtuAddr, Acc) ->
{<<>>, modbus_tcp_decoder(ProductId, TransactionId, Address, Data, Acc)}.
decode_data(Buff, ProductId, DtuAddr, Address, Acc) ->
<<SlaveId:8, FunCode:8, ResponseData/binary>> = Buff,
{SizeOfData, DataBytes} =
@ -432,6 +443,38 @@ list_word16_to_binary(Values) when is_list(Values) ->
)
).
modbus_tcp_decoder(ProductId, TransactionId, Address, Data, Acc1) ->
case dgiot_product:lookup_prod(ProductId) of
{ok, #{<<"thing">> := #{<<"properties">> := Props}}} ->
lists:foldl(fun(X, Acc) ->
case X of
#{<<"identifier">> := Identifier,
<<"dataForm">> := #{
<<"slaveid">> := OldSlaveid,
<<"address">> := OldAddress,
<<"protocol">> := <<"modbus">>
}} ->
<<H:8, L:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldSlaveid)),
<<Sh:8, Sl:8>> = dgiot_utils:hex_to_binary(modbus_rtu:is16(OldAddress)),
NewSlaveid = H * 256 + L,
NewAddress = Sh * 256 + Sl,
case {TransactionId, Address} of
{NewSlaveid, NewAddress} ->
case format_value(Data, X) of
{Value, _Rest} ->
Acc#{Identifier => Value};
_ -> Acc
end;
_ ->
Acc
end;
_ ->
Acc
end
end, Acc1, Props);
_ -> #{}
end.
modbus_decoder(ProductId, SlaveId, Address, Data, Acc1) ->
case dgiot_product:lookup_prod(ProductId) of
{ok, #{<<"thing">> := #{<<"properties">> := Props}}} ->

View File

@ -401,7 +401,7 @@ get_Product() ->
{ok, #{<<"results">> := Results}} ->
lists:foldl(fun(X, _Acc) ->
case X of
#{<<"objectId">> := ProductId, <<"config">> := #{<<"konva">> := #{<<"Stage">> := #{<<"children">> := Children}}}, <<"thing">> := #{<<"properties">> := Properties}} ->
#{<<"objectId">> := ProductId, <<"thing">> := #{<<"properties">> := Properties}} ->
lists:map(fun(P) ->
DataType = maps:get(<<"dataType">>, P, #{}),
Type = maps:get(<<"type">>, DataType, <<"">>),
@ -412,7 +412,15 @@ get_Product() ->
dgiot_data:insert({product, <<ProductId/binary, Identifier/binary>>}, {Name, Type, Unit}),
dgiot_data:insert({thing, <<ProductId/binary, Identifier/binary>>}, P)
end, Properties),
get_children(<<"web">>, ProductId, Children, ProductId, <<"KonvatId">>, <<"Shapeid">>, <<"Identifier">>, <<"Name">>);
case dgiot_parse:query_object(<<"View">>, #{<<"limit">> => 1, <<"where">> => #{<<"key">> => ProductId, <<"type">> => <<"topo">>, <<"class">> => <<"Product">>}}) of
{ok, #{<<"results">> := Views}} when length(Views) > 0 ->
lists:foldl(fun(View, _Acc1) ->
#{<<"data">> := #{<<"konva">> := #{<<"Stage">> := #{<<"children">> := Children}}}} = View,
get_children(<<"web">>, ProductId, Children, ProductId, <<"KonvatId">>, <<"Shapeid">>, <<"Identifier">>, <<"Name">>)
end, #{}, Views);
_ ->
pass
end;
_ ->
pass
end