python-opcua icon indicating copy to clipboard operation
python-opcua copied to clipboard

Using infinite while loop or def datachange_notification(self, node, val, data) of Handler for calculating DOWNTIME values based on 3 Bit values in realtime and facing TIMEOUT Error issue

Open rajnishnationfirst opened this issue 4 years ago • 5 comments

Hi ,

I need to use def datachange_notification(self, node, val, data): method of the handler class.

a) I am subscribing ( using handler ) and/or checking ( by accessing node value using node.get_value()) a RUNNING TAG1 of a machine to get the value from 1 to 0 .. here 1 indicates machine is running and 0 its stopped .

b) Here when running bit is 0 , i will check for another TAG2 called as DOWNTIME started ( here i will note the start time of downtime) , after getting the status of this as 1 , then again i will check for Reason for downtime TAG3 which has values ranging from 1., 2, 3, 4,.......7 ( which has reasons ) .

c) After i get the reason for downtime TAG3 value , i will check for when the RUNNING TAG1 as 1 , then i will note this end time and calculate Downtime in hours

The above both point A ,B and C happens when machine is stopped to calculate the downtime of the machine based on RUNNING TAG1 , Downtime Started TAG2 and Reason For Downtime TAG3 .

Consider TAG 1 - Running BIT , TAG2 - Downtime Started Bit and TAG3 as Reason specified bit.

@oroulet sir , your suggested to use client.get_values() and subscription logic, but i am not able to apply for the above case.

I tried using infinite loop like

