Bouni / python-luxtronik

python-luxtronik is a library that allow you to interact with a Luxtronik heatpump controller.
MIT License
37 stars 19 forks source link

Support multi-threadded applications #166

Closed Guzz-T closed 6 months ago

Guzz-T commented 6 months ago

The implementation of the lock mechanism may be insufficient for multi-threaded applications. In case:

Then, the lock() from thread A does not block access from thread B.

Am i right?

Possible Solution: Use a class dictionary (ip-address to lock-object) instead of a instance member _lock.

Use case: Home-Assistant with two independent integrations. For example BenPru/luxtronik for high-level functions and Bouni/luxtronik for other missing values

gerw commented 6 months ago

Is this really a problem? Did you observed any problems?

From my understanding, each instance of Luxtronik (or LuxtronikSocketInterface) opens its own socket and can communicate independently with the heat pump.

Guzz-T commented 6 months ago

I have got problems in homeassistant. But i cannot reproduce it with the bare python-luxtronik. Maybe my workaround solved another problem.

I'll keep an eye on it and reopen the issue if necessary.

Testcode:

#! /usr/bin/env python3

import threading
from luxtronik import LuxtronikSocketInterface

IP = '192.168.13.2'

def calc_function(lux, data):
    l = LuxtronikSocketInterface(IP)
    #l = lux
    while True:
        c = l.read_calculations()
        for number, item in c:
            orig_item = data.get(number)
            if orig_item.raw != item.raw:
                print(f'Calc - Item differs: {orig_item} !== {item}')
            #else:
            #    print(f'Calc - Item match: {item}')

def visi_function(lux, data):
    l = LuxtronikSocketInterface(IP)
    #l = lux
    while True:
        c = l.read_visibilities()
        for number, item in c:
            orig_item = data.get(number)
            if orig_item.raw != item.raw:
                print(f'Visi - Item differs: {orig_item} != {item}')
            #else:
            #    print(f'Visi - Item match: {item}')

def para_function(lux, data):
    l = LuxtronikSocketInterface(IP)
    #l = lux
    while True:
        c = l.read_parameters()
        for number, item in c:
            orig_item = data.get(number)
            if orig_item.raw != item.raw:
                print(f'Para - Item differs: {orig_item} != {item}')
            #else:
            #    print(f'Para - Item match: {item}')

if __name__ == "__main__":

    lux = LuxtronikSocketInterface(IP)
    data = lux.read()

    #calc = threading.Thread(target=calc_function, args=(lux, data.calculations,))
    visi = threading.Thread(target=visi_function, args=(lux, data.visibilities,))
    par1 = threading.Thread(target=para_function, args=(lux, data.parameters,))
    par2 = threading.Thread(target=para_function, args=(lux, data.parameters,))

    #calc.start()
    visi.start()
    par1.start()
    par2.start()
gerw commented 6 months ago

You are aware that BenPru/luxtronik does not use this python module itself, but rather contains a copy of the code? Maybe this is causing some problems.