stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
254 stars 94 forks source link

[Help] How can I ensure I can get an initial value when using add_device_notification? #411

Closed liwen-tj closed 2 weeks ago

liwen-tj commented 2 weeks ago

Hello everyone!

I met a problem when trying to use NotificationAttrib What I want is I can get an initial value when startup and whenever data changes, I can immediately get the changed value. How do I set trans_mode and max_delay and cycle_time param?

I have read https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/117553803.html&id=1821528703544766287 but it seems that we can't always get initial value when plc value is not changed. What is weird is that sometimes I can get the initial value while other time I can not get the initial value when the value is always constant.

import ctypes
import time

import pyads
from pyads.structs import NotificationAttrib, SAdsNotificationHeader
from pyads.constants import ADSTRANS_SERVERONCHA, ADSTRANS_SERVERCYCLE

from covariant_libs import logger

def register_callback(client) -> None:
    def callback_func(notification: SAdsNotificationHeader, key: str):
        _, _, current_status = client.parse_notification(notification, pyads.PLCTYPE_UINT)
        logger.info(f"--> {key=}, {current_status=}")

    client.add_device_notification(
        data="MAIN.safety_2.safety_status",
        attr=NotificationAttrib(length=ctypes.sizeof(pyads.PLCTYPE_UINT), trans_mode=ADSTRANS_SERVERONCHA, max_delay=1, cycle_time=0),
        callback=callback_func,
    )

    client.add_device_notification(
        data="MAIN.machine_control_2.machine_status",
        attr=NotificationAttrib(length=ctypes.sizeof(pyads.PLCTYPE_UINT), trans_mode=ADSTRANS_SERVERONCHA, max_delay=1, cycle_time=0),
        callback=callback_func,
    )

if __name__ == "__main__":
    ams_net_port = 851
    plc_ams_net_id = "192.168.**.**.1.1"
    plc_ip_address = "192.168.**.**"
    plc_password = "**"
    plc_user_name = "**"
    route_name = "***_PLC_2"
    sender_ams_address = "192.168.**.**.1.1"
    sender_ip_address = "192.168.**.**"
    pyads.open_port()
    pyads.set_local_address(sender_ams_address)
    pyads.add_route_to_plc(
        sender_ams_address,
        sender_ip_address,
        plc_ip_address,
        plc_user_name,
        plc_password,
        route_name=route_name,
    )
    pyads.close_port()

    plc = pyads.Connection(
        ams_net_id=plc_ams_net_id,
        ams_net_port=ams_net_port,
        ip_address=plc_ip_address,
    )

    plc.open()
    register_callback(plc)

    print(f"{time.time()} plc local address:", plc.get_local_address())
    print(f"{time.time()} Plc symbols length: ", len(plc.get_all_symbols()))

    time.sleep(10000)
    plc.close()