fix donghuoliren
This commit is contained in:
parent
efaa6f2fcd
commit
fb3f21411c
186
apps/iot/src/endpoint/iot_donghuoliren_endpoint.erl
Normal file
186
apps/iot/src/endpoint/iot_donghuoliren_endpoint.erl
Normal file
@ -0,0 +1,186 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author anlicheng
|
||||
%%% @copyright (C) 2024, <COMPANY>
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 13. 12月 2024 16:20
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(iot_donghuoliren_endpoint).
|
||||
-author("anlicheng").
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
-export([forward/4, get_status/0]).
|
||||
-export([test/0]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-record(state, {
|
||||
%% 签名用的token值
|
||||
token :: binary(),
|
||||
url :: string(),
|
||||
succ_counter = 0,
|
||||
fail_counter = 0,
|
||||
logger_pid :: pid()
|
||||
}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
|
||||
test() ->
|
||||
forward(<<"1234">>, <<"1234">>, 17, #{
|
||||
<<"datetime">> => <<"2024-12-12 03:10:29">>,
|
||||
<<"attachments">> => []
|
||||
}).
|
||||
|
||||
-spec forward(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map()) -> no_return().
|
||||
forward(LocationCode, DynamicLocationCode, EventType, Params) when is_binary(LocationCode), is_binary(DynamicLocationCode), is_integer(EventType), is_map(Params) ->
|
||||
gen_server:cast(?MODULE, {forward, LocationCode, DynamicLocationCode, EventType, Params}).
|
||||
|
||||
-spec get_status() -> {ok, map()}.
|
||||
get_status() ->
|
||||
gen_server:call(?MODULE, get_status).
|
||||
|
||||
%% @doc Spawns the server and registers the local name (unique)
|
||||
-spec(start_link() ->
|
||||
{ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%%%===================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%===================================================================
|
||||
|
||||
%% @private
|
||||
%% @doc Initializes the server
|
||||
-spec(init(Args :: term()) ->
|
||||
{ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term()} | ignore).
|
||||
init([]) ->
|
||||
{ok, Props} = application:get_env(iot, donghuoliren),
|
||||
Token = proplists:get_value(token, Props),
|
||||
Url = proplists:get_value(url, Props),
|
||||
|
||||
{ok, LoggerPid} = iot_logger:start_link("donghuoliren_data"),
|
||||
|
||||
{ok, #state{token = Token, url = Url, logger_pid = LoggerPid}}.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling call messages
|
||||
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
|
||||
State :: #state{}) ->
|
||||
{reply, Reply :: term(), NewState :: #state{}} |
|
||||
{reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
|
||||
{noreply, NewState :: #state{}} |
|
||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
|
||||
{stop, Reason :: term(), NewState :: #state{}}).
|
||||
handle_call(get_status, _From, State = #state{succ_counter = SuccCounter, fail_counter = FailCounter}) ->
|
||||
{reply, {ok, #{succ => SuccCounter, fail => FailCounter}}, State}.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling cast messages
|
||||
-spec(handle_cast(Request :: term(), State :: #state{}) ->
|
||||
{noreply, NewState :: #state{}} |
|
||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term(), NewState :: #state{}}).
|
||||
handle_cast({forward, LocationCode, DynamicLocationCode, EventType, Params},
|
||||
State = #state{url = Url, token = Token, logger_pid = LoggerPid, succ_counter = SuccCounter, fail_counter = FailCounter}) ->
|
||||
|
||||
Body = format_event(LocationCode, DynamicLocationCode, EventType, Params),
|
||||
case do_post(Url, Token, Body) of
|
||||
{ok, RespBody} ->
|
||||
%% 记录日志
|
||||
iot_logger:write(LoggerPid, [<<"OK">>, Body, RespBody]),
|
||||
{noreply, State#state{succ_counter = SuccCounter + 1}};
|
||||
{error, Reason} ->
|
||||
NReason = iolist_to_binary(io_lib:format("~p", Reason)),
|
||||
iot_logger:write(LoggerPid, [<<"ERROR">>, Body, NReason]),
|
||||
{noreply, State#state{fail_counter = FailCounter + 1}}
|
||||
end.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling all non call/cast messages
|
||||
-spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
|
||||
{noreply, NewState :: #state{}} |
|
||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term(), NewState :: #state{}}).
|
||||
handle_info(_Info, State = #state{}) ->
|
||||
{noreply, State}.
|
||||
|
||||
%% @private
|
||||
%% @doc This function is called by a gen_server when it is about to
|
||||
%% terminate. It should be the opposite of Module:init/1 and do any
|
||||
%% necessary cleaning up. When it returns, the gen_server terminates
|
||||
%% with Reason. The return value is ignored.
|
||||
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
|
||||
State :: #state{}) -> term()).
|
||||
terminate(_Reason, _State = #state{}) ->
|
||||
ok.
|
||||
|
||||
%% @private
|
||||
%% @doc Convert process state when code is changed
|
||||
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
|
||||
Extra :: term()) ->
|
||||
{ok, NewState :: #state{}} | {error, Reason :: term()}).
|
||||
code_change(_OldVsn, State = #state{}, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
||||
-spec do_post(Url :: string(), Token :: binary(), Body :: binary()) -> {ok, Resp :: binary()} | {error, any()}.
|
||||
do_post(Url, Token, Body) when is_binary(Body) ->
|
||||
Headers = [
|
||||
{<<"content-type">>, <<"application/json">>}
|
||||
],
|
||||
Sign = iot_util:md5(iolist_to_binary([Token, Body, Token])),
|
||||
|
||||
Url1 = Url ++ "?sign=" ++ binary_to_list(Sign),
|
||||
case hackney:request(post, Url1, Headers, Body) of
|
||||
{ok, 200, _, ClientRef} ->
|
||||
{ok, RespBody} = hackney:body(ClientRef),
|
||||
hackney:close(ClientRef),
|
||||
{ok, RespBody};
|
||||
{ok, HttpCode, _, ClientRef} ->
|
||||
{ok, RespBody} = hackney:body(ClientRef),
|
||||
hackney:close(ClientRef),
|
||||
{error, {HttpCode, RespBody}};
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
%% 格式话要发送的数据,避免多次格式化处理
|
||||
-spec format_event(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map()) -> Body :: binary().
|
||||
format_event(LocationCode, DynamicLocationCode, EventType,
|
||||
#{<<"datetime">> := Datetime, <<"attachments">> := Attachments0})
|
||||
when is_binary(LocationCode), is_binary(DynamicLocationCode), is_integer(EventType) ->
|
||||
|
||||
%Attachments = lists:map(fun(#{<<"filename">> := Filename}) ->
|
||||
% {ok, FileUrl} = iot_util:file_uri(Filename),
|
||||
% Name = filename:basename(FileUrl),
|
||||
% #{<<"name">> => Name, <<"url">> => FileUrl}
|
||||
% end, Attachments0),
|
||||
|
||||
Attachments = [
|
||||
<<"https://lgsiot.njau.edu.cn/upload/2024/11/29/2024-11-29-1732842080-1732842100.mp4">>,
|
||||
<<"https://lgsiot.njau.edu.cn/upload/2024/11/29/2024-11-29-1732842080-1732842100.jpg">>
|
||||
],
|
||||
|
||||
Params = #{
|
||||
<<"eventLocation">> => <<"事件地点测试值"/utf8>>,
|
||||
<<"eventType">> => <<"动火离人"/utf8>>,
|
||||
<<"eventTime">> => Datetime,
|
||||
<<"videoJkAddr">> => <<"rtsp://admin:admin@123@192.168.111.147/cam/realmonitor?channel=1&subtype=0">>,
|
||||
<<"attachments">> => Attachments
|
||||
},
|
||||
|
||||
iolist_to_binary(jiffy:encode(Params, [force_utf8])).
|
||||
@ -93,16 +93,13 @@ handle_call(_Request, _From, State = #state{}) ->
|
||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||
{stop, Reason :: term(), NewState :: #state{}}).
|
||||
handle_cast({forward, LocationCode, DynamicLocationCode, EventType, Params}, State = #state{id = Id, timer_map = TimerMap, pri_key = PriKey, url = Url}) ->
|
||||
case format_event(LocationCode, DynamicLocationCode, EventType, Params, PriKey) of
|
||||
error ->
|
||||
{noreply, State};
|
||||
{ok, ReqBody} ->
|
||||
Res = catch do_post(Url, Id, ReqBody),
|
||||
lager:debug("[iot_jinzhi_endpoint] format_data: ~p, post result: ~p", [ReqBody, Res]),
|
||||
TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}),
|
||||
ReqBody = format_event(LocationCode, DynamicLocationCode, EventType, Params, PriKey),
|
||||
|
||||
{noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}}
|
||||
end.
|
||||
Res = catch do_post(Url, Id, ReqBody),
|
||||
lager:debug("[iot_jinzhi_endpoint] format_data: ~p, post result: ~p", [ReqBody, Res]),
|
||||
TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}),
|
||||
|
||||
{noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}}.
|
||||
|
||||
%% @private
|
||||
%% @doc Handling all non call/cast messages
|
||||
@ -180,42 +177,36 @@ do_post(Url, Id, Body) when is_list(Url), is_integer(Id), is_binary(Body) ->
|
||||
end).
|
||||
|
||||
%% 格式话要发送的数据,避免多次格式化处理
|
||||
-spec format_event(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map(), PriKey :: public_key:private_key()) -> error | {ok, binary()}.
|
||||
-spec format_event(LocationCode :: binary(), DynamicLocationCode :: binary(), EventType :: integer(), Params :: map(), PriKey :: public_key:private_key()) -> binary().
|
||||
format_event(LocationCode, DynamicLocationCode, EventType, #{<<"event_code">> := EventCode, <<"description">> := Description, <<"datetime">> := Datetime, <<"attachments">> := Attachments0}, PriKey)
|
||||
when is_binary(LocationCode), is_binary(DynamicLocationCode), is_integer(EventType) ->
|
||||
|
||||
%% 动火离人不推送给金智 2024-12-02
|
||||
case lists:member(EventCode, [<<"23104">>]) of
|
||||
true ->
|
||||
error;
|
||||
false ->
|
||||
Attachments = lists:map(fun(#{<<"filename">> := Filename}) ->
|
||||
{ok, FileUrl} = iot_util:file_uri(Filename),
|
||||
Name = filename:basename(FileUrl),
|
||||
#{<<"name">> => Name, <<"url">> => FileUrl}
|
||||
end, Attachments0),
|
||||
Attachments = lists:map(fun(#{<<"filename">> := Filename}) ->
|
||||
{ok, FileUrl} = iot_util:file_uri(Filename),
|
||||
Name = filename:basename(FileUrl),
|
||||
#{<<"name">> => Name, <<"url">> => FileUrl}
|
||||
end, Attachments0),
|
||||
|
||||
% <<"occurrenceTime">> => <<"2023-06-10 12:00:00">>,
|
||||
% <<"occurrenceTime">> => <<"2023-06-10 12:00:00">>,
|
||||
|
||||
LocationCode1 = fake_location_code(EventCode, LocationCode),
|
||||
DeviceInfo = #{
|
||||
% <<"location">> => LocationCode,
|
||||
<<"location">> => LocationCode1,
|
||||
<<"category">> => EventCode,
|
||||
<<"description">> => Description,
|
||||
<<"occurrenceTime">> => Datetime,
|
||||
<<"attachments">> => Attachments
|
||||
},
|
||||
LocationCode1 = fake_location_code(EventCode, LocationCode),
|
||||
DeviceInfo = #{
|
||||
% <<"location">> => LocationCode,
|
||||
<<"location">> => LocationCode1,
|
||||
<<"category">> => EventCode,
|
||||
<<"description">> => Description,
|
||||
<<"occurrenceTime">> => Datetime,
|
||||
<<"attachments">> => Attachments
|
||||
},
|
||||
|
||||
ReqData = #{
|
||||
<<"sign">> => sign(DeviceInfo, PriKey),
|
||||
<<"sysId">> => ?SYS_ID,
|
||||
<<"taskId">> => generate_task_id(LocationCode1, EventCode),
|
||||
<<"count">> => 1,
|
||||
<<"deviceInfo">> => DeviceInfo
|
||||
},
|
||||
{ok, iolist_to_binary(jiffy:encode(ReqData, [force_utf8]))}
|
||||
end.
|
||||
ReqData = #{
|
||||
<<"sign">> => sign(DeviceInfo, PriKey),
|
||||
<<"sysId">> => ?SYS_ID,
|
||||
<<"taskId">> => generate_task_id(LocationCode1, EventCode),
|
||||
<<"count">> => 1,
|
||||
<<"deviceInfo">> => DeviceInfo
|
||||
},
|
||||
iolist_to_binary(jiffy:encode(ReqData, [force_utf8])).
|
||||
|
||||
-spec generate_task_id(LocationCode :: binary(), EventCode :: binary()) -> binary().
|
||||
generate_task_id(LocationCode, EventCode) when is_binary(LocationCode), is_binary(EventCode) ->
|
||||
|
||||
@ -18,7 +18,14 @@ route_uuid(RouterUUID, EventType, Params) when is_binary(RouterUUID), is_integer
|
||||
%% 查找终端设备对应的点位信息
|
||||
case redis_client:hgetall(RouterUUID) of
|
||||
{ok, #{<<"location_code">> := LocationCode, <<"dynamic_location_code">> := DynamicLocationCode}} when is_binary(LocationCode), is_binary(DynamicLocationCode) ->
|
||||
iot_jinzhi_endpoint:forward(LocationCode, DynamicLocationCode, EventType, Params);
|
||||
%% 动火离人不推送给金智 2024-12-02
|
||||
case lists:member(EventType, [17]) of
|
||||
true ->
|
||||
lager:debug("[iot_ai_router] donghuoliren: ~p", [RouterUUID]);
|
||||
%iot_donghuoliren_endpoint:forward(LocationCode, DynamicLocationCode, EventType, Params);
|
||||
false ->
|
||||
iot_jinzhi_endpoint:forward(LocationCode, DynamicLocationCode, EventType, Params)
|
||||
end;
|
||||
{ok, _} ->
|
||||
lager:debug("[iot_ai_router] the event_data hget location_code, uuid: ~p, not found", [RouterUUID]);
|
||||
{error, Reason} ->
|
||||
|
||||
@ -82,6 +82,15 @@ init([]) ->
|
||||
modules => ['iot_zd_endpoint']
|
||||
},
|
||||
|
||||
#{
|
||||
id => 'iot_donghuoliren_endpoint',
|
||||
start => {'iot_donghuoliren_endpoint', start_link, []},
|
||||
restart => permanent,
|
||||
shutdown => 2000,
|
||||
type => worker,
|
||||
modules => ['iot_donghuoliren_endpoint']
|
||||
},
|
||||
|
||||
#{
|
||||
id => 'iot_zd_consumer',
|
||||
start => {'iot_zd_consumer', start_link, []},
|
||||
|
||||
@ -71,6 +71,12 @@
|
||||
]}
|
||||
]},
|
||||
|
||||
%% 智慧监控平台
|
||||
{donghuoliren, [
|
||||
{url, "https://xsdc.njau.edu.cn/hq-cyaqjg/rest/rgkSmart/push"},
|
||||
{token, <<"aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d">>}
|
||||
]},
|
||||
|
||||
{pools, [
|
||||
%% mysql连接池配置
|
||||
{mysql_iot,
|
||||
|
||||
@ -58,6 +58,12 @@
|
||||
{pool_size, 10}
|
||||
]},
|
||||
|
||||
%% 智慧监控平台
|
||||
{donghuoliren, [
|
||||
{url, "https://xsdc.njau.edu.cn/hq-cyaqjg/rest/rgkSmart/push"},
|
||||
{token, <<"aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d">>}
|
||||
]},
|
||||
|
||||
%% influxdb数据库配置
|
||||
{influx_pool, [
|
||||
{pool_size, 100},
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# 事件分类
|
||||
|
||||
```text
|
||||
23103 鼠类监测 event_code: 11
|
||||
20407 异物占道 event_code: 13
|
||||
10404 垃圾溢满 event_code: 14
|
||||
22503 后厨非标着装 event_code: 12
|
||||
23104 动火离人 event_code: 15
|
||||
22706 强弱电间违规进入 event_code: 16
|
||||
event_code: 23103 鼠类监测 event_type: 11
|
||||
event_code: 20407 异物占道 event_type: 13
|
||||
event_code: 10404 垃圾溢满 event_type: 14
|
||||
event_code: 22503 后厨非标着装 event_type: 12
|
||||
event_code: 23104 动火离人 event_type: 15
|
||||
event_code: 22706 强弱电间违规进入 event_type: 16
|
||||
```
|
||||
|
||||
1、鼠类检测 0508103010001050300001 朴苑餐厅
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user