From 1abf585f99d430fdb331cb9c68b1dc49e8016a82 Mon Sep 17 00:00:00 2001 From: dawnwinterLiu <1737801684@qq.com> Date: Thu, 18 Aug 2022 10:15:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9F=AD=E4=BF=A1=E5=91=8A=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/dgiot_notification_channel.erl | 18 ++ apps/dgiot_http/etc/dgiot_http.conf | 10 +- apps/dgiot_http/priv/dgiot_http.schema | 12 +- .../dgiot_http/priv/swagger/swagger_http.json | 161 ++++++++++++++++++ apps/dgiot_http/src/dgiot_http_handler.erl | 94 ++++++++++ .../src/umeng/dgiot_notification.erl | 110 ++++++++---- apps/dgiot_modbus/src/dgiot_modbusc_tcp.erl | 2 +- 7 files changed, 365 insertions(+), 42 deletions(-) diff --git a/apps/dgiot_device/src/dgiot_notification_channel.erl b/apps/dgiot_device/src/dgiot_notification_channel.erl index 9ecc10a2..1d3f3c59 100644 --- a/apps/dgiot_device/src/dgiot_notification_channel.erl +++ b/apps/dgiot_device/src/dgiot_notification_channel.erl @@ -116,6 +116,24 @@ handle_message({rule, #{clientid := _DevAddr, disconnected_at := _DisconnectedAt %% SELECT payload.electricity as electricity FROM "$dg/user/alarm/94656917ab/157d0ff60f/#" where electricity > 20 handle_message({rule, #{metadata := #{rule_id := <<"rule:Notification_", Ruleid/binary>>}, clientid := DeviceId, payload := _Payload, topic := _Topic} = _Msg, Context}, State) -> dgiot_umeng:add_notification(Ruleid, DeviceId, Context), + case dgiot_parse:get_object(<<"_Role">>, application:get_env(dgiot_http, tencent_sms_sign,"ae746ee803")) of + {ok,#{<<"objectId">> := RolesId}} -> + %循环得到部门下所有的手机号 + Users =dgiot_parse_auth:get_UserIds(unicode:characters_to_binary(RolesId)), + UsersQuery = #{<<"where">> => #{<<"objectId">> => #{<<"$in">> => Users}}}, + {ok, #{<<"results">> := Row}}=dgiot_parse:query_object(<<"_User">>, UsersQuery), + Params= lists:foldl(fun(X,Acc)-> + Acc++[X++":"++DeviceId] + end,[],application:get_env(dgiot_http, tencent_sms_params,["aaa","bbb","ccc","ddd","eee","fff"])), + lists:foldl(fun(X,Acc)-> + Phone=unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>,X))), + dgiot_notification:send_sms(Phone,Params), + Acc ++ [unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>,X)))] + end,[],Row); +% 模板格式:时间:{1} {2}(发起人:{3})(单据编号{4})(车间:{5})产生异常,警告等级为:{6}。 + _ -> + pass + end, {ok, State}; handle_message({sync_parse, Pid, 'after', get, _Token, <<"Notification">>, #{<<"results">> := _Results} = ResBody}, State) -> diff --git a/apps/dgiot_http/etc/dgiot_http.conf b/apps/dgiot_http/etc/dgiot_http.conf index 2fea7bb2..4ef7eaa3 100644 --- a/apps/dgiot_http/etc/dgiot_http.conf +++ b/apps/dgiot_http/etc/dgiot_http.conf @@ -13,7 +13,7 @@ aliyun.uploadCallbackUrl= http://127.0.0.1:8081 aliyun.uploadHost= http://dgiotpump.oss-cn-shanghai.aliyuncs.com #百度地图 -baidumap.appkey = S7pehghn5BdQeSGZAcpEk4bLQSQ8czvi +baidumap.appkey = WpeAb6pL4tsX2ZVd56GHbO9Ut6c4HZhG #百度地图纠偏值 baidumap.lngoffset = 0.00000 baidumap.latoffset = 0.00000 @@ -28,10 +28,10 @@ wechat.appid = wxb37f3990d2424ea0 wechat.secret = 0c8b9e229ebe48c6878727a9d2e0263d #腾讯云短信 -tencent_sms.appid = 1400214975 -tencent_sms.appkey = 25c8c3a4d17367a8232931ff54d114a2 -tencent_sms.tmplid = 340847 -tencent_sms.sign = dgiot +tencent_sms.appid = 1400635630 +tencent_sms.appkey = 40d9609b9e6212cbff051b4f1d4cabfc +tencent_sms.notification.templateId = 1473069 +tencent_sms.sign = ae746ee803 # jwt jwt.algorithm = rs256 diff --git a/apps/dgiot_http/priv/dgiot_http.schema b/apps/dgiot_http/priv/dgiot_http.schema index 0b7baa61..ccc48c8b 100644 --- a/apps/dgiot_http/priv/dgiot_http.schema +++ b/apps/dgiot_http/priv/dgiot_http.schema @@ -28,27 +28,25 @@ %%-------------------------------------------------------------------- {mapping, "tencent_sms.appid", "dgiot_http.tencent_sms_appid", [ -{default, "1400214975"}, +{default, "1400635630"}, {datatype, string} ]}. {mapping, "tencent_sms.appkey", "dgiot_http.tencent_sms_appkey", [ -{default, "25c8c3a4d17367a8232931ff54d114a2"}, +{default, "40d9609b9e6212cbff051b4f1d4cabfc"}, {datatype, string} ]}. -{mapping, "tencent_sms.tmplid", "dgiot_http.tencent_sms_tmplid", [ -{default, "340847"}, +{mapping, "tencent_sms.notification.templateId", "dgiot_http.tencent_sms_notification_templateId", [ +{default, "1473069"}, {datatype, string} ]}. {mapping, "tencent_sms.sign", "dgiot_http.tencent_sms_sign", [ -{default, "dgiot"}, +{default, "ae746ee803"}, {datatype, string} ]}. - - %%-------------------------------------------------------------------- %% 百度地图配置 %%-------------------------------------------------------------------- diff --git a/apps/dgiot_http/priv/swagger/swagger_http.json b/apps/dgiot_http/priv/swagger/swagger_http.json index 96956313..059ca71c 100644 --- a/apps/dgiot_http/priv/swagger/swagger_http.json +++ b/apps/dgiot_http/priv/swagger/swagger_http.json @@ -8,6 +8,166 @@ "definitions": { }, "paths": { + "/handlewarnsendsms": { + "post": { + "security": [], + "summary": "短信配置发送", + "description": "短信配置发送", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "user", + "required": true, + "schema": { + "type": "object", + "properties": { + "appId": { + "required": true, + "type": "string", + "example": "1400635630" + }, + "appKey": { + "required": true, + "type": "string", + "example": "40d9609b9e6212cbff051b4f1d4cabfc" + }, + "tplId": { + "required": true, + "type": "string", + "example": "1473069" + }, + "sign": { + "required": true, + "type": "string", + "example": "ae746ee803" + }, + "params": { + "required": true, + "type": "object", + "example": ["测试1","测试2","测试3","测试4","测试5","测试6"] + } + } + } + } + ], + "responses": { + "200": { + "description": "Returns success" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "500": { + "description": "Server Internal error", + "schema": { + "$ref": "#/definitions/Error" + } + } + }, + "tags": [ + "Notification" + ] + } + }, + "/warnsendsms": { + "post": { + "security": [], + "summary": "短信告警发送", + "description": "短信告警发送", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "user", + "required": true, + "schema": { + "type": "object", + "properties": { + "objectId": { + "required": true, + "type": "string", + "example": "dasssd54" + }, + "branchId": { + "required": true, + "type": "string", + "example": "9256b5cf2e" + }, + "docnumber": { + "required": true, + "type": "string", + "example": "MO000015" + }, + "datetimes": { + "required": true, + "type": "string", + "example": "2022-12-15,14:20" + }, + "username": { + "required": true, + "type": "string", + "example": "张三" + }, + "workshop": { + "required": true, + "type": "string", + "example": "车间1-1" + }, + "level": { + "required": true, + "type": "string", + "example": "1" + }, + "desc": { + "required": true, + "type": "string", + "example": "desc" + }, + "file": { + "required": true, + "type": "string", + "example": "img" + } + } + } + } + ], + "responses": { + "200": { + "description": "Returns success" + }, + "400": { + "description": "Bad Request" + }, + "404": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "500": { + "description": "Server Internal error", + "schema": { + "$ref": "#/definitions/Error" + } + } + }, + "tags": [ + "Notification" + ] + } + }, "/wechat": { "get": { "security": [], @@ -40,6 +200,7 @@ "Notification" ] }, + "post": { "security": [], "summary": "wechat绑定", diff --git a/apps/dgiot_http/src/dgiot_http_handler.erl b/apps/dgiot_http/src/dgiot_http_handler.erl index ccd39e96..c65b0dcb 100644 --- a/apps/dgiot_http/src/dgiot_http_handler.erl +++ b/apps/dgiot_http/src/dgiot_http_handler.erl @@ -74,6 +74,100 @@ do_request(get_file_signature, Args, _Context, _Req) -> _ -> {404, #{<<"code">> => 1001, <<"error">> => <<"not support this type">>}} end; +%dgiot通用告警 +do_request(post_handlewarnsendsms, #{<<"appId">> := AppId, <<"appKey">> := AppKey, <<"tplId">> := TplId, <<"sign">> := Sign, <<"params">> := Params}, _Context, _Req) -> + %通用 + application:set_env(dgiot_http, tencent_sms_appid, AppId), + application:set_env(dgiot_http, tencent_sms_appkey, AppKey), + application:set_env(dgiot_http, tencent_sms_notification_templateId, TplId), + %测试告警通知的部门,默认为数蛙部门 + application:set_env(dgiot_http, tencent_sms_sign, Sign), + application:set_env(dgiot_http, tencent_sms_params, Params), + + case dgiot_parse:get_object(<<"_Role">>, Sign) of + {ok, #{<<"objectId">> := RolesId}} -> + %循环得到部门下所有的手机号 + Users = dgiot_parse_auth:get_UserIds(unicode:characters_to_binary(RolesId)), + UsersQuery = #{<<"where">> => #{<<"objectId">> => #{<<"$in">> => Users}}}, + {ok, #{<<"results">> := Row}} = dgiot_parse:query_object(<<"_User">>, UsersQuery), + PhoneList = lists:foldl(fun(X, Acc) -> + Phone = unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>, X))), + dgiot_notification:send_sms(Phone, application:get_env(dgiot_http, tencent_sms_params, Params)), + Acc ++ [unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>, X)))] + end, [], Row), +% 模板格式:时间:{1} {2}(发起人:{3})(单据编号{4})(车间:{5})产生异常,警告等级为:{6}。 + Json = #{<<"phones">> => PhoneList}, + {ok, #{ + <<"status">> => 200, + <<"msg">> => <<"success">>, + <<"data">> => Json + }}; + _ -> + {error, #{<<"status">> => 404, <<"msg">> => <<"部门ID错误"/utf8>>, <<"result">> => <<"_Role info null">>}} + end; + +%数字工厂告警 +do_request(post_warnsendsms, #{<<"objectId">> := DeviceId, <<"branchId">> := BranchId, <<"datetimes">> := DateTimes, <<"docnumber">> := Docnumber, <<"username">> := UserName, <<"workshop">> := Workshop, <<"level">> := Level, <<"desc">> := Desc, <<"file">> := FileInfo}, _Context, _Req) -> + + case Level of + <<"1">> -> + Warn = <<"待首检"/utf8>>, + dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"realstatus">> => 3}); + <<"2">> -> + Warn = <<"待尾检"/utf8>>, + dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"realstatus">> => 5}); + _ -> + Warn = <<"告警"/utf8>>, + {error, #{code => 1, error => ("level错误")}} + end, + Warns = Warn, + case dgiot_parse:get_object(<<"_Role">>, BranchId) of + {ok, #{<<"objectId">> := RolesId, <<"ACL">> := Acl}} -> + + Map = #{ + <<"type">> => DeviceId, + <<"name">> => <<"Manual alarm">>, + <<"status">> => 0, + <<"content">> => #{ + <<"alarm">> => #{ + <<"deviceId"/utf8>> => DeviceId, + <<"docnumber"/utf8>> => Docnumber, + <<"datetimes"/utf8>> => DateTimes, + <<"username"/utf8>> => UserName, + <<"workshop"/utf8>> => Workshop, + <<"level"/utf8>> => Level, + <<"desc"/utf8>> => Desc, + <<"imgurl"/utf8>> => FileInfo + }, + <<"alertstatus">> => 1 + }, + <<"ACL">> => Acl + }, + #{<<"objectId">> := ObjectId} = dgiot_parse_id:get_objectid(<<"Notification">>, Map), + NewMap = Map#{ + <<"objectId">> => ObjectId + }, + dgiot_parse:create_object(<<"Notification">>, NewMap), + %循环得到部门下所有的手机号 + Users = dgiot_parse_auth:get_UserIds(unicode:characters_to_binary(RolesId)), + UsersQuery = #{<<"where">> => #{<<"objectId">> => #{<<"$in">> => Users}}}, + {ok, #{<<"results">> := Row}} = dgiot_parse:query_object(<<"_User">>, UsersQuery), + PhoneList = lists:foldl(fun(X, Acc) -> + Phone = unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>, X))), + dgiot_notification:send_sms(Phone, [DateTimes, <<"-">>, UserName, Docnumber, Workshop, Warns]), + Acc ++ [unicode:characters_to_binary(dgiot_utils:to_list(maps:get(<<"phone">>, X)))] + end, [], Row), +% 模板格式:时间:{1} {2}(发起人:{3})(单据编号{4})(车间:{5})产生异常,警告等级为:{6}。 + Json = #{<<"phones">> => PhoneList}, + {ok, #{ + <<"status">> => 200, + <<"msg">> => <<"success">>, + <<"data">> => Json + }}; + _ -> + {error, #{<<"status">> => 404, <<"msg">> => <<"部门ID错误"/utf8>>, <<"result">> => <<"_Role info null">>}} + end; + %% iot_hub 概要: 查询平台api资源 描述:jwt回调 %% OperationId:get_jwtlogin %% 请求:POST /iotapi/get_jwtlogin diff --git a/apps/dgiot_http/src/umeng/dgiot_notification.erl b/apps/dgiot_http/src/umeng/dgiot_notification.erl index 17b7063a..c76c01ab 100644 --- a/apps/dgiot_http/src/umeng/dgiot_notification.erl +++ b/apps/dgiot_http/src/umeng/dgiot_notification.erl @@ -21,7 +21,7 @@ -dgiot_data("ets"). -export([init_ets/0]). %% API --export([send_sms/3, send_sms/4, send_sms/5]). +-export([send_sms/2, send_sms/3, send_sms/5, send_sms/6, send_sms/7]). -export([send_email/1, test_email/0]). @@ -41,8 +41,7 @@ send_verification_code(NationCode, Key) -> rand:seed(exs1024), Rand = 10000 + erlang:round(rand:uniform() * 10000), TTL = 3, - Tpml = dgiot:get_env(dgiot_http, tencent_sms_tmplid,""), - case dgiot_notification:send_sms(NationCode, Key, Tpml, [Rand, TTL]) of + case dgiot_notification:send_sms(NationCode, Key, [Rand, TTL]) of {ok, _Ext} -> dgiot_cache:set(Key, Rand, TTL * 60), {ok, #{<<"expire">> => TTL * 60}}; @@ -62,46 +61,99 @@ check_verification_code(Key, Code) -> -send_sms(Mobile, TplId, Params) -> - send_sms("+86", Mobile, TplId, Params). -send_sms(NationCode, Mobile, TplId, Params) -> - send_sms(NationCode, Mobile, TplId, Params, <<>>). -send_sms(NationCode, Mobile, TplId, Params, Ext) -> - Random = integer_to_list(1000 + rand:uniform(1000)), - AppId = dgiot:get_env(dgiot_http, tencent_sms_appid,""), - AppKey = dgiot:get_env(dgiot_http, tencent_sms_appkey,""), - BaseUrl = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=~s&random=~s", - Url = io_lib:format(BaseUrl, [AppId, Random]), - Now = dgiot_datetime:nowstamp(), - case re:run(NationCode, <<"\\+(\\d{1,3})">>, [{capture, all, binary}]) of +send_sms(Mobile, Params) -> + send_sms("+86", Mobile, Params). +send_sms(NationCode, Mobile, Params) -> + TplId = dgiot_utils:to_list(application:get_env(dgiot_http, tencent_sms_notification_templateId, <<"">>)), + AppId = dgiot_utils:to_list(application:get_env(dgiot_http, tencent_sms_appid, <<"">>)), + AppKey = dgiot_utils:to_list(application:get_env(dgiot_http, tencent_sms_appkey, <<"">>)), + send_sms(NationCode, Mobile, Params, AppId, AppKey, TplId). +send_sms(Mobile, Params, AppId, AppKey, TplId) -> + send_sms("+86", Mobile, Params, AppId, AppKey, TplId, <<>>). +send_sms(NationCode, Mobile, Params, AppId, AppKey, TplId) -> + send_sms(NationCode, Mobile, Params, AppId, AppKey, TplId, <<>>). +send_sms(NationCode, Mobile, Params, AppId, AppKey, TplId, Ext) -> + AppId_b = + case is_binary(AppId) of + true -> + binary_to_list(AppId); + _ -> + AppId + end, + Random = dgiot_utils:to_list(1000 + rand:uniform(1000)), + Url = + case is_list(Mobile) of + true -> + "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2?sdkappid=" ++ AppId_b ++ "&random=" ++ Random; + false -> + "https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=" ++ AppId_b ++ "&random=" ++ Random + end, + case re:run(NationCode, <<"\\+(\\d{1,3})">>, [{capture, all, binary}]) of % "+86" 自动转换二进制 {match, [_, NationCode1]} -> + + {MobileStr, Tel_b} = + case is_list(Mobile) of + true -> %%短信多发 + ListMobile = lists:foldl(fun(#{<<"mobile">> := Num}, Acc) -> Acc ++ [binary_to_list(Num)] + end, [], Mobile), + {string:join(ListMobile, ","), Mobile}; + _ -> %%短信单发 + case is_binary(Mobile) of + true -> + {Mobile, #{<<"mobile">> => Mobile, <<"nationcode">> => NationCode1}}; + _ -> + {Mobile, #{<<"mobile">> => unicode:characters_to_binary(Mobile), <<"nationcode">> => NationCode1}} + end + end, + Now = dgiot_datetime:nowstamp(), + AppKey_b = + case is_binary(AppKey) of + true -> + binary_to_list(AppKey); + _ -> + AppKey + end, + SigStr = io_lib:format("appkey=~s&random=~s&time=~s&mobile=~s", [AppKey_b, Random, integer_to_list(Now), MobileStr]), + Sig_b = dgiot_utils:to_binary(string:to_lower(binary_to_list(<<<> || <> <= crypto:hash(sha256, SigStr), Y <- integer_to_list(X, 16)>>))), + FunParams = + fun(X, Acc) -> + case is_binary(X) of + true -> + Acc ++ [X]; + _ -> + Acc ++ [unicode:characters_to_binary(X)] + end + end, + Params_b = lists:foldl(FunParams, [], Params), + case is_binary(TplId) of + true -> + TplId_b = TplId; + _ -> + TplId_b = unicode:characters_to_binary(TplId) + end, Data = #{ - <<"tpl_id">> => dgiot_utils:to_binary(TplId), + <<"tpl_id">> => TplId_b, <<"ext">> => Ext, <<"extend">> => <<>>, - <<"params">> => Params, - <<"sign">> => dgiot_utils:to_binary(dgiot:get_env(dgiot_http, tencent_sms_sign,"")), - <<"tel">> => #{ - <<"mobile">> => case is_binary(Mobile) of true -> Mobile; false -> list_to_binary(Mobile) end, - <<"nationcode">> => NationCode1 - }, - <<"time">> => Now + <<"params">> => Params_b, + <<"sign">> => <<"dgiot"/utf8>>, + <<"tel">> => Tel_b, + <<"time">> => Now, + <<"sig">> => Sig_b }, - SigStr = io_lib:format("appkey=~s&random=~s&time=~s&mobile=~s", [AppKey, Random, integer_to_list(Now), Mobile]), - Sig = string:to_lower(binary_to_list(<<<> || <> <= crypto:hash(sha256, SigStr), Y <- integer_to_list(X, 16)>>)), - Body = Data#{<<"sig">> => list_to_binary(Sig)}, - Request = {Url, [], "application/json", jsx:encode(Body)}, + Request = {Url, [], "application/json", jsx:encode(Data)}, + case catch httpc:request(post, Request, [], [{body_format, binary}]) of {ok, {{_HTTPVersion, 200, "OK"}, _Header, ResBody}} -> case jsx:decode(ResBody, [{labels, binary}, return_maps]) of #{<<"result">> := 0, <<"ext">> := Ext} -> {ok, Ext}; #{<<"errmsg">> := ErrMsg, <<"result">> := Code} -> - ?LOG(error, "Send SMS ERROR: ~p->~ts, Request:~p~n", [list_to_binary(Url), unicode:characters_to_binary(ErrMsg), Body]), + ?LOG(error, "Send SMS ERROR: ~p->~ts, Request:~p~n", [list_to_binary(Url), unicode:characters_to_binary(ErrMsg), Data]), {error, #{code => Code, error => ErrMsg}} end; {Err, Reason} when Err == error; Err == 'EXIT' -> - ?LOG(error, "Send SMS ERROR: ~p, ~p, ~p~n", [Url, Body, Reason]), + ?LOG(error, "Send SMS ERROR: ~p, ~p, ~p~n", [Url, Data, Reason]), {error, #{code => 1, error => list_to_binary(io_lib:format("~p", [Reason]))}} end; _ -> diff --git a/apps/dgiot_modbus/src/dgiot_modbusc_tcp.erl b/apps/dgiot_modbus/src/dgiot_modbusc_tcp.erl index 8dc6c2ac..a3012151 100644 --- a/apps/dgiot_modbus/src/dgiot_modbusc_tcp.erl +++ b/apps/dgiot_modbus/src/dgiot_modbusc_tcp.erl @@ -33,7 +33,7 @@ init(_) -> {ok, #{}}. handle_info(connection_ready, #dclient{child = ChildState} = Dclient) -> - io:format("~s ~p ChildState = ~p.~n", [?FILE, ?LINE, ChildState]), +%% io:format("~s ~p ChildState = ~p.~n", [?FILE, ?LINE, ChildState]), rand:seed(exs1024), Time = erlang:round(rand:uniform() * 1 + 1) * 1000, erlang:send_after(Time, self(), read),