Fraunhofer-FIT-DIEN / iec104-python

A Python module to simulate SCADA and RTU communication over protocol 60870-5-104 to research ICT behavior in power grids.
https://iec104-python.readthedocs.io/latest/python/index.html
GNU General Public License v3.0
50 stars 9 forks source link

Keep Client Open #8

Closed PedroSchroeder closed 9 months ago

PedroSchroeder commented 9 months ago

Hi! I'm creating a master client with you lib, but I would like to now how to keep the client open, for now if I don't set the sleep, it's going to finish

import c104
import random
import time

def handle_packets(connection: c104.Connection, data: bytes) -> None:
    print(
        "-->| {1} [{0}] | CON {2}:{3} HAHAHAHAHAHAHAHHAHAHA".format(
            data.hex(),
            c104.explain_bytes(apdu=data),
            connection.ip,
            connection.port,
        )
    )
    return

class IECMasterClient:
    def __init__(self, ip: str, port: int, common_address: int = 27808):
        self.ip = ip
        self.port = port
        self.common_address = common_address
        self.client = c104.Client(tick_rate_ms=1000, command_timeout_ms=1000)
        self.connection = self.client.add_connection(
            ip=ip, port=port, init=c104.Init.INTERROGATION
        )
        self.connection.on_receive_raw(callable=handle_packets)
        self.station = self.connection.add_station(common_address=self.common_address)

    def connect(self):
        self.connection.connect()

    def send_n_level(self, ioa: int, value: float):
        print("self.connection.is_connected --- ", self.connection.is_connected)
        point = self.station.get_point(io_address=ioa)
        if not point:
            point = self.station.add_point(io_address=ioa, type=c104.Type.C_SE_NC_1)
        point.value = value
        if point.transmit(cause=c104.Cot.ACTIVATION):
            print(f"n-level ioa {ioa} -> value: {value} SUCCESS")
        else:
            print(f"n-level ioa {ioa} -> value: {value} FAILURE")

    def transmit(self, point: c104.Point, cause: c104.Cot = c104.Cot.ACTIVATION):
        if point.transmit(cause=cause):
            return True
        return False

    def stop(self):
        self.client.stop()

    def start(self):
        self.client.start()

if __name__ == "__main__":
    c104.set_debug_mode(c104.Debug.Client | c104.Debug.Connection)
    client = IECMasterClient(ip="127.0.0.1", port=2404)
    client.start()
    time.sleep(1)
    client.send_n_level(11, 666)

    time.sleep()
m-unkel commented 9 months ago

It is intended that the connection is running in background threads so you can use the foreground thread for implementing your business logic.

Therefore it will not block your code and once this code ends the garbage collector of Python will delete all objects and threads.

If you don't need a custom logic, write an infinite sleep loop and wrap it with a try catch for KeyboardInterrupt.