API Documentation¶
Objects¶
Root¶
To specify a root object of the user-written adapter, you must create a class that inherits from class Root:
from alphalogic_api.objects import Root
......
class MyRoot(Root):
......
-
class
alphalogic_api.objects.
Root
¶ Root object inherits from
Object
. This kind of object is a child for the adapter service node. Root object is created automatically when starting the adapter instance.Parameters: - host – hostname of the gRPC stub instance of the composite adapter
- port – port of the gRPC stub instance of the composite adapter
-
init
(id_root)¶ Called from Root constructor
-
join
()¶ Wait until all threads within stub process terminate. This function provides an infinite communication loop between the adapter core and gRPC stub instance. Must be placed in the code of the adapter to keep it working till the process be stopped by the user or an error happens.
Object¶
To specify an adapter object (not Root object), create a class that inherits from the class Object:
from alphalogic_api.objects import Object
......
class Controller(Object):
......
-
class
alphalogic_api.objects.
Object
(type_device, id_device, **kwargs)¶ Adapter object can have a number of interactions (parameters, commands, events) and run functions. All the declarations of the object interactions must be placed inside the Object class body. Each of them must have a unique name among instances of the same class.
-
event
(name)¶ Get event by name
Parameters: name – event name Return type: Event
#TODO
-
events
()¶ Return events of the object
Return type: list of Event
#TODO
-
handle_defaults_loaded
(**kwargs)¶ Handler for configure Object after creation. Parameters, commands, events have already created.
-
handle_get_available_children
()¶ Handler is executed when an adapter’s client requests new available child objects Return list of tuples, each tuple can be either (class_name, user_name_display) or (class_name, user_name_display, device_type). Second choice is meant for devices with a type containing dots, like “access.passpoint”. Otherwise, if class_name is not the actual name of a class (usually if “partial” is used), class_name must contain attribute “cls” with the actual class name
-
handle_prepare_for_work
()¶ Handler is executed before work of object Parameters, commands, events have already created.
-
parameter
(name)¶ Get parameter by name
Parameters: name – parameter name Return type: Parameter
#TODO
-
parameters
()¶ Return parameters of the object
Return type: list of Parameter
#TODO
-
Parameter¶
Example of parameter definition:
from alphalogic_api.objects import ParameterBool, ParameterLong, ParameterDouble, ParameterDatetime, ParameterString, ParameterList, ParameterDict
...
message = ParameterString(default='Hello world!')
Read and write parameter value:
self.message.val = 'Me too'
self.param_str.val = self.message.val
Parameter arguments are optional.
Argument | Description | Default Value | Possible Values |
---|---|---|---|
default | Default parameter value |
|
All the values of the
corresponding type are
allowed (for example,
a parameter of
ParameterDouble can
hold real numbers)
|
visible | A parameter type that
specifies its features
and visibility in the
Alphalogic Studio
|
Visible.runtime |
|
access | A parameter access type
which specifies the
permitted and prohibited
uses of the parameter
|
Access.read_write |
|
choices | Allows to set up a
predefined enumeration
of values for the
parameter
|
The enumeration can be
specified in one of two
different ways:
1) list of values of the
corresponding type in a
tuple as (value1,
value2, …, valueN)
2) list of enumeration
members in a tuple of
tuples as ((value1,
‘enum_name1’), (value2,
‘enum_name2’), …,
(value2, ‘enum_nameN’))
|
To build a value list for the parameter, it is required that both arguments ‘choices’ and ‘default’ are specified.
param_tmp = ParameterLong(visible=Visible.setup, access=Access.read_write, default=1, choices=((1, 'First'), (2, 'Second')))
Second approach to build value list for parameter:
param_tmp = ParameterLong(visible=Visible.setup, access=Access.read_write, default=1, choices=(1, 2))
Be careful to assign a value (not an enumeration member’s name) to ‘default’ argument if the ‘choices’ argument provides enumeration with descriptions:
param_tmp2 = ParameterBool(default=True, choices=((True, 'On'), (False, 'Off')))
Here is the definition of the class Parameter:
-
class
alphalogic_api.objects.
Parameter
(*args, **kwargs)¶ Class Parameter inherits all data elements and methods from
AbstractParameter
.
Event¶
To define an event with arguments, you must append a tuple of (argument name, argument type) pairs. The names of the arguments must be enclosed with single or double quotes.
Example of event definition:
alarm = MajorEvent(('where', unicode), ('when', datetime.datetime), ('why', long))
- unicode – used for string data,
- datetime.datetime – used for date and time,
- long – for integer values,
- float – to store real numbers,
- bool – used for boolean values.
The function that triggers an event occurence (emit) can be passed with the event arguments as a tuple of name/value pairs, each argument name followed by an equal sign:
alarm.emit(where="Red Square, Moscow", when=datetime.datetime(2018, 12, 31), why=123456)
Python allows you to pass functions as a parameters to another functions. In the present case, function can be passed instead of the value for the event argument:
alarm.emit(where="Red Square, Moscow", when=datetime.datetime.utcnow(), why=123456)
Example of the event function without arguments:
alarm.emit()
Here is the definition of the class Event:
-
class
alphalogic_api.objects.
Event
(priority, *args, **kwargs)¶ Class Event inherits all data elements and methods from
AbstractEvent
.Parameters: - priority – trivial, minor, major, critical or blocker
- args – name/type pairs in a tuple of tuples (argument name, argument type)
Decorators¶
A decorator is any callable Python object that is used to modify a function, method or class definition. A decorator is passed the original object being defined and returns a modified object, which is then bound to the name in the definition. Decorators are used for creating class methods or static methods, adding function attributes, tracing, setting pre- and postconditions, etc. The @ special character is used to indicate a decorator.
Command¶
Possible values for result type are: unicode, datetime.datetime, int, float, bool, list, dict. Here is the definition of the class Command:
-
alphalogic_api.decorators.
command
(*argv_c, **kwargs_c)¶ Use this decorator to create
Command
object.Example 1:
# The command returns True every time @command(result_type=bool) def cmd_exception(self): # do smth return True
Example 2:
# The command has three arguments and returns 'where' argument value @command(result_type=bool) def cmd_alarm(self, where='here', when=datetime.datetime.now(), why=2): return where
Example 3:
# The command hasn't arguments and return dict type @command(result_type=dict) def cmd_alarm(self): return {'a': 1, 'b': 'second', 'c': [1,2,3], 'd' : [1, {'2': 3}, 3]}
Parameters: result_type – Command return type
Run functions¶
There is easy way to do some job periodicaly. You can define a lot of run functions in the root or object.
-
alphalogic_api.decorators.
run
(*argv_r, **kwargs_r)¶ - This function is used to be called periodically by the gRPC process.It can be defined inside the Object class body to implement some repeatable tasks likeinterrogation of the controller, modem, database, etc.It is required to specify the necessary trigger period in seconds in the argument of the function.Name of this function should not be started with
_
.Example:
# Called every 1 second. # You can change period by changing 'period_one' parameter. @run(period_one=1) def run_one(self): self.counter.val += 1
SynchronizationAll functions wrapped in@run
decorator may be called simultaneously in a thread pool.However,Object
hasmutex
attribute for synchronization between@run
functionsdefined in one Object instance.They are also synchronized withhandle_before_remove_device()
.handle_before_remove_device()
can be called only after the end of the last callof any@run
functions of the object.Note however, that there’s no any synchronization between@run
functionsand object’s constructor,handle_defaults_loaded()
,handle_prepare_for_work()
,handle_get_available_children()
and also between different Object instances.
Handlers¶
The handlers are executed when the corresponding condition occurs. There are three types of handlers which can be installed to control the workflow of the adapter before or after calling some functions:
1) Request on child objects of the adapter object:
def handle_get_available_children(self):
return [
(Controller, 'Controller'),
(MyObject, 'MyObject')
]
You can define and implement this function in the object class to return an array of the child adapter objects. You must use the exact name of the handler as in the example above.
2) Request on deletion of the adapter object(s):
def handle_before_remove_device(self):
do something
You can use this handler to do something before the adapter object will be deleted. You must use the exact name of the handler as in the example above.
3) Changing the value of the parameter:
def handle_after_set_double(node, parameter):
node.log.info('double changed')
node.after_set_value_test_event.emit(value=parameter.val)
param_double = ParameterDouble(default=2.3, callback=handle_after_set_double)
The handler will be invoked when the specified parameter is changed. In the example above, this means that the function handle_after_set_double will be called if param_double is changed. In the case of parameter changes, you can use whichever name of the handler function you like.
4) Handler for configure Object after creation by user
number = ParameterLong(visible=Visible.setup)
def handle_defaults_loaded(self, **kwargs):
self.displayName.val = str(self.number.val)
5) Handler is executed before work of object
number = ParameterLong(visible=Visible.setup)
def handle_prepare_for_work(self):
self.displayName.val = str(self.number.val)
Оbject lifetime¶
Created by user¶
__init__
. You can’t do anything with parameters, events, commands here.- Create parameters, events, commands
- Accept values from
__init__
kwargs. See Advanced using p.1. handle_defaults_loaded
handlehandle_prepare_for_work
handle
Loaded from configuration¶
__init__
. You can’t do anything with parameters, events, commands here.- Create parameters, events, commands
handle_prepare_for_work
handle
Note
Order of handle_prepare_for_work
handle calls is from child objects to the root object. All initialization including handler calls is performed inside the Root constructor.
Removed by user¶
handle_before_remove_device
Advanced using¶
1) Create a child object with predefault values:
class Controller(Object, DiagHelper):
some_parameter_title = ParameterLong(default=0)
def handle_get_available_children(self):
children = [] # return empty list if exception
try:
p = partial(Controller, some_parameter_title=0)
p.cls = Controller
children.append((p, 'Controller 0'))
# You can set parameter values in
p = partial(Controller, some_parameter_title=1, displayName=h['name'])
p.cls = Controller
children.append((p, 'Controller 1'))
except Exception as err:
log.error(err.message)
return children
Handlers order example¶
1) Situation 1: User creates object
class Controller(Object):
def __init__(self, type_device, id_device, **kwargs):
super(Controller, self).__init__(type_device, id_device, **kwargs)
# 1: Partial arguments in the kwargs
def handle_defaults_loaded(self, **kwargs):
# 2: Partial arguments in the kwargs
def handle_prepare_for_work(self):
# 3: Parameters, commands, events created and have default values
def handle_before_remove_device(self):
# remove object by user
2) Situation 2: Object has been loaded from configuration
class Controller(Object):
def __init__(self, type_device, id_device, **kwargs):
super(Controller, self).__init__(type_device, id_device, **kwargs)
# 1: nothing in the kwargs
def handle_defaults_loaded(self, **kwargs):
# Not called
def handle_prepare_for_work(self):
# 2: Parameters, commands, events created.
# Values from configuration loaded.
Arbitrary object type¶
Alphalogic objects have type
attribute. By default, it’s set to Python object’s class name. For example, an object of Python class MyObject
has MyObject
alphalogic object type.
However, you may want to set an alphalogic type, which cannot be represented by Python class name, like access.wipepoint
. Such names are usually required for ACS adapters.
In this case, two steps should be done to set an arbitrary type attribute.
First, in the list returned from parent’s handle_available_children()
method, corresponding item should be represented by a tuple with 3 elements where the last element is the required type name.
Second, before creating root object, this type should be registered with Manager.add_device("type name", ClassName)
method.
Example:
class AccessWipepoint(Object):
# This device has alphalogic type "access.wipepoint"
pass
class RootDevice(Root):
def handle_get_available_children(self):
# Set device type in a tuple (the last item)
return [(AccessWipepoint, "access wipepoint device", "access.wipepoint")]
if __name__ == "__main__":
# Add device AccessWipepoint to alphalogic-api with device type "access.wipepoint"
Manager.add_device("access.wipepoint", AccessWipepoint)
# main loop
root = RootDevice()
# ...
If you need to set arbitrary type for the root object, this type must be set in the C++ part of your adapter.
Dynamic object components¶
Besides adding a component (parameter, command, event) as a class attribute, components can be added dynamically since alphalogic_api v0.0.23. Repeated addition overwrites the previous one.
@run(period_one=3)
def run_function(self):
# Dynamic switching of attributes and parameters of dynamic_event
event_class = random.choice([TrivialEvent, MinorEvent, MajorEvent, CriticalEvent,
BlockerEvent])
param_type = random.choice([int, bool, unicode])
param_name = random.choice(["foo", "bar", "baz"])
if param_type is int:
param_value = random.randint(0, 10)
elif param_type is bool:
param_value = random.choice([True, False])
elif param_type is unicode:
param_value = random.choice(["value1", "value2", "value3", "value4", "value5"])
else:
assert False, "Impossible branch"
event = event_class((param_name, param_type))
# Add dynamic event (not added as class attribute)
# Can be called after Object's constructor
Object.manager.add_event_to_object(self, "dynamic_event", event)
event.emit(**{param_name: param_value})
# Dynamic command example
# Handler, parameters, choices, default values can be changed
# Result type MUST NOT be changed
@command(result_type=bool, param1={"default": "default", "val1": "value1", "val2": "value2"})
def dynamic_command1(self, param1="default", param2=0):
log.info("param1={}, param2={}".format(param1, param2))
return True
@command(result_type=unicode, p1={"default": 0, "v1": 1, "v2": 2})
def dynamic_command2(self, p1=0, p2=True):
log.info("p1={}, p2={}".format(p1, p2))
return "OK"
# Can be called after Object's constructor
Object.manager.add_command_to_object(self, "dynamic_command",
random.choice([dynamic_command1, dynamic_command2]))
# Dynamic parameter: attributes and choices can be changed
# Type MUST NOT be changed
p = random.choice([ParameterLong(visible=Visible.setup, access=Access.read_write,
choices=((1, "one"), (2, "two"))),
ParameterLong(visible=Visible.runtime, access=Access.read_only,
choices=((1, "ONE"), (2, "TWO")))])
# Can be called after Object's constructor
Object.manager.add_parameter_to_object(self, "dynamic_parameter", p)
Exceptions¶
-
class
alphalogic_api.exceptions.
IncorrectRPCRequest
(msg)¶ This kind of exception occurs when there is an internal API error, possibly incorrect syntax of some function, or something else.
-
class
alphalogic_api.exceptions.
RequestError
(msg)¶ Internal gRPC call error that occurs when the remote request processing has failed.
-
class
alphalogic_api.exceptions.
ComponentNotFound
(msg)¶ API error that occurs if the name of the declared variable is missing, mismatched, or unidentifiable
-
class
alphalogic_api.exceptions.
Exit
¶ A fatal exception that will trigger adapter instance to exit
Abstract Classes¶
Abstract parameter¶
-
class
alphalogic_api.objects.parameter.
AbstractParameter
¶ AbstractParameter implements ParameterService service (see rpc.proto)
-
clear
()¶ Remove all predefined values from the ‘choices’ argument of the parameter
-
desc
()¶ Return parameter description
Return type: unicode
-
display_name
()¶ Return parameter display name
Return type: unicode
-
enums
()¶ Get the predefined enumeration of values from the ‘choices’ argument of the parameter
Return type: List of values of long, float, datetime, bool or unicode type in a tuple as (value1, value2, value3 ….)
-
get
()¶ Get parameter value
Return type: long, float, datetime, bool or unicode
-
has_enum
(enum_name)¶ Return True if parameter has a predefined enumeration of values
Return type: bool
-
is_bool
()¶ Return True if parameter value type is bool
Return type: bool
-
is_common
()¶ Return True if parameter type is Visible.common
Return type: bool
-
is_datetime
()¶ Return True if parameter value type is datetime
Return type: bool
-
is_double
()¶ Return True if parameter value type is double
Return type: bool
Return True if parameter type is Visible.hidden
Return type: bool
-
is_licensed
()¶ Return True if parameter is the license key parameter
Return type: bool
-
is_list
()¶ Return True if parameter value type is list
Return type: bool
-
is_long
()¶ Return True if parameter value type is long
Return type: bool
-
is_map
()¶ Return True if parameter value type is map
Return type: bool
-
is_read_only
()¶ Return True if parameter access type is Access.read_only
Return type: bool
-
is_read_write
()¶ Return True if parameter access type is Access.read_write
Return type: bool
-
is_runtime
()¶ Return True if parameter type is Visible.runtime
Return type: bool
-
is_setup
()¶ Return True if parameter type is Visible.setup
Return type: bool
-
is_string
()¶ Return True if parameter value type is string
Return type: bool
-
name
()¶ Return parameter name
Return type: unicode
-
owner
()¶ Return ID of the parameter’s owner
Return type: uint64
-
set
(value)¶ Set parameter value
Parameters: value – The value type: long, float, datetime, bool or unicode
-
set_common
()¶ Set parameter type to Visible.common
-
set_desc
(desc)¶ Set parameter description
Parameters: desc – unicode
-
set_display_name
(display_name)¶ Set parameter display name
Parameters: display_name – unicode
-
set_enum
(value, enum_name)¶ Add/replace enumeration member – a pair (value, name) – for the ‘choices’ argument of the parameter
Parameters: - value – The value type: long, float, datetime, bool or unicode
- enum_name – enumeration member name
-
set_enums
(values)¶ Add/replace multiple enumeration members for the ‘choices’ argument of the parameter
Parameters: values – An array of values can be one of the following: - List of values of long, float, datetime, bool or unicode type in a tuple as (value1, value2, value3 ….)
- List of enumeration members in a tuple of tuples as ((value1, ‘enum_name1’), (value2, ‘enum_name2’), …)
Set parameter type to Visible.hidden
-
set_licensed
()¶ Set the license key parameter
-
set_list
()¶ Set value_type LIST
-
set_read_only
()¶ Set parameter access type to Access.read_only
-
set_read_write
()¶ Set parameter access type to Access.read_write
-
set_runtime
()¶ Set parameter type to Visible.runtime
-
set_setup
()¶ Set parameter type to Visible.setup
-
Abstract event¶
-
class
alphalogic_api.objects.event.
AbstractEvent
¶ AbstractEvent implements EventService service (see rpc.proto)
-
argument
(name_argument)¶ Return event argument with value by argument name
Parameters: name_argument – event argument name Return type: name/value pair as a tuple (argument name, argument value)
-
argument_list
()¶ Return list of event arguments
Return type: list of event argument names
-
clear
()¶ Remove event arguments
-
desc
()¶ Return event description
Return type: unicode
-
display_name
()¶ Return event display name
Return type: unicode
-
emit
(**kwargs)¶ - Emit event with the current UTC time.In order to use timestamp other than the current UTC time, you should call set_time function with required timestamp before executing emit function.
Parameters: kwargs – name/value pairs of event arguments separated by commas, each argument name followed by an equal sign
-
is_blocker
()¶ Return True if event severity is blocker
Return type: bool
-
is_critical
()¶ Return True if event severity is critical
Return type: bool
-
is_major
()¶ Return True if event severity is major
Return type: bool
-
is_minor
()¶ Return True if event severity is minor
Return type: bool
-
is_trivial
()¶ Return True if event severity is trivial
Return type: bool
-
name
()¶ Return event name
Return type: unicode
-
owner
()¶ Return ID of the event’s owner
Return type: uint64
-
set_argument_value
(name_arg, value)¶ Set argument value
Parameters: - name_arg – event argument name
- value – event argument value
-
set_blocker
()¶ Set event severity to blocker
-
set_critical
()¶ Set event severity to critical
-
set_desc
(desc)¶ Set event description
Parameters: desc – unicode
-
set_display_name
(display_name)¶ Set event display name
Parameters: display_name – unicode
-
set_major
()¶ Set event severity to major
-
set_minor
()¶ Set event severity to minor
-
set_time
(timestamp)¶ Set event time (UTC)
Parameters: timestamp – int(time.time() * 1000) (мс)
-
set_trivial
()¶ Set event severity to trivial
-
update_or_create_argument
(name_arg, value)¶ Add event argument / overwrite argument value
Parameters: - name_arg – event argument name
- value – event argument value
-
Abstract command¶
-
class
alphalogic_api.objects.command.
AbstractCommand
¶ AbstractCommand implements CommandService service (see rpc.proto)
-
argument
(name_argument)¶ Return command argument with value by argument name
Parameters: name_argument – command argument name Return type: name/value pair as a tuple (argument name, argument value)
-
argument_list
()¶ Return list of command arguments
Return type: list of command argument names
-
clear
()¶ Remove command arguments
-
desc
()¶ Return command description
Return type: unicode
-
display_name
()¶ Return command display name
Return type: unicode
-
is_bool
()¶ Return True if command return type is bool
Return type: bool
-
is_datetime
()¶ Return True if command return type is datetime
Return type: bool
-
is_double
()¶ Return True if command return type is double
Return type: bool
-
is_list
()¶ Return True if command return type is list
Return type: bool
-
is_long
()¶ Return True if command return type is long
Return type: bool
-
is_map
()¶ Return True if command return type is map
Return type: bool
-
is_string
()¶ Return True if command return type is string
Return type: bool
-
name
()¶ Return command name
Return type: unicode
-
owner
()¶ Return ID of the command’s owner
Return type: uint64
-
set_desc
(desc)¶ Set command description
Parameters: desc – unicode
-
set_display_name
(display_name)¶ Set command display name
Parameters: display_name – unicode
-
set_exception
(reason)¶ Set exception in command. Information about exception will be called for adapter’s side.
Parameters: reason – state unicode string
-
set_result
(value)¶ Set command return value
Parameters: value – The value type: long, float, datetime, bool or unicode
-
update_or_create_argument
(name_arg, value)¶ Add command argument / overwrite argument value
Parameters: - name_arg – command argument name
- value – command argument value
-
Command¶
-
class
alphalogic_api.objects.command.
Command
(device, function)¶ - Class Command is used in command decorator.Class Command inherits all data elements and methods from
AbstractCommand
.Parameters: - device – has
Object
type - function – executed function
-
call_function
()¶ Call function when command executed
Return type: The return type depends on the function code
- device – has
License¶
MIT License
Copyright (c) 2018 Alphaopen LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Contact¶
Indices and tables¶
Alphalogic API¶
The Alphalogic API is an official library that provides developers with the tools for creating the Alphalogic system adapters in Python 2.
Compatibility¶
The library is compatible with Alphalogic adapter’s core since 381
.
Installation¶
To install the alphalogic_api
package with pip, run this command in your terminal:
pip install alphalogic-api
If you don’t have pip installed, this Python installation guide can guide you through the process.
Dependencies¶
To start using this library you need the Alphalogic Service Manager (ASM) to be installed on your machine. Additionally, you also need the composite Alphalogic adapter (probably, engine) to be installed to provide a “shell” for your code to run in.
You can define the required dependencies by editing the ‘requirements’ parameter in the [pip] section in the stub.win32.ini
file (for Windows) or stub.linux.ini
file (for Linux). Navigate to the \bin
folder of the installed composite Alphalogic adapter, and open appropriate file to edit.
After saving this file, you can access the necessary libraries via the ASM: go to Infrastructure > Adapters page, download and install the specific dependencies by clicking on the install button for the deployed adapter.
Overview¶
- traditional C++ adapters;
- composite adapters of two different parts: a relatively unchangeable program core written in C++, supplemented by gRPC stub containing application-specific program code which can be written in almost any programming language (C++, Python, Go!, JavaScript, etc.).
- Java adapters.
The alphalogic_api library allows to access Alphalogic Integration API for easily developing composite adapters in Python 2, providing the integration developer with opportunity to code at once the functional part of the adapter, knowing nothing about the core.
Every adapter has a tree-like structure of the adapter objects represented as a set of linked nodes. The object tree has a Root object which will be generated automatically after the adapter instance is started, and a number of parent/child objects forming the object architecture of the adapter.
Object is a unit that has specific information and/or implements the necessary technical functions of the integrated device/subsystem. Root object is a root node of the adapter object tree. Usually serves for specifying initial device/subsystem data or defining connection settings or just as a go-between node. Root object cannot be deleted separately from the adapter instance. All other objects (not Root) – subobjects (dependent objects) – are inherited from class Object.
Every adapter object has a name and a defined set of the specific types of interactions – parameters, events, and commands – which determine its behaviour in the adapter.
Usage¶
Navigate to the \bin
folder of the installed composite Alphalogic adapter and open stub.py
file to edit. It contains the following code:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from alphalogic_api.objects import Root, Object
from alphalogic_api.attributes import Visible, Access
from alphalogic_api.objects import MajorEvent
from alphalogic_api.objects import ParameterBool, ParameterLong, ParameterDouble, ParameterDatetime, ParameterString, ParameterList, ParameterDict
from alphalogic_api.decorators import command, run
from alphalogic_api.logger import log
class Engine(Root):
pass
if __name__ == '__main__':
# main loop
root = Engine()
root.join()
In the beginning of the file, there is a line of the unicode_literals import, which makes all string literals of unicode type, instead of string type.
Then come import statements for the classes probably required by the code of the adapter.
Below, there is a declaration of the class Engine to implement the default root object, designed to be changed as needed.
Finally, you can see an “if__name__== “__main__” block used to run stub.py
as a standalone program which cannot be imported as a reusable module.
In the act of writing Python code, you should follow the coding conventions, PEP-8.
Example Usage¶
The use of the library can be demonstrated via the following example of the SendMail Adapter:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from operator import methodcaller
from alphalogic_api import options
from alphalogic_api.objects import Root, Object
from alphalogic_api.attributes import Visible, Access
from alphalogic_api.objects import ParameterBool, ParameterLong, ParameterDouble, ParameterDatetime, ParameterString, ParameterList, ParameterDict
from alphalogic_api.decorators import command, run
from alphalogic_api.logger import log
#
# How to send an email with Python
# http://naelshiab.com/tutorial-send-email-python/
#
def send_mail(smtp, message, topic, recipients):
host = smtp.ServerAddress.val
port = smtp.Port.val
user = smtp.Login.val
password = smtp.Password.val
timeout = smtp.TimeoutMillisec.val / 1000.0 # in seconds
from_addr = smtp.SenderAddress.val
to_addrs = map(methodcaller('strip'), recipients.split(',')) # 'mike@mail.com, tom@mail.com'
msg = MIMEMultipart()
msg['From'] = smtp.SenderName.val
msg['To'] = recipients
msg['Subject'] = topic
body = message
charset = dict(Smtp.ENCODING_CHOICES)[smtp.Encoding.val]
msg.attach(MIMEText(body, 'plain', charset))
server = smtplib.SMTP(host=host, port=port, timeout=timeout)
server.starttls()
server.login(user=user, password=password)
text = msg.as_string()
server.sendmail(from_addr, to_addrs, text)
server.quit()
return ''
#
# Adapter Stub.
# Tree:
# MailAdapter
# |
# |__Smtp
#
class MailAdapter(Root):
def handle_get_available_children(self):
return [
(Smtp, 'Smtp'),
]
class Smtp(Object):
PORT_CHOICES = (
(25, '25'),
(465, '465'),
(587, '587'),
(2525, '2525'),
)
ENCODING_CHOICES = (
(0, 'utf-8'),
(1, 'koi8-r'),
(2, 'windows-1251'),
(3, 'windows-1252'),
)
# parameters
ServerAddress = ParameterString(visible=Visible.setup)
SenderAddress = ParameterString(visible=Visible.setup)
Login = ParameterString(visible=Visible.setup)
Password = ParameterString(visible=Visible.setup)
SenderName = ParameterString(visible=Visible.setup)
Port = ParameterLong(visible=Visible.setup, choices=PORT_CHOICES, default=587)
TimeoutMillisec = ParameterLong(visible=Visible.common, default=5000)
Encoding = ParameterLong(visible=Visible.common, choices=ENCODING_CHOICES, default=0)
# commands
@command(result_type=unicode)
def SendMail(self, message='', topic='', recipients=''):
return send_mail(self, message=message, topic=topic, recipients=recipients)
if __name__ == '__main__':
# main loop
root = MailAdapter()
root.join()