Difficulty instantiating a subclass [object has no attribute]

Question:

I get two types of errors when I try to start or initiate the member function temp_controll from the subclass Temperature_Controll. The issue is that the while loops are started in a new thread.

I am having trouble passing the modbus client connection to the member function.

 AttributeError: 'ModbusTcpClient' object has no attribute 'modbus'

I don’t understand the problem in its entirety, because I assumed I would inherit modbus.client from the main class?

The second problem was, when I comment out rp and want to access a member function from the main class "database_reading", I get the following error:

 AttributeError: 'str' object has no attribute 'database_reading'

How can I execute the subclass method via a second thread?

class Echo(WebSocket):

    def __init__(self, client, server, sock, address):
        super().__init__(server, sock, address)
        self.modbus = client

    def database_reading(self)
        do_something()
        return data


class Temperature_Controll2(Echo):

    def __init__(self, client):
        super(Temperature_Controll, self).__init__(client)
        self.modbus = client
    
    def temp_controll(self, value):
        #super().temp_controll(client)
        while True:
            print("temp_controll")
            rp = self.modbus.read_coils(524, 0x1)
            print(rp.bits[0])

            self.database_reading()
    

def main():
    logging.basicConfig()
    with ModbusClient(host=HOST, port=PORT) as client:
        client.connect()
        time.sleep(0.01)
        print("Websocket server on port %s" % PORTNUM)
        server = SimpleWebSocketServer('', PORTNUM, partial(Echo, client))
        
        control = Temperature_Controll2.temp_controll
        t2 = threading.Thread(target=control, args=(client, 'get'))
        t2.start()
        
        try:
            t1 = threading.Thread(target=server.serveforever())
            t1.start()
        finally:
            server.close()

if __name__ == "__main__":
    main()

This is a minimal example of my code, the thread t1 is executed without any problems. I have little experience with OOP programming, maybe someone here can help, thanks!

Asked By: Gool

||

Answers:

You get this error:

 AttributeError: 'ModbusTcpClient' object has no attribute 'modbus'

because when the Thread that you create:

t2 = threading.Thread(target=control, args=(client, 'get'))

calls Temperature_Controll2.temp_controll(client, 'get'),

on this line: rp = self.modbus.read_coils(524, 0x1) the self is actually the client variable you created here:

with ModbusClient(host=HOST, port=PORT) as client:

and is not an instance of Temperature_Controll2 that I assume you were expecting.

Answered By: quamrana

Ok, thank you again, the solution is:

class Temperature_Controll2(Echo):

    def __init__(self, client):
        #super(Temperature_Controll2, self).__init__() #client , server, sock, address, database_reading)
        #super().__init__()
        self.modbus = client

    def temp_controll(self, value):
        #super().temp_controll(client)
        while True:
            print("temp_controll")
            rp = self.modbus.read_coils(524, 0x1)
            time.sleep(4)

def main():
    with ModbusClient(host=HOST, port=PORT) as client:
        client.connect()
        time.sleep(0.01)

        print("Websocket server on port %s" % PORTNUM)
        server = SimpleWebSocketServer('', PORTNUM, partial(Echo, client))

        control = Temperature_Controll2(client)
        t2 = threading.Thread(target=control.temp_controll('get'))

        try:
            t1 = threading.Thread(target=server.serveforever())
            t1.start()
        finally:
            server.close()

But with client I can only make one connection to the modbus server, so either the websocket or the while loop works. I think I would have to approach the problem differently.

Answered By: Gool

A short addendum, I think, I now know why the second variant does not work.

This variant is running until the temp_control in class Echo comes to the point, in which modbus modul was called by a funcion. Modbus module is not part of the mother class Echo, which is why I think this cannot be inherited.

Modbus is passed to the class Echo as a variable via partial and will thus instantiate (I hope I am expressing myself correctly). Therefore, only the variant in which the variable client is passed to the instance will work.

# This is a non-functional version of my programme and is for information only

class Echo(WebSocket):

    def __init__(self, client, server, sock, address):
        super().__init__(server, sock, address)
        self.modbus = client

    def temp_control(self)
        do_something()
        return True

class Temperature_Control3(Echo):

    def __init__(self, value=None): #, client, server, sock, address):
        #super(Temperature_Control3, self).__init__(server, sock, address) 
        if value is None:
            value = {}
        self.value = value

    def control(self, value):
        while True:
            self.temp_control(524, 'get')
            #self.database_reading()[0][1]
            time.sleep(2)


def main():
    with ModbusClient(host=HOST, port=PORT) as client:
        client.connect()
        time.sleep(0.01)

        print("Websocket server on port %s" % PORTNUM)
        server = SimpleWebSocketServer('', PORTNUM, partial(Echo, client))

        control = Temperature_Control3()

        t3 = threading.Thread(target=lambda:control.control('get')) 
        t3.start()

        try:
            t1 = threading.Thread(target=server.serveforever())
            t1.start()
            for thread in threading.enumerate():
                print(thread.name)
        finally:
            server.close()
Answered By: Gool