125 lines
5.4 KiB
Erlang
125 lines
5.4 KiB
Erlang
%%%-------------------------------------------------------------------
|
|
%%% @copyright (C) 2023, <COMPANY>
|
|
%%% @doc
|
|
%%%
|
|
%%% @end
|
|
%%% Created : 14. 8月 2023 11:40
|
|
%%%-------------------------------------------------------------------
|
|
-module(iot_device).
|
|
-author("aresei").
|
|
-include("iot.hrl").
|
|
|
|
%% API
|
|
-export([new/1, is_activated/1, change_status/2, reload/1, auth/2]).
|
|
|
|
%% 终端是否授权
|
|
-define(DEVICE_AUTH_DENIED, 0).
|
|
-define(DEVICE_AUTH_AUTHED, 1).
|
|
|
|
%% 状态
|
|
-define(STATE_DENIED, denied).
|
|
-define(STATE_ACTIVATED, activated).
|
|
|
|
-record(device, {
|
|
device_uuid :: binary(),
|
|
auth_state = ?STATE_DENIED,
|
|
status = ?DEVICE_OFFLINE
|
|
}).
|
|
|
|
%%%===================================================================
|
|
%%% API
|
|
%%%===================================================================
|
|
|
|
-spec new(DeviceInfo :: binary() | map()) -> error | {ok, Device :: #device{}}.
|
|
new(DeviceUUID) when is_binary(DeviceUUID) ->
|
|
case device_bo:get_device_by_uuid(DeviceUUID) of
|
|
{ok, #{<<"device_uuid">> := DeviceUUID, <<"authorize_status">> := AuthorizeStatus, <<"status">> := Status}} ->
|
|
{ok, #device{device_uuid = DeviceUUID, status = Status, auth_state = auth_state(AuthorizeStatus)}};
|
|
undefined ->
|
|
lager:warning("[iot_device] device uuid: ~p, loaded from mysql failed", [DeviceUUID]),
|
|
error
|
|
end;
|
|
new(#{<<"device_uuid">> := DeviceUUID, <<"authorize_status">> := AuthorizeStatus, <<"status">> := Status}) ->
|
|
{ok, #device{device_uuid = DeviceUUID, status = Status, auth_state = auth_state(AuthorizeStatus)}}.
|
|
|
|
-spec is_activated(Device :: #device{}) -> boolean().
|
|
is_activated(#device{auth_state = AuthState}) ->
|
|
AuthState =:= ?STATE_ACTIVATED.
|
|
|
|
-spec change_status(Device :: #device{}, NewStatus :: integer()) -> NDevice :: #device{}.
|
|
change_status(Device = #device{status = Status}, NewStatus) when is_integer(NewStatus), Status =:= NewStatus ->
|
|
Device;
|
|
change_status(Device = #device{device_uuid = DeviceUUID}, ?DEVICE_ONLINE) ->
|
|
{ok, _} = device_bo:change_status(DeviceUUID, ?DEVICE_ONLINE),
|
|
report_event(DeviceUUID, ?DEVICE_ONLINE),
|
|
Device#device{status = ?DEVICE_ONLINE};
|
|
change_status(Device = #device{device_uuid = DeviceUUID}, ?DEVICE_OFFLINE) ->
|
|
{ok, #{<<"status">> := Status}} = device_bo:get_device_by_uuid(DeviceUUID),
|
|
case Status of
|
|
?DEVICE_NOT_JOINED ->
|
|
lager:debug("[iot_device] device: ~p, device_maybe_offline, not joined, can not change to offline", [DeviceUUID]),
|
|
Device#device{status = ?DEVICE_NOT_JOINED};
|
|
?DEVICE_OFFLINE ->
|
|
lager:debug("[iot_device] device: ~p, device_maybe_offline, is offline, do nothing", [DeviceUUID]),
|
|
Device#device{status = ?DEVICE_OFFLINE};
|
|
?DEVICE_ONLINE ->
|
|
{ok, _} = device_bo:change_status(DeviceUUID, ?DEVICE_OFFLINE),
|
|
report_event(DeviceUUID, ?DEVICE_OFFLINE),
|
|
Device#device{status = ?DEVICE_OFFLINE}
|
|
end.
|
|
|
|
-spec reload(Device :: #device{}) -> error | {ok, NDevice :: #device{}}.
|
|
reload(Device = #device{device_uuid = DeviceUUID}) ->
|
|
lager:debug("[iot_device] will reload: ~p", [DeviceUUID]),
|
|
case device_bo:get_device_by_uuid(DeviceUUID) of
|
|
{ok, #{<<"authorize_status">> := AuthorizeStatus, <<"status">> := Status}} ->
|
|
{ok, Device#device{device_uuid = DeviceUUID, status = Status, auth_state = auth_state(AuthorizeStatus)}};
|
|
undefined ->
|
|
lager:warning("[iot_device] device uuid: ~p, loaded from mysql failed", [DeviceUUID]),
|
|
error
|
|
end.
|
|
|
|
-spec auth(Device :: #device{}, Auth :: boolean()) -> NDevice :: #device{}.
|
|
auth(Device = #device{auth_state = StateName, device_uuid = DeviceUUID}, Auth) when is_boolean(Auth) ->
|
|
case {StateName, Auth} of
|
|
{?STATE_DENIED, false} ->
|
|
lager:debug("[iot_device] device_uuid: ~p, auth: false, will keep state_name: ~p", [DeviceUUID, ?STATE_DENIED]),
|
|
Device;
|
|
{?STATE_DENIED, true} ->
|
|
Device#device{auth_state = ?STATE_ACTIVATED};
|
|
{?STATE_ACTIVATED, false} ->
|
|
lager:debug("[iot_device] device_uuid: ~p, auth: false, state_name from: ~p, to: ~p", [DeviceUUID, ?STATE_ACTIVATED, ?STATE_DENIED]),
|
|
Device#device{auth_state = ?STATE_DENIED};
|
|
{?STATE_ACTIVATED, true} ->
|
|
lager:debug("[iot_device] device_uuid: ~p, auth: true, will keep state_name: ~p", [DeviceUUID, ?STATE_ACTIVATED]),
|
|
Device
|
|
end.
|
|
|
|
%%%===================================================================
|
|
%%% Internal functions
|
|
%%%===================================================================
|
|
|
|
-spec auth_state(integer()) -> atom().
|
|
auth_state(?DEVICE_AUTH_AUTHED) ->
|
|
?STATE_ACTIVATED;
|
|
auth_state(?DEVICE_AUTH_DENIED) ->
|
|
?STATE_DENIED.
|
|
|
|
-spec report_event(DeviceUUID :: binary(), NewStatus :: integer()) -> no_return().
|
|
report_event(DeviceUUID, NewStatus) when is_binary(DeviceUUID), is_integer(NewStatus) ->
|
|
TextMap = #{
|
|
0 => <<"离线"/utf8>>,
|
|
1 => <<"在线"/utf8>>
|
|
},
|
|
%% 设备的状态信息上报给中电
|
|
Timestamp = iot_util:timestamp_of_seconds(),
|
|
FieldsList = [#{
|
|
<<"key">> => <<"device_status">>,
|
|
<<"value">> => NewStatus,
|
|
<<"value_text">> => maps:get(NewStatus, TextMap),
|
|
<<"unit">> => 0,
|
|
<<"type">> => <<"DI">>,
|
|
<<"name">> => <<"设备状态"/utf8>>,
|
|
<<"timestamp">> => Timestamp
|
|
}],
|
|
lager:debug("[iot_device] device_uuid: ~p, route fields: ~p", [DeviceUUID, FieldsList]). |