Menu

S7 read cycle slow b'CLI : Job pending

macs
2018-06-18
2018-06-20
  • macs

    macs - 2018-06-18

    Hello David,
    I have to say at the beginning that I'm not a programmer. I found Snap7 in conjunction with Smarthome to read and write data from an S7-300 controller. The program works on the whole, but I constantly get error message.

    2018-06-18  22:15:37 ERROR    S7 read cycle slow b'CLI : Job pending'
    2018-06-18  22:15:37 ERROR    S7 read cycle slow Method S7 read cycle slow exception: b'CLI : Job pending'
    Traceback (most recent call last):
      File "/usr/local/smarthome/lib/scheduler.py", line 449, in _task
        obj()
      File "/usr/local/smarthome/plugins/s7/__init__.py", line 283, in _read_slow
        result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 4)       #Lese    DB / Ab / Byte
      File "/usr/local/lib/python3.5/dist-packages/snap7/client.py", line 142, in db_read
        check_error(result, context="client")
      File "/usr/local/lib/python3.5/dist-packages/snap7/common.py", line 65, in check_error
        raise Snap7Exception(error)
    snap7.snap7exceptions.Snap7Exception: b'CLI : Job pending'
    

    Enclosed is the code from the Smarthome application.

    import logging
    import threading
    import struct
    import binascii
    import re
    
    import snap7
    from snap7.snap7exceptions import Snap7Exception
    from snap7.snap7types import S7AreaDB, S7WLBit, S7WLByte, S7WLWord, S7WLDWord, S7WLReal, S7DataItem
    from snap7.util import *
    
    import lib.connection
    
    tcpport = 102
    rack = 0
    slot = 2
    
    logger = logging.getLogger('')
    
    class S7(lib.connection.Client):
    
        def __init__(self, smarthome, time_ga=None, date_ga=None, read_cyl_fast=1, read_cyl_slow=10, busmonitor=False, host='127.0.0.1', port=102):
            self.client = snap7.client.Client()
            self.client.connect(host, rack, slot, tcpport)
    
            lib.connection.Client.__init__(self, host, port, monitor=False)
            self._sh = smarthome
            self.gal = {}
            self.gar = {}
            self._init_ga = []
            self._cache_ga = []
            self.time_ga = time_ga
            self.date_ga = date_ga
            self._lock = threading.Lock()
    
            if read_cyl_fast:
                self._sh.scheduler.add('S7 read cycle fast', self._read_fast, prio=5, cycle=int(read_cyl_fast))
    
            if read_cyl_slow:
                self._sh.scheduler.add('S7 read cycle slow', self._read_slow, prio=5, cycle=int(read_cyl_slow))
    
        def _send(self, data):
    
            if len(data) < 2 or len(data) > 0xffff:                                          # 0xffff = 65535
                logger.debug('S7: Illegal data size: {}'.format(repr(data)))
                return False
    
            # prepend data length
            send = bytearray(len(data).to_bytes(2, byteorder='big'))
            send.extend(data)
            self.send(send)
    
        # ------------------------
        # Daten schreiben
        # ------------------------
        def groupwrite(self, ga, payload, dpt, flag='write'):
            print("groupwrite")
            print("ga: " +  ga)
            print("payload: " +  str(payload))
            print("dpt: " +  dpt)
            print("flag: " +  flag)
            ret_s7_num = re.findall(r'\d+', ga)
    
            if dpt == '1':
                #Schreibe Bool
                print("Schreibe Bool")
    
                ret_val = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 1)      #Lese    DB / Ab / Byte
    
                writevalue = payload
                snap7.util.set_bool(ret_val, 0, int(ret_s7_num[2]), writevalue)               #Schreibe    Value aus Byte / Adresse 
                self.client.db_write(int(ret_s7_num[0]), int(ret_s7_num[1]), ret_val)         #Schreibe    DB / Ab / Byte
    
            elif dpt == '5':
                # Schreibe Dezimalzahl#
                print("Schreibe Dezimalzahl")
    
                write_value_5 = payload
                write_bytes_5 = bytearray(struct.pack('>h', write_value_5))            
                self.client.db_write(int(ret_s7_num[0]), int(ret_s7_num[1]), write_bytes_5)          #Schreibe    DB / Ab / Byte
    
            elif dpt == '6':
                # Schreibe Gleitzahl
                print("Schreibe Gleitzahl")
    
                write_value_6 = payload
                write_bytes_6 = bytearray(struct.pack('>f', write_value_6))              
                self.client.db_write(int(ret_s7_num[0]), int(ret_s7_num[1]), write_bytes_6)         #Schreibe    DB / Ab / Byte
    
        # ------------------------
        # Daten Lesen
        # ------------------------
        def groupread(self, ga, dpt):
            print("groupread")
            print("ga: " +  ga)
            print("dpt: " +  dpt)
            ret_s7_num = re.findall(r'\d+', ga)
            val = 0                 #Item-Value
            src = ga                #Source-Item      (Quell-Adresse)
            dst = ga                #Destination-Item (Ziel-Adresse)
    
            if dpt == '1':
                #Lese Bool
                print("Lese Bool")
    
                ret_val = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 1)      #Lese    DB / Ab / Byte
                val = snap7.util.get_bool(ret_val, 0, int(ret_s7_num[2]))                     #Lese    Value aus Byte / Adresse 
    
            elif dpt == '5':
                # Lese Dezimalzahl#
                print("Lese Dezimalzahl")
    
                result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 2)       #Lese    DB / Ab / Byte    
                bytes = ''.join([chr(x) for x in result]).encode('utf-8')
                int_num = struct.unpack('>h', bytes)
                int_num2 = re.findall(r'\d+', str(int_num))
                val = int_num2[0]
    
            elif dpt == '6':
                # Lese Gleitzahl
                print("Lese Gleitzahl")
    
                result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 4)       #Lese    DB / Ab / Byte    
                int_num = struct.unpack('>f', result)[0]
                val = int_num
    
            item(val, 'S7', src, ga)
            print(str(val) + ":" + str(val) + ":" + str(src) + ":" + str(ga))
    
        # --------------------------
        # Daten lesen Zyklus schnell
        # --------------------------
        def _read_fast(self):
    
            for ga in self._init_ga:
                print("Daten lesen Zyklus schnell")
                print("ga: " +  ga)
                val = 0             #Item-Value
                src = ga            #Source-Item      (Quell-Adresse)
                dst = ga            #Destination-Item (Ziel-Adresse)
    
                for item in self.gal[dst]['items']:
    
                    ret_s7_num = re.findall(r'\d+', dst)
                    var_typ = len(ret_s7_num)
                    dpt = item.conf['s7_dpt']
                    print("dpt: " +  dpt)
    
                    if dpt == '1':
                        #Initialisiere Bool
                        #print("Initialisiere Bool")
    
                        ret_val = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 1)      #Lese    DB / Ab / Byte
                        val = snap7.util.get_bool(ret_val, 0, int(ret_s7_num[2]))                     #Lese    Value aus Byte / Adresse 
    
                    elif dpt == '5':
                        #Initialisiere Dezimalzahl
                        #print("Initialisiere Dezimalzahl")
    
                        result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 2)       #Lese    DB / Ab / Byte    
                        bytes = ''.join([chr(x) for x in result]).encode('utf-8')
                        int_num = struct.unpack('>h', bytes)
                        int_num2 = re.findall(r'\d+', str(int_num))
                        val = int_num2[0]
    
                    elif dpt == '6':
                        #Initialisiere Gleitzahl
                        #print("Initialisiere Gleitzahl")
    
                        result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 4)       #Lese    DB / Ab / Byte    
                        int_num = struct.unpack('>f', result)[0]
                        val = int_num
    
                    item(val, 'S7', src, ga)
                    print(str(val) + ":" + str(val) + ":" + str(src) + ":" + str(ga))
    
        # --------------------------
        # Daten lesen Zyklus langsam
        # --------------------------
        def _read_slow(self):
    
            for ga in self._init_ga:
                print("Daten lesen Zyklus langsam")
                print("ga: " +  ga)
                val = 0             #Item-Value
                src = ga            #Source-Item      (Quell-Adresse)
                dst = ga            #Destination-Item (Ziel-Adresse)
    
                for item in self.gal[dst]['items']:
    
                    ret_s7_num = re.findall(r'\d+', dst)
                    var_typ = len(ret_s7_num)
                    dpt = item.conf['s7_dpt']
                    print("dpt: " +  dpt)
    
                    if dpt == '1':
                        #Initialisiere Bool
                        #print("Initialisiere Bool")
    
                        ret_val = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 1)      #Lese    DB / Ab / Byte
                        val = snap7.util.get_bool(ret_val, 0, int(ret_s7_num[2]))                     #Lese    Value aus Byte / Adresse 
    
                    elif dpt == '5':
                        #Initialisiere Dezimalzahl
                        #print("Initialisiere Dezimalzahl")
    
                        result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 2)       #Lese    DB / Ab / Byte    
                        bytes = ''.join([chr(x) for x in result]).encode('utf-8')
                        int_num = struct.unpack('>h', bytes)
                        int_num2 = re.findall(r'\d+', str(int_num))
                        val = int_num2[0]
    
                    elif dpt == '6':
                        #Initialisiere Gleitzahl
                        #print("Initialisiere Gleitzahl")
    
     result = self.client.db_read(int(ret_s7_num[0]), int(ret_s7_num[1]), 4)       #Lese    DB / Ab / Byte
                        int_num = struct.unpack('>f', result)[0]
                        val = int_num
    
                    item(val, 'S7', src, ga)
                    print(str(val) + ":" + str(val) + ":" + str(src) + ":" + str(ga))
    
        def run(self):
            self.alive = True
    
        def stop(self):
            self.alive = False
            self.handle_close()
    
        def parse_item(self, item):
    
            if 's7_dtp' in item.conf:
                logger.warning("S7: Ignoring {0}: please change s7_dtp to s7_dpt.".format(item))
                return None
    
            if 's7_dpt' in item.conf:
                dpt = item.conf['s7_dpt']
            else:
                return None
    
            if 's7_read_s' in item.conf:
                ga = item.conf['s7_read_s']
                logger.debug("S7: {0} listen on and init with {1}".format(item, ga))
    
                if not ga in self.gal:
                    self.gal[ga] = {'dpt': dpt, 'items': [item], 'logics': []}
    
                else:
                    if not item in self.gal[ga]['items']:
                        self.gal[ga]['items'].append(item)
                self._init_ga.append(ga)
    
            if 's7_read_f' in item.conf:
                ga = item.conf['s7_read_f']
                logger.debug("S7: {0} listen on and init with {1}".format(item, ga))
    
                if not ga in self.gal:
                    self.gal[ga] = {'dpt': dpt, 'items': [item], 'logics': []}
    
                else:
                    if not item in self.gal[ga]['items']:
                        self.gal[ga]['items'].append(item)
                self._init_ga.append(ga)
    
            if 's7_send' in item.conf:
                if isinstance(item.conf['s7_send'], str):
                    item.conf['s7_send'] = [item.conf['s7_send'], ]
    
            if's7_send' in item.conf:
                return self.update_item_send
    
            return None
    
            if 's7_read' in item.conf:
                return self.update_item_read
    
            return None
    
            if 's7_listen' in item.conf:
                s7_listen = item.conf['s7_listen']
                if isinstance(s7_listen, str):
                    s7_listen = [s7_listen, ]
                for ga in s7_listen:
                    logger.debug("S7: {0} listen on {1}".format(item, ga))
    
                    if not ga in self.gal:
                        self.gal[ga] = {'dpt': dpt, 'items': [item], 'logics': []}
    
                    else:
                        if not item in self.gal[ga]['items']:
                            self.gal[ga]['items'].append(item)
    
        def update_item_send(self, item, caller=None, source=None, dest=None):
    
            if 's7_send' in item.conf:
                if caller != 's7':
                    for ga in item.conf['s7_send']:
                        self.groupwrite(ga, item(), item.conf['s7_dpt'], flag='write')
    
        def update_item_read(self, item, caller=None, source=None, dest=None):
    
            if 's7_status' in item.conf:
                for ga in item.conf['s7_status']:  # send status update
                    if ga != dest:
                        self.groupread(ga, item.conf['s7_dpt'])
    

    Can you give me a clue why this error occurs again and again? What can I do against it?

    Thanks in advance
    Markus

     
  • Davide Nardella

    Davide Nardella - 2018-06-20

    Hi,
    As I said many times, I don't know Python at all.

    Anyway CLI : Job pending error is raised when you try to use the same client contemporary from two threads.
    I.E. you call a read or write function when the client is already working (Job Pending means Job not complete)

    two ways :
    Either semaphorize the calls or use two different clients.

    regards
    Dave

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.