Create a custom controller¶
Copy the included template to create a custom controller.
netdef/Controllers/NewControllerTemplate.py
:
import datetime
import logging
from netdef.Controllers import BaseController, Controllers
from netdef.Sources.BaseSource import StatusCode
# import my supported sources
from netdef.Sources.NewSourceTemplate import NewSourceTemplate
@Controllers.register("NewControllerTemplate")
class NewControllerTemplate(BaseController.BaseController):
def __init__(self, name, shared):
super().__init__(name, shared)
self.logger = logging.getLogger(self.name)
self.logger.info("init")
self.one_config_entry = self.shared.config.config(
self.name, "one_config_entry", "default_value"
)
def run(self):
"Main loop. Will exit when receiving interrupt signal"
self.logger.info("Running")
while not self.has_interrupt():
self.loop_incoming() # dispatch handle_* functions
self.loop_outgoing() # dispatch poll_* functions
self.logger.info("Stopped")
def handle_readall(self, incoming):
raise NotImplementedError
def handle_add_source(self, incoming):
self.logger.debug("'Add source' event for %s", incoming.key)
self.add_source(incoming.key, incoming)
def handle_read_source(self, incoming):
raise NotImplementedError
def handle_write_source(self, incoming, value, source_time):
self.logger.debug(
"'Write source' event to %s. value: %s at: %s",
incoming.key,
value,
source_time,
)
def poll_outgoing_item(self, item):
if isinstance(item, NewSourceTemplate): # My
# TODO: get new value somehow
address = item.unpack_address()
new_val = get_the_new_value_somehow(address)
stime = datetime.datetime.utcnow()
status_ok = True # Why not
cmp_oldew = False # compare old and new value?
if self.update_source_instance_value(
item, new_val, stime, status_ok, cmp_oldew
):
self.send_outgoing(item)
Paste it into your application with a new name:
first_app/Controllers/CmdController.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import logging
import datetime
from netdef.Controllers import BaseController, Controllers
from netdef.Sources.BaseSource import StatusCode
# import my supported sources
from netdef.Sources.NewSourceTemplate import NewSourceTemplate
@Controllers.register("CmdController")
class CmdController(BaseController.BaseController):
def __init__(self, name, shared):
super().__init__(name, shared)
...
|
Line 9 and 10 is changed to the same name as the file. Line 7 have to be replaced at a later time to a custom or built-in source
To activate the controller we have to merge following config to default.conf
:
[controllers]
CmdController = 1
[CmdController]
Result after merge:
[controllers]
CrontabController = 1
OPCUAServerController = 1
CmdController = 1
[CrontabController]
[OPCUAServerController]
[CmdController]
Create a custom source¶
Copy the included template to create a custom source for your controller.
netdef/Sources/NewSourceTemplate.py
:
from netdef.Interfaces.DefaultInterface import DefaultInterface
from netdef.Sources import BaseSource, Sources
@Sources.register("NewSourceTemplate")
class NewSourceTemplate(BaseSource.BaseSource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.interface = DefaultInterface
# TODO: add a address for your new controller
def unpack_address(self):
return self.key
Paste it into your application with a new name:
first_app/Sources/CmdSource.py
:
1 2 3 4 5 6 7 8 9 10 11 12 | from netdef.Sources import BaseSource, Sources
from netdef.Interfaces.DefaultInterface import DefaultInterface
@Sources.register("CmdSource")
class CmdSource(BaseSource.BaseSource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.interface = DefaultInterface
# TODO: add a address for your new controller
def unpack_address(self):
return self.key
|
Line 4 and 5 is changed to the same name as the file.
Change line 7 in your custom controller:
first_app/Controllers/CmdController.py
:
1 2 3 4 5 6 7 8 | import logging
import datetime
from netdef.Controllers import BaseController, Controllers
from netdef.Sources.BaseSource import StatusCode
# import my new source
from ..Sources.CmdSource import CmdSource
...
|
To activate the source we have to merge following config to default.conf
:
[sources]
CmdSource = 1
[CmdSource]
controller = CmdController
Result:
[controllers]
CrontabController = 1
OPCUAServerController = 1
CmdController = 1
[sources]
CrontabSource = 1
VariantSource = 1
CmdSource = 1
[CrontabSource]
controller = CrontabController
[VariantSource]
controller = OPCUAServerController
[CmdSource]
controller = CmdController
[CrontabController]
[OPCUAServerController]
[CmdController]
Create a custom rule¶
Copy the included template to create a custom rule.
netdef/Rules/NewRuleTemplate.py
:
import logging
import pathlib
from netdef.Rules import BaseRule, Rules
from netdef.Rules.utils import import_file
SourceInfo = BaseRule.SourceInfo
ExpressionInfo = BaseRule.ExpressionInfo
@Rules.register("NewTemplateRule")
class NewTemplateRule(BaseRule.BaseRule):
def __init__(self, name, shared):
super().__init__(name, shared)
self.logger = logging.getLogger(name)
self.logger.info("init")
config = self.shared.config.config
self.proj_path = pathlib.Path(config("proj", "path", ".")).absolute()
def setup(self):
self.logger.info("Running setup")
# example:
self.setup_example()
# sub rule example:
for name, active in self.shared.config.get_dict(self.name).items():
if int(active):
self.setup_sub_rule(name)
self.logger.info("Done parsing")
def setup_sub_rule(self, name):
raise NotImplementedError
def setup_example(self):
# example_expression_module = self.import_py_file("config/example_expression.py")
# config/example_expresion.py:
# def expression(internal):
# if internal.new or internal.update:
# print(internal)
self.add_new_parser("InternalSource")
source_count = self.add_new_expression(
ExpressionInfo(
example_expression_module,
[SourceInfo("InternalSource", "intern_test_1")],
)
)
self.update_statistics(self.name + ".example", 0, 1, source_count)
def import_py_file(self, rel_file):
full_file = pathlib.Path(self.proj_path).joinpath(rel_file)
nice_name = full_file.name
return import_file(str(full_file), self.name, nice_name)
def run(self):
self.logger.info("Running")
while not self.has_interrupt():
self.loop_incoming() # dispatch handle_* functions
self.logger.info("Stopped")
def handle_run_expression(self, incoming, value, source_time, status_code):
expressions = self.get_expressions(incoming)
self.logger.debug(
"Received %s. Found expressions %s", incoming.key, len(expressions)
)
if expressions:
self.send_expressions_to_engine(
incoming, expressions, value, source_time, status_code
)
Paste it into your application with a new name:
first_app/Rules/FirstAppRule.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import logging
import pathlib
from .utils import import_file
from . import BaseRule, Rules
SourceInfo = BaseRule.SourceInfo
ExpressionInfo = BaseRule.ExpressionInfo
@Rules.register("FirstAppRule")
class FirstAppRule(BaseRule.BaseRule):
def __init__(self, name, shared):
super().__init__(name, shared)
self.logger = logging.getLogger(name)
self.logger.info("init")
|
Line 9 and 10 is changed to the same name as the file.
To activate the rule we have to merge following config to default.conf
:
[rules]
FirstAppRule = 1
[FirstAppRule]
Result:
[rules]
FirstAppRule = 1
[FirstAppRule]
[controllers]
CrontabController = 1
OPCUAServerController = 1
CmdController = 1
[sources]
CrontabSource = 1
VariantSource = 1
CmdSource = 1
[CrontabSource]
controller = CrontabController
[VariantSource]
controller = OPCUAServerController
[CmdSource]
controller = CmdController
[CrontabController]
[OPCUAServerController]
[CmdController]