Example #1
0
from hat import util

mlog: logging.Logger = logging.getLogger(__name__)
"""Module logger"""


class DeviceInfo(typing.NamedTuple):
    addr: udp.Address
    location: str
    server: str
    service: str


DeviceInfoCb = aio.AsyncCallable[[DeviceInfo], None]
"""Device info callback"""
util.register_type_alias('DeviceInfoCb')

default_multicast_addr = udp.Address('239.255.255.250', 1900)


async def discover(device_info_cb: DeviceInfoCb,
                   multicast_addr: udp.Address = default_multicast_addr,
                   local_name: str = 'hat') -> 'DiscoveryServer':
    """Create discovery server"""
    endpoint = await udp.create(udp.Address('0.0.0.0', multicast_addr.port))

    srv = DiscoveryServer()
    srv._endpoint = endpoint
    srv._device_info_cb = device_info_cb
    srv._multicast_addr = multicast_addr
    srv._local_name = local_name
Example #2
0
"""Python ctypes wrapper for duktape JavaScript interpreter"""

from pathlib import Path
import ctypes
import sys
import typing

from hat import util


Data = typing.Union[None, bool, int, float, str,
                    typing.List['Data'], typing.Dict[str, 'Data'],
                    typing.Callable]
"""Supported data types"""
util.register_type_alias('Data')


class EvalError(Exception):
    """Evaluation error"""


class Interpreter:
    """JavaScript interpreter

    High-level python wrapper for duktape JavaScript interpreter.

    Current implementation caches all function objects for preventing
    garbage collection.

    """
Example #3
0

class BinaryCounterValue(typing.NamedTuple):
    value: int
    """value in range [-2^31, 2^31-1]"""
    sequence: int
    overflow: bool
    adjusted: bool
    invalid: bool


DataValue = typing.Union[SingleValue, DoubleValue, StepPositionValue,
                         BitstringValue, NormalizedValue, ScaledValue,
                         FloatingValue, BinaryCounterValue]
"""Data value"""
util.register_type_alias('DataValue')

CommandValue = typing.Union[SingleValue, DoubleValue, RegulatingValue,
                            NormalizedValue, ScaledValue, FloatingValue]
"""Command value"""
util.register_type_alias('CommandValue')


class Quality(typing.NamedTuple):
    invalid: bool
    not_topical: bool
    substituted: bool
    blocked: bool
    overflow: typing.Optional[bool]
    """Overflow is ``None`` in case of `SingleValue` and `DoubleValue`
    (otherwise can not be ``None``)"""
Example #4
0
from hat.drivers.modbus import common
from hat.drivers.modbus import encoder
from hat.drivers.modbus import messages
from hat.drivers.modbus import transport

mlog: logging.Logger = logging.getLogger(__name__)
"""Module logger"""

SlaveCb = aio.AsyncCallable[['Slave'], None]
"""Slave callback

Args:
    slave: slave instance

"""
util.register_type_alias('SlaveCb')

ReadCb = aio.AsyncCallable[
    ['Slave', int, common.DataType, int, typing.Optional[int]],
    typing.Union[typing.List[int], common.Error]]
"""Read callback

Args:
    slave: slave instance
    device_id: device identifier
    data_type: data type
    start_address: staring address
    quantity: number of registers

Returns:
    list of register values or error
Example #5
0
"""Statechart module"""

import collections
import itertools
import pathlib
import typing
import xml.etree.ElementTree

from hat import aio
from hat import util


EventName = str
"""Event name"""
util.register_type_alias('EventName')

StateName = str
"""State name"""
util.register_type_alias('StateName')

ActionName = str
"""Action name"""
util.register_type_alias('ActionName')

ConditionName = str
"""Condition name"""
util.register_type_alias('ConditionName')


class Event(typing.NamedTuple):
    """Event instance"""
Example #6
0
import logging
import pathlib
import ssl
import typing

from hat import aio
from hat import json
from hat import util


mlog: logging.Logger = logging.getLogger(__name__)
"""Module logger"""

ConnectionCb = typing.Callable[['Connection'], None]
"""Connection callback"""
util.register_type_alias('ConnectionCb')


async def connect(address: str, *,
                  autoflush_delay: typing.Optional[float] = 0.2,
                  ) -> 'Connection':
    """Connect to remote server

    Address represents remote WebSocket URL formated as
    ``<schema>://<host>:<port>/<path>`` where ``<schema>`` is ``ws`` or
    ``wss``.

    Argument `autoflush_delay` defines maximum time delay for automatic
    synchronization of `local_data` changes. If `autoflush_delay` is set to
    ``None``, automatic synchronization is disabled and user is responsible
    for calling :meth:`Connection.flush_local_data`. If `autoflush_delay` is
Example #7
0
        raise CancelledWithResultError(result, f.exception()) from exc

    if f.cancelled():
        raise asyncio.TimeoutError()

    return f.result()


Executor = typing.Callable[..., typing.Awaitable]
"""Executor coroutine

This coroutine takes a function and its arguments, executes the
function in executor and returns the result.

"""
util.register_type_alias('Executor')


def create_executor(
    *args: typing.Any,
    executor_cls: typing.Type = concurrent.futures.ThreadPoolExecutor,  # NOQA
    loop: typing.Optional[asyncio.AbstractEventLoop] = None) -> Executor:
    """Create `asyncio.loop.run_in_executor` wrapper.

    Wrapped executor is created from `executor_cls` with provided `args`.

    Args:
        args: executor args
        executor_cls: executor class
        loop: asyncio loop
Example #8
0
    optional: bool = False


class TypeRef(typing.NamedTuple):
    module: str
    name: str


Type = typing.Union[TypeRef, 'BooleanType', 'IntegerType', 'BitStringType',
                    'OctetStringType', 'NullType', 'ObjectIdentifierType',
                    'StringType', 'ExternalType', 'RealType', 'EnumeratedType',
                    'EmbeddedPDVType', 'ChoiceType', 'SetType', 'SetOfType',
                    'SequenceType', 'SequenceOfType', 'EntityType',
                    'UnsupportedType', 'PrefixedType']
"""Type"""
util.register_type_alias('Type')


class BooleanType(typing.NamedTuple):
    pass


class IntegerType(typing.NamedTuple):
    pass


class BitStringType(typing.NamedTuple):
    pass


class OctetStringType(typing.NamedTuple):
Example #9
0
from hat.drivers.iec104 import _iec104
from hat.drivers.iec104 import common

mlog: logging.Logger = logging.getLogger(__name__)
"""Module logger"""

InterrogateCb = aio.AsyncCallable[['Connection', int],
                                  typing.Optional[typing.List[common.Data]]]
"""Interrogate callback

This method is called when local peer receives interrogate request.
Called with asdu address, returns list of data. If ``None`` is returned,
negative response is sent.

"""
util.register_type_alias('InterrogateCb')

CounterInterrogateCb = aio.AsyncCallable[
    ['Connection', int, common.FreezeCode],
    typing.Optional[typing.List[common.Data]]]
"""Counter interrogate callback

This method is called when local peer receives counter interrogate request.
Called with asdu address and freeze code, returns list of data. If ``None``
is returned, negative response is sent.

"""
util.register_type_alias('CounterInterrogateCb')

CommandCb = aio.AsyncCallable[['Connection', typing.List[common.Command]],
                              bool]
Example #10
0
class Node(typing.NamedTuple):
    """Abstract syntax tree node.

    Node names are identifiers of parser's definitions and values
    are other nodes or string values representing matched `Literal`, `Class`
    or `Dot` leafs.

    """
    name: str
    value: typing.List[typing.Union['Node', str]]


Action = typing.Callable[[Node, typing.List], typing.Any]
"""Action"""
util.register_type_alias('Action')


def walk_ast(node: Node,
             actions: typing.Dict[str, Action],
             default_action: typing.Optional[Action] = None
             ) -> typing.Any:
    """Simple depth-first abstract syntax tree parser.

    Actions are key value pairs where keys represent node names and values
    are callables that should be called for appropriate node. Each callable
    receives matched node and list of results from recursively applying
    this function on child nodes. For nodes which name doesn't match any
    action, default action is used. If default action is not defined and node
    name doesn't match action, result is None and recursion is stopped.
Example #11
0
import itertools
import json
import pathlib
import typing
import urllib.parse

import jsonpatch
import jsonschema.validators
import yaml

from hat import util


Array: typing.Type = typing.List['Data']
"""JSON Array"""
util.register_type_alias('Array')

Object: typing.Type = typing.Dict[str, 'Data']
"""JSON Object"""
util.register_type_alias('Object')

Data: typing.Type = typing.Union[None, bool, int, float, str, Array, Object]
"""JSON data type identifier."""
util.register_type_alias('Data')

Format = enum.Enum('Format', ['JSON', 'YAML'])
"""Encoding format"""

Path: typing.Type = typing.Union[int, str, typing.List['Path']]
"""Data path"""
util.register_type_alias('Path')
Example #12
0
import sys
import threading
import asyncio
import functools
import typing

import PySide2.QtCore
import PySide2.QtWebEngineWidgets
import PySide2.QtWidgets

from hat import aio
from hat import util

QtExecutor = typing.Callable[..., typing.Awaitable[typing.Any]]
"""First argument is Callable called with additional arguments"""
util.register_type_alias('QtExecutor')

AsyncMain = typing.Callable[..., typing.Awaitable[typing.Any]]
"""First argument is QtExecutor"""
util.register_type_alias('AsyncMain')


def run(async_main: AsyncMain, *args, **kwargs):
    """Run Qt application with additional asyncio thread

    Args:
        async_main: asyncio main entry point
        args: aditional positional arguments passed to `async_main`
        kwargs: aditional keyword arguments passed to `async_main`

    """