diff --git a/apps/modbus/include/modbus_ast.hrl b/apps/modbus/include/modbus_ast.hrl index c2925ac..e04751f 100644 --- a/apps/modbus/include/modbus_ast.hrl +++ b/apps/modbus/include/modbus_ast.hrl @@ -28,6 +28,18 @@ access_log = "" :: string() }). +-record(modbus_collect_template, { + name :: binary(), + %% 轮询间隔 + poll_interval :: integer() | undefined, + %% 重试策略 + retries :: integer(), + retry_timeout :: integer(), + + %% 数据定义 + metrics = #{} :: map() +}). + -record(modbus_device, { %% 设备名称 name :: string(), @@ -37,6 +49,8 @@ model :: string() | undefined, description :: string() | undefined, + collect_template :: binary() | undefined, + %% 轮询间隔 poll_interval :: integer() | undefined, @@ -89,6 +103,7 @@ -record(ast, { modbus, + collect_templates = [], devices = [], processors = [], alarms = [] diff --git a/apps/modbus/src/modbus_parser.erl b/apps/modbus/src/modbus_parser.erl index 54a41f7..853c269 100644 --- a/apps/modbus/src/modbus_parser.erl +++ b/apps/modbus/src/modbus_parser.erl @@ -30,6 +30,16 @@ parse(Input) when is_binary(Input) -> _ -> false end end, Trees), + + Templates = lists:filter(fun(E) -> + case E of + #modbus_collect_template{} -> + true; + _ -> + false + end + end, Trees), + Devices = lists:filter(fun(E) -> case E of #modbus_device{} -> @@ -56,7 +66,7 @@ parse(Input) when is_binary(Input) -> case length(Modbus) == 1 of true -> - AST = #ast{modbus = hd(Modbus), devices = Devices, processors = Processors, alarms = Alarms }, + AST = #ast{modbus = hd(Modbus), collect_templates = Templates, devices = Devices, processors = Processors, alarms = Alarms }, {ok, AST}; false -> {error, modbus_block_error} @@ -158,11 +168,21 @@ parse_ast0(#block{ident = <<"modbus">>, props = Props}) -> access_log = map_of_binary(<<"access_log">>, MapProps, undefined), error_log = map_of_binary(<<"error_log">>, MapProps, undefined) }; +parse_ast0(#block{ident = <<"collect_template", Name0/binary>>, props = Props}) -> + MapProps = parse_ast1(Props), + #modbus_collect_template { + name = string:trim(Name0), + poll_interval = map_of_time(<<"poll_interval">>, MapProps, 0), + retries = map_of_integer(<<"retries">>, MapProps, 0), + retry_timeout = maps:get(<<"retry_timeout">>, MapProps, undefined), + metrics = maps:get(<<"metrics">>, MapProps, undefined) + }; parse_ast0(#block{ident = <<"device", Name0/binary>>, props = Props}) -> MapProps = parse_ast1(Props), #modbus_device { name = string:trim(Name0), slave_id = map_of_integer(<<"slave_id">>, MapProps, 0), + collect_template = map_of_binary(<<"collect_template">>, MapProps, undefined), model = maps:get(<<"model">>, MapProps, undefined), description = maps:get(<<"description">>, MapProps, undefined), poll_interval = map_of_time(<<"poll_interval">>, MapProps, 0), diff --git a/apps/modbus/src/modbus_service.erl b/apps/modbus/src/modbus_service.erl index fd6d313..72cbcfe 100644 --- a/apps/modbus/src/modbus_service.erl +++ b/apps/modbus/src/modbus_service.erl @@ -82,15 +82,17 @@ start_link(AST = #ast{}) -> %% @doc Whenever a gen_statem is started using gen_statem:start/[3,4] or %% gen_statem:start_link/[3,4], this function is called by the new %% process to initialize. -init([AST = #ast{modbus = Modbus = #modbus{error_log = ErrorLog, access_log = AccessLog}, devices = Devices, alarms = Alarms}]) -> +init([AST = #ast{modbus = Modbus = #modbus{error_log = ErrorLog, access_log = AccessLog}, collect_templates = CollectTemplates, devices = Devices, alarms = Alarms}]) -> lager:debug("[modbus_service] modbus is: ~p", [Modbus]), + lager:debug("[modbus_service] templates is: ~p", [CollectTemplates]), + lager:debug("[modbus_service] devices is: ~p", [Devices]), %% 建立连接 erlang:start_timer(0, self(), modbus_connect), %% 启动设备相关的进程 DevicesPids = lists:map(fun(Device = #modbus_device{slave_id = SlaveId}) -> - {ok, DevicePid} = modbus_device:start_link(self(), Device), + {ok, DevicePid} = modbus_device:start_link(self(), merge_template(Device, CollectTemplates)), {SlaveId, DevicePid} end, Devices), DevicesMap = maps:from_list(DevicesPids), @@ -282,4 +284,20 @@ create_log_file(FileName) when is_binary(FileName) -> FilePid; _ -> undefined + end. + +merge_template(Device = #modbus_device{collect_template = undefined}, _Templates) -> + Device; +merge_template(Device = #modbus_device{collect_template = TemplateName}, Templates) -> + case lists:search(fun(#modbus_collect_template{name = T0}) -> TemplateName =:= T0 end, Templates) of + {value, #modbus_collect_template{poll_interval = PollInterval, retries = Retries, retry_timeout = RetryTimeout, metrics = Metrics}} -> + %% 合并配置项目 + Device#modbus_device{ + poll_interval = PollInterval, + retries = Retries, + retry_timeout = RetryTimeout, + metrics = Metrics + }; + false -> + Device end. \ No newline at end of file diff --git a/modbus.conf b/modbus.conf index 47ef56c..8f5c467 100644 --- a/modbus.conf +++ b/modbus.conf @@ -20,51 +20,44 @@ modbus { access_log /var/log/modbus_access.log; } +collect_template t1 { + # 轮询间隔 + poll_interval 5s; + + # 重试策略 + retries 3; + retry_timeout 2s; + + # 数据点定义 + metrics { + # 温度读取(保持寄存器) + temperature { + address 40001; # Modbus地址表示法 + type int16; + scale 0.1; + unit "°C"; + poll on; + } + + # 压力传感器(输入寄存器) + pressure { + address 30001; + type uint16; + scale 0.01; + unit "kPa"; + poll on; + } + } +} + device boiler_controller { # 设备标识 slave_id 1; model "Siemens S7-1200"; description "Main boiler controller"; - # 轮询间隔 - poll_interval 5s; + collect_template t1; - # 重试策略 - retries 3; - retry_timeout 2s; - - # 数据点定义 - metrics { - # 温度读取(保持寄存器) - temperature { - address 40001; # Modbus地址表示法 - type int16; - scale 0.1; - unit "°C"; - poll on; - } - - # 压力传感器(输入寄存器) - pressure { - address 30001; - type uint16; - scale 0.01; - unit "kPa"; - poll on; - } - - # 状态位(线圈) - #alarm_status { - # address 00001; - # type bool; - # bits { - # 0 "overheat"; - # 1 "low_pressure"; - # 2 "pump_failure"; - # } - # poll on; - #} - } # 写入控制 controls {