a) Using Infinite While Loop: ( Here below i will check all values instantaneously in infinite while loop based on TAG1 , TAFG2 and TAG3 value.

while True:
           global st_time_exe
           print("RUNNING BIT VALUE",self.run_tag.get_value())
           #print("DT STARTED BIT VALUE", self.dt_started.get_value())
           #print("MAIN REASON BIT VALUE", self.main_reason.get_value())
           while True:
               if self.run_tag.get_value()  == True:
                   print("RUNNING BIT STATES RUNNING")
                   break;
               else:
                   print("STOPPED")
                   while True:
                       if self.dt_started.get_value() == True:
                           print("DT STARTED")
                           st_time_exe=time.time();
                           if self.run_tag.get_value() == True:
                               print("RUNNING STARTED IN DT STARTED")
                               break;
                           while True:
                               if self.dt_not_decided.get_value() == False:
                                   print("REASON NOT SPECIFIED")
                               else:
                                   print("REASON SPECIFIED")
                                   if self.run_tag.get_value() == True:
                                       et_time_exe = time.time();
                                       main_reason_specified=self.main_reason.get_value()
                                       array_main_reasons=[]
                                       #postgres_select_query = "SELECT * FROM main_reason_rcbl_stck_erp where value='1'"
                                       #cursor.execute(postgres_select_query)

                                       postgres_select_query = "SELECT * FROM main_reason_rcbl_stck_erp where value = %s"
                                       cursor.execute(postgres_select_query, (str(main_reason_specified),))
                                       tup = cursor.fetchall()
                                       downtime_main_reasons = list(sum(tup, ()))
                                       print(downtime_main_reasons)
                                       print(len(downtime_main_reasons))
                                       main_reason_id = downtime_main_reasons[0]
                                       main_reason_code = downtime_main_reasons[1]
                                       main_reason_type = downtime_main_reasons[2]
                                       main_reason_tagname = downtime_main_reasons[3]
                                       main_reason_tag_node_to_check_subreason = downtime_main_reasons[4]

                                       if main_reason_type=='' or main_reason_type=='':
                                           print("PM & Organisational BLOCK")

                                           array_main_reasons.append("Machine_Name")
                                           array_main_reasons.append(
                                               datetime.datetime.fromtimestamp(st_time_exe).strftime(
                                                   "%Y-%m-%d"))
                                           array_main_reasons.append(self.get_Shift())
                                           array_main_reasons.append(main_reason_type)
                                           array_main_reasons.append("NA")
                                           array_main_reasons.append(
                                               datetime.datetime.fromtimestamp(st_time_exe).strftime(
                                                   "%Y-%m-%d %H:%M:%S.%f"))
                                           array_main_reasons.append(
                                               datetime.datetime.fromtimestamp(et_time_exe).strftime(
                                                   "%Y-%m-%d %H:%M:%S.%f"))
                                           array_main_reasons.append(et_time_exe - st_time_exe)

                                           columns_string_main_reasons_log = '"' + 'machine_name' + '"' + ',' + '"' + 'date' + '"' + ',' + '"' + 'shift' + '"' + \
                                                                             ',' + '"' + 'main_reason' + '"' + ',' + '"' + 'sub_reason' + '"' + \
                                                                             ',' + '"' + 'start_time' + '"' + ',' + '"' + 'end_time' + '"' + \
                                                                             ',' + '"' + 'duration_hrs' + '"'
                                           # print('COL STRING', columns_string)
                                           final_col_string_mainreason_log = '(' + columns_string_main_reasons_log + ')'

                                           sql_stmt_insert_main_reason = "INSERT INTO " + "main_reasons_table" + final_col_string_mainreason_log + "VALUES" + str(
                                               tuple(array_main_reasons))

                                           # print('Sql statement',sql_stmt)

                                           v = cursor.execute(sql_stmt_insert_main_reason);
                                           conn.commit()
                                           print("DOWNTIME LOG CREATED SUCCESSFULLY");
                                           break;


                                       else:
                                           print("NOT PM & Organisational BLOCK")
                                           sub_reason_tag_code = hda_client.get_node(main_reason_tag_node_to_check_subreason).get_value()
                                           print("SUB REASON NODE",sub_reason_tag_code)
                                           print("SUB REASON CODE", sub_reason_tag_code.get_value())
                                           postgres_subreason_query = "SELECT * FROM sub_reason_erp_rcbl where main_reason_value=%s and sub_main_reason_value=%s"
                                           cursor.execute(postgres_subreason_query, (str(main_reason_specified),str(sub_reason_tag_code)))

                                           sub_reasons = cursor.fetchall()
                                           downtime_sub_reasons = list(sum(sub_reasons, ()))
                                           print(downtime_sub_reasons)
                                           print(len(downtime_sub_reasons))
                                           main_reason_value = downtime_main_reasons[0]
                                           main_reason_description= downtime_main_reasons[1]
                                           sub_main_reason_value = downtime_main_reasons[2]
                                           sub_main_reason_description = downtime_main_reasons[3]
                                           sub_reason_ids = downtime_main_reasons[4]
                                           array_main_reasons.append("RCBL")
                                           array_main_reasons.append(datetime.datetime.fromtimestamp(st_time_exe).strftime("%Y-%m-%d %H:%M:%S.%f"))
                                           array_main_reasons.append(self.get_Shift())
                                           array_main_reasons.append(main_reason_description)
                                           array_main_reasons.append(sub_main_reason_description)
                                           array_main_reasons.append(datetime.datetime.fromtimestamp(st_time_exe).strftime("%Y-%m-%d %H:%M:%S.%f"))
                                           array_main_reasons.append(
                                               datetime.datetime.fromtimestamp(et_time_exe).strftime("%Y-%m-%d %H:%M:%S.%f"))
                                           array_main_reasons.append(et_time_exe-st_time_exe)

                                           columns_string_main_reasons_log = '"' + 'machine_name' + '"' + ',' + '"' + 'date' + '"' + ',' + '"' + 'shift' + '"' + \
                                                                     ',' + '"' + 'main_reason' + '"' + ',' + '"' + 'sub_reason' + '"' + \
                                                                     ',' + '"' + 'start_time' + '"' + ',' + '"' + 'end_time' + '"' + \
                                                                     ',' + '"' + 'duration_hrs' + '"'
                                           # print('COL STRING', columns_string)
                                           final_col_string_mainreason_log = '(' + columns_string_main_reasons_log + ')'

                                           sql_stmt_insert_main_reason = "INSERT INTO " + "main_reasons_table" + final_col_string_mainreason_log + "VALUES" + str(
                                               tuple(array_main_reasons))

                                           # print('Sql statement',sql_stmt)

                                           v = cursor.execute(sql_stmt_insert_main_reason);
                                           conn.commit()
                                           print("DOWNTIME LOG CREATED SUCCESSFULLY");
                                           break;

                                   else:
                                       print("REASON SPECIFIED DOWNTIME STILL CONTINUED")
                       else:
                           print("DT NOT STARTED")
                           print("RUNNING STATUS",self.run_tag.get_value())
                           break;

b) I tried using def datachange_notification(self, node, val, data): ( Here below all TAG1 value , TAG2 value , TAG3 value is accesed inside datachange_notification(self, node, val, data):

import sys
sys.path.insert(0, "..")
import logging
import time

try:
    from IPython import embed
except ImportError:
    import code

    def embed():
        vars = globals()
        vars.update(locals())
        shell = code.InteractiveConsole(vars)
        shell.interact()


from opcua import Client
from opcua import ua

import psycopg2

conn = psycopg2.connect(database="test_array_db_3", user="postgres", password="12345",
                        host="127.0.0.1")
cursor = conn.cursor()

class SubHandler(object):
    def __init__(self, obj):
        self.obj = obj
    def datachange_notification(self, node, val, data):
        #_node_name = node.get_browse_name()
        #setattr(self.obj, _node_name.Name, data.monitored_item.Value.Value.Value)
        print("Python: New data change event", node, val)
        if val==False:
            print("RUNNING")
            postgres_select_query = "SELECT * FROM main_reason_rcbl_stck_erp where value='1'"
            cursor.execute(postgres_select_query)
            tup = cursor.fetchall()
            downtime_main_reasons = list(sum(tup, ()))
            print(downtime_main_reasons)
            print(len(downtime_main_reasons))
            main_reason_id=downtime_main_reasons[0]
            main_reason_code=downtime_main_reasons[1]
            main_reason_type = downtime_main_reasons[2]
            main_reason_tagname = downtime_main_reasons[3]
            main_reason_tag_node_to_check_subreason = downtime_main_reasons[4]

            sub_reason_tag_code=client.get_node(main_reason_tag_node_to_check_subreason)
            print("SUB REASON")
            vr=sub_reason_tag_code.get_value()
            #print("SUB2 REASON")

            #print("SUB REASON CODE",sub_reason_tag_code.get_value())

        else:
            print("STOPPED")
            if dt_started==True:
                print("DT STARTED")

                if dt_not_decided==False:
                    print("REASON NOT SPECIFIED")

                else:
                    print("REASON SPECIFIED")



                    postgres_select_query = "SELECT * FROM main_reason_rcbl_stck_erp"
                    cursor.execute(postgres_select_query)
                    tup = cursor.fetchall()
                    downtime_main_reasons = list(sum(tup, ()))
                    print(downtime_main_reasons)
                    print(len(downtime_main_reasons))

            else:
                print("DT NOT STARTED")

class machine_centre_downtime(object):
    def __init__(self,client,run_tag,dt_started,main_reason,dt_not_decided):
        self.ua_node = run_tag
        #self.ua_node = dt_started
        #self.ua_node = main_reason
        #self.ua_node = dt_not_decided
        handler = SubHandler(self)
        sub = client.create_subscription(500, handler)
        handle = sub.subscribe_data_change(self.ua_node)

if __name__ == "__main__":
    client = Client("opc.tcp://WINCCSERVERA:4862")
    try:
        client.connect()
        root = client.get_root_node()
        #myvar = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"])
        # Now getting a variable node using its browse path
        #run_tag, dt_started, main_reason, dt_not_decided
        run_tag= client.get_node('ns=1;s=t|RUNNING_STCK')
        dt_started = client.get_node('ns=1;s=t|DN_STRTED_STCK')
        main_reason = client.get_node('ns=1;s=t|DN_REASONS_NOT_DECIDED_STCK')
        dt_not_decided = client.get_node('ns=1;s=t|MAIN_REASON_STCK')

        sub_reason_tag_code = client.get_node('ns=1;s=t|ELECTRICAL_ERP_STCK')
        print("SUB REASON")
        vr = sub_reason_tag_code.get_value()
        print("SUB2 REASON",vr)


        rcblDowntimeHandlerObj = machine_centre_downtime(client, run_tag,dt_started,main_reason,dt_not_decided)
        time.sleep(1)
    finally:
        #client.disconnect()
        print("myvar is:")

In the above both the cases i am facing TIME OUT issue and how can i do this .

The above is the case for only machine , there will be such 22 machines and i will create muliple objects of HANDLERs .

How to tacke this.

Thanks

Rajnish Vishwakarma

rajnishnationfirst avatar Dec 05 '20 15:12 rajnishnationfirst

What stops you from deferred execution of your "stop handling routine" on a different thread than your subscription handler? That would immediately unblock the communication thread, and prevent you from needing active polling. And save a ton of network load.

starturtle avatar Dec 05 '20 15:12 starturtle

Thanks @starturtle for your reply .

Could you pls help me with the an example explaining your statements - " What stops you from deferred execution of your "stop handling routine" on a different thread than your subscription handler? That would immediately unblock the communication thread, and prevent you from needing active polling. "

Requesting @starturtle to pls help me with your guidance that would really help me to solve the problems very fast.

Thanks

Rajnish Vishwakarma

rajnishnationfirst avatar Dec 05 '20 16:12 rajnishnationfirst

I don't have a dev env for python at hand anytime soon, sorry. But will elaborate, hoping to get you on track.

The core idea would be to create a worker thread waiting for new items in an event queue, and feeding that queue from inside the subscription handler (only). For an intro, see this tutorial, for example.

The smallest "queue" is a "conditional variable" (actual or semantical) that waits for the subscription handler to set it. If you have concurrent.futures available, it should help a lot. The subscription object needs to stay alive anyway, so you can make arrangements that your objects can reach one another through it.

starturtle avatar Dec 05 '20 17:12 starturtle

@rajnishnationfirst you are really asking a lot of open source developers working for free... Questions like this have nothing to do with issues related to the library and are almost entirely about basic python skills. I hope in the future you consider contributing back to the open source projects you are using to make your application.

zerox1212 avatar Dec 05 '20 21:12 zerox1212

@rajnishnationfirst you are really asking a lot of open source developers working for free... Questions like this have nothing to do with issues related to the library and are almost entirely about basic python skills. I hope in the future you consider contributing back to the open source projects you are using to make your application.

@zerox1212 yes sure .. i will share the solution which i did for the hurdles which i faced and facing during the phase of the development.

rajnishnationfirst avatar Dec 06 '20 07:12 rajnishnationfirst