fix donghuoliren

This commit is contained in:
anlicheng 2024-12-13 18:02:52 +08:00
parent efaa6f2fcd
commit fb3f21411c
7 changed files with 251 additions and 46 deletions

View 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])).

View File

@ -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) ->

View File

@ -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} ->

View File

@ -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, []},

View File

@ -71,6 +71,12 @@
]}
]},
%% 智慧监控平台
{donghuoliren, [
{url, "https://xsdc.njau.edu.cn/hq-cyaqjg/rest/rgkSmart/push"},
{token, <<"aB3$dEfGhiJkLmNoPqRsTuVwXyZ!@#4f5e6d7c8b9a0f1e2d">>}
]},
{pools, [
%% mysql连接池配置
{mysql_iot,

View File

@ -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},

View File

@ -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 朴苑餐厅