%%%------------------------------------------------------------------- %%% @copyright (C) 2023, %%% @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 }], iot_router:route_uuid(DeviceUUID, FieldsList, Timestamp), lager:debug("[iot_device] device_uuid: ~p, route fields: ~p", [DeviceUUID, FieldsList]).