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} |
|
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||||
{stop, Reason :: term(), NewState :: #state{}}).
|
{stop, Reason :: term(), NewState :: #state{}}).
|
||||||
handle_cast({forward, LocationCode, DynamicLocationCode, EventType, Params}, State = #state{id = Id, timer_map = TimerMap, pri_key = PriKey, url = Url}) ->
|
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
|
ReqBody = format_event(LocationCode, DynamicLocationCode, EventType, Params, PriKey),
|
||||||
error ->
|
|
||||||
{noreply, State};
|
|
||||||
{ok, ReqBody} ->
|
|
||||||
Res = catch do_post(Url, Id, ReqBody),
|
Res = catch do_post(Url, Id, ReqBody),
|
||||||
lager:debug("[iot_jinzhi_endpoint] format_data: ~p, post result: ~p", [ReqBody, Res]),
|
lager:debug("[iot_jinzhi_endpoint] format_data: ~p, post result: ~p", [ReqBody, Res]),
|
||||||
TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}),
|
TimerRef = erlang:start_timer(?RETRY_INTERVAL, self(), {repost_ticker, Id, ReqBody}),
|
||||||
|
|
||||||
{noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}}
|
{noreply, State#state{id = Id + 1, timer_map = maps:put(Id, TimerRef, TimerMap)}}.
|
||||||
end.
|
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
%% @doc Handling all non call/cast messages
|
%% @doc Handling all non call/cast messages
|
||||||
@ -180,15 +177,10 @@ do_post(Url, Id, Body) when is_list(Url), is_integer(Id), is_binary(Body) ->
|
|||||||
end).
|
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)
|
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) ->
|
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}) ->
|
Attachments = lists:map(fun(#{<<"filename">> := Filename}) ->
|
||||||
{ok, FileUrl} = iot_util:file_uri(Filename),
|
{ok, FileUrl} = iot_util:file_uri(Filename),
|
||||||
Name = filename:basename(FileUrl),
|
Name = filename:basename(FileUrl),
|
||||||
@ -214,8 +206,7 @@ format_event(LocationCode, DynamicLocationCode, EventType, #{<<"event_code">> :=
|
|||||||
<<"count">> => 1,
|
<<"count">> => 1,
|
||||||
<<"deviceInfo">> => DeviceInfo
|
<<"deviceInfo">> => DeviceInfo
|
||||||
},
|
},
|
||||||
{ok, iolist_to_binary(jiffy:encode(ReqData, [force_utf8]))}
|
iolist_to_binary(jiffy:encode(ReqData, [force_utf8])).
|
||||||
end.
|
|
||||||
|
|
||||||
-spec generate_task_id(LocationCode :: binary(), EventCode :: binary()) -> binary().
|
-spec generate_task_id(LocationCode :: binary(), EventCode :: binary()) -> binary().
|
||||||
generate_task_id(LocationCode, EventCode) when is_binary(LocationCode), is_binary(EventCode) ->
|
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
|
case redis_client:hgetall(RouterUUID) of
|
||||||
{ok, #{<<"location_code">> := LocationCode, <<"dynamic_location_code">> := DynamicLocationCode}} when is_binary(LocationCode), is_binary(DynamicLocationCode) ->
|
{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, _} ->
|
{ok, _} ->
|
||||||
lager:debug("[iot_ai_router] the event_data hget location_code, uuid: ~p, not found", [RouterUUID]);
|
lager:debug("[iot_ai_router] the event_data hget location_code, uuid: ~p, not found", [RouterUUID]);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
|||||||
@ -82,6 +82,15 @@ init([]) ->
|
|||||||
modules => ['iot_zd_endpoint']
|
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',
|
id => 'iot_zd_consumer',
|
||||||
start => {'iot_zd_consumer', start_link, []},
|
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, [
|
{pools, [
|
||||||
%% mysql连接池配置
|
%% mysql连接池配置
|
||||||
{mysql_iot,
|
{mysql_iot,
|
||||||
|
|||||||
@ -58,6 +58,12 @@
|
|||||||
{pool_size, 10}
|
{pool_size, 10}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
|
%% 智慧监控平台
|
||||||
|
{donghuoliren, [
|
||||||
|
{url, "https://xsdc.njau.edu.cn/hq-cyaqjg/rest/rgkSmart/push"},
|
||||||
|
{token, <<"aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d">>}
|
||||||
|
]},
|
||||||
|
|
||||||
%% influxdb数据库配置
|
%% influxdb数据库配置
|
||||||
{influx_pool, [
|
{influx_pool, [
|
||||||
{pool_size, 100},
|
{pool_size, 100},
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
# 事件分类
|
# 事件分类
|
||||||
|
|
||||||
```text
|
```text
|
||||||
23103 鼠类监测 event_code: 11
|
event_code: 23103 鼠类监测 event_type: 11
|
||||||
20407 异物占道 event_code: 13
|
event_code: 20407 异物占道 event_type: 13
|
||||||
10404 垃圾溢满 event_code: 14
|
event_code: 10404 垃圾溢满 event_type: 14
|
||||||
22503 后厨非标着装 event_code: 12
|
event_code: 22503 后厨非标着装 event_type: 12
|
||||||
23104 动火离人 event_code: 15
|
event_code: 23104 动火离人 event_type: 15
|
||||||
22706 强弱电间违规进入 event_code: 16
|
event_code: 22706 强弱电间违规进入 event_type: 16
|
||||||
```
|
```
|
||||||
|
|
||||||
1、鼠类检测 0508103010001050300001 朴苑餐厅
|
1、鼠类检测 0508103010001050300001 朴苑餐厅
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user