E5EB Setup the Channel Pipeline by hutcheb · Pull Request #362 · apache/plc4x · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions sandbox/plc4py/plc4py/PlcDriverManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
#

import logging
from contextlib import contextmanager
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from typing import Generator, Type
from typing import Type, AsyncIterator
from pluggy import PluginManager # type: ignore

from plc4py.api.PlcConnection import PlcConnection
Expand Down Expand Up @@ -55,34 +55,32 @@ def __post_init__(self):
logging.info(f"... {driver} .. OK")
self.class_loader.check_pending()

@contextmanager
def connection(self, url: str) -> Generator[PlcConnection, None, None]:
@asynccontextmanager
async def connection(self, url: str) -> AsyncIterator[PlcConnection]:
"""
Context manager to handle connection.

:param url: plc connection string
:return: plc connection generator
"""
conn = None
conn: PlcConnection = await self.get_connection(url)
try:
conn = self.get_connection(url)
yield conn
finally:
if conn is not None:
conn.close()
conn.close()

def get_connection(self, url: str) -> PlcConnection:
async def get_connection(self, url: str) -> PlcConnection:
"""
Connects to a PLC using the given plc connection string using given authentication credentials.
:param url: plc connection string.
:return: plc connection
"""
protocol_code = get_protocol_code(url)
return self._driverMap[protocol_code]().get_connection(url)
return await self._driverMap[protocol_code]().get_connection(url)

def list_drivers(self) -> list[str]:
"""
Returns the codes of all of the drivers which are currently registered at the PlcDriverManager
Returns the codes of the drivers which are currently registered at the PlcDriverManager
:return: Set of driver codes for all drivers registered
"""
return list(self._driverMap.keys())
Expand Down
13 changes: 3 additions & 10 deletions sandbox/plc4py/plc4py/api/PlcConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,14 @@

from plc4py.api.messages.PlcResponse import PlcResponse, PlcReadResponse
from plc4py.api.messages.PlcRequest import ReadRequestBuilder, PlcRequest
from plc4py.api.exceptions.exceptions import PlcConnectionException
from plc4py.api.value.PlcValue import PlcResponseCode
from plc4py.spi.configuration.PlcConfiguration import PlcConfiguration
from plc4py.utils.GenericTypes import GenericGenerator


class PlcConnection(GenericGenerator):
def __init__(self, url: str):
self.url = url

@abstractmethod
def connect(self) -> None:
"""
Establishes the connection to the remote PLC.
"""
raise PlcConnectionException
def __init__(self, config: PlcConfiguration):
self._configuration = config

@abstractmethod
def is_connected(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion sandbox/plc4py/plc4py/api/PlcDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def metadata(self):
return PlcDriverMetaData()

@abstractmethod
def get_connection(
async def get_connection(
self, url: str, authentication: PlcAuthentication = PlcAuthentication()
) -> PlcConnection:
"""
Expand Down
22 changes: 22 additions & 0 deletions sandbox/plc4py/plc4py/api/listener/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#


class EventListener:
pass
14 changes: 10 additions & 4 deletions sandbox/plc4py/plc4py/drivers/mock/MockConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,19 @@ class MockConnection(PlcConnection, PlcReader):
_is_connected: bool = False
device: MockDevice = field(default_factory=lambda: MockDevice())

def connect(self):
def _connect(self):
"""
Connect the Mock PLC connection
:return:
"""
self._is_connected = True
self.device = MockDevice()

@staticmethod
async def create(url):
# config = PlcConfiguration(url)
connection = MockConnection()
connection._connect()
return connection

def is_connected(self) -> bool:
"""
Expand Down Expand Up @@ -168,7 +174,7 @@ def __init__(self):
self.protocol_code = "mock"
self.protocol_name = "Mock"

def get_connection(
async def get_connection(
self, url: str, authentication: PlcAuthentication = PlcAuthentication()
) -> PlcConnection:
"""
Expand All @@ -177,7 +183,7 @@ def get_connection(
:param authentication: authentication credentials.
:return PlcConnection: PLC Connection object
"""
return MockConnection()
return await MockConnection.create(url)


class MockDriverLoader(PlcDriverLoader):
Expand Down
31 changes: 31 additions & 0 deletions sandbox/plc4py/plc4py/drivers/modbus/ModbusConfiguration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
from plc4py.spi.configuration.PlcConfiguration import PlcConfiguration


class ModbusConfiguration(PlcConfiguration):

def __init__(self, url):
super().__init__(url)

if self.transport is None:
self.transport = "tcp"

if self.port is None:
self.port = 502
43 changes: 30 additions & 13 deletions sandbox/plc4py/plc4py/drivers/modbus/ModbusConnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# specific language governing permissions and limitations
# under the License.
#
import asyncio
from typing import Type, Awaitable

import plc4py
Expand All @@ -25,33 +26,49 @@
from plc4py.api.messages.PlcResponse import PlcResponse
from plc4py.api.messages.PlcRequest import ReadRequestBuilder
from plc4py.drivers.PlcDriverLoader import PlcDriverLoader
from plc4py.drivers.modbus.ModbusConfiguration import ModbusConfiguration
from plc4py.drivers.modbus.ModbusProtocol import ModbusProtocol
from plc4py.spi.transport.Plc4xBaseTransport import Plc4xBaseTransport
from plc4py.spi.transport.TCPTransport import TCPTransport


class ModbusConnection(PlcConnection):
"""A hook implementation namespace."""

def __init__(self, url: str):
super().__init__(url)
def __init__(self, config: ModbusConfiguration, transport: Plc4xBaseTransport):
super().__init__(config)
self._transport: Plc4xBaseTransport = transport

def connect(self):
"""
Establishes the connection to the remote PLC.
"""
pass
@staticmethod
async def create(url):
config = ModbusConfiguration(url)
loop = asyncio.get_running_loop()
connection_future = loop.create_future()
# TODO:- Look at removing this future.
transport = await TCPTransport.create(
protocol_factory=lambda: ModbusProtocol(connection_future),
host=config.host,
port=config.port,
)
return ModbusConnection(config, transport)

def is_connected(self) -> bool:
"""
Indicates if the connection is established to a remote PLC.
:return: True if connection, False otherwise
"""
pass
if self._transport is not None:
return not self._transport.is_closing()
else:
return False

def close(self) -> None:
"""
Closes the connection to the remote PLC.
:return:
"""
pass
if self._transport is not None:
self._transport.close()

def read_request_builder(self) -> ReadRequestBuilder:
"""
Expand All @@ -70,10 +87,10 @@ def execute(self, PlcRequest) -> Awaitable[PlcResponse]:

class ModbusDriver(PlcDriver):
def __init__(self):
self.protocol_code = "modbus"
self.protocol_name = "Modbus"
self.protocol_code = "modbus-tcp"
self.protocol_name = "Modbus TCP"

def get_connection(
async def get_connection(
self, url: str, authentication: PlcAuthentication = PlcAuthentication()
) -> PlcConnection:
"""
Expand All @@ -82,7 +99,7 @@ def get_connection(
:param authentication: authentication credentials.
:return PlcConnection: PLC Connection object
"""
return ModbusConnection(url)
return await ModbusConnection.create(url)


class ModbusDriverLoader(PlcDriverLoader):
Expand Down
31 changes: 31 additions & 0 deletions sandbox/plc4py/plc4py/drivers/modbus/ModbusProtocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
from dataclasses import dataclass

from plc4py.spi.Plc4xBaseProtocol import Plc4xBaseProtocol


@dataclass
class ModbusProtocol(Plc4xBaseProtocol):
def data_received(self, data):
# TODO:- Implement Protocol specific stuff
pass

def close(self):
pass
37 changes: 37 additions & 0 deletions sandbox/plc4py/plc4py/spi/Plc4xBaseProtocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#

from asyncio import Protocol, Future
from dataclasses import dataclass


@dataclass
class Plc4xBaseProtocol(Protocol):
handler: Future
connected: bool = False

def data_received(self, data) -> None:
self.handler.set_result(data)

def connection_made(self):
self.connected = True

def connection_lost(self, exc: Exception | None) -> None:
self.connected = False
raise ConnectionError
Loading
0