0

first time questioner here! I´m currently working on a python project that´s supposed to read soil moisture through a sensor on a raspberry pi, which then sends the data to another laptop through a socket connection. That other laptop displays the data in a UI. That UI is also capable of controllig the script flow. My Server starts up just fine, but when the client connects to it(connection itself works), I get the following Error Stack:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.5/threading.py", line 862, in run
    self._target(self._args, **self._kwargs)
  File "/home/pi/Py_Scripts/MoistureSensor/Server.py", line 77, in worker_recv
    self.JSON_Control = pickle.loads(self.data_recv)
EOFError: Ran out of input

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.5/threading.py", line 862, in run
    self._target(self._args, **self._kwargs)
  File "/home/pi/Py_Scripts/MoistureSensor/Server.py", line 70, in worker_send
    self.conn.send(self.data_send)
BrokenPipeError: [Errno 32] Broken pipe

My Scripts look as follows:

Client-side:

import sys
from socket import *
from threading import Thread
from time import sleep
import pickle
from PySide6 import QtWidgets, QtGui


class MyClient: 
    def __init__(self, server_port, buf_size, host):
        self.server_port = server_port
        self.buf_size = buf_size
        self.host = host
        self.data_send = None
        self.data_recv = None
        self.exit = False

        self.JSON_Control = {
            "measure": False,
            "exit": False,
        }

        self.JSON_Moisture = {
            "moisture_level": 0
        }

        self.socket_connection = socket(AF_INET, SOCK_STREAM)
        self.socket_connection.connect((self.host, self.server_port))
        print("Connected with Server: %s: " % self.host)

        # thread for sending
        self.thread_send = Thread(target=self.worker_send)
        # thread for receiving
        self.thread_recv = Thread(target=self.worker_recv)

        # starting Threads
        self.thread_send.start()
        self.thread_recv.start()

    def worker_send(self):
        while not self.exit:
            self.data_send = pickle.dumps(self.JSON_Control)
            self.socket_connection.send(self.data_send)
            sleep(0.5)

    def worker_recv(self):
        while not self.exit:
            self.data_recv = self.socket_connection.recv(self.buf_size)
            if self.data_recv is not None:
                self.JSON_Moisture = pickle.loads(self.data_recv)


class UiDisplay(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        self.moisture_label = None
        self.moisture_level = None
        self.start_button = None
        self.refresh_button = None
        self.stop_button = None
        self.reset_button = None
        self.quit_button = None
        self.create_widgets()

    def create_widgets(self):
        # create a label to display the current time
        self.moisture_label = QtWidgets.QLabel(self)
        self.moisture_label.setFont(QtGui.QFont("Helvetica", 16))
        self.moisture_level = client.JSON_Moisture["moisture_level"]
        self.moisture_label.setText('Bodenfeuchtigkeit: ' + str(self.moisture_level)[:3] + '%')

        # button to start the weight measuring
        self.start_button = QtWidgets.QPushButton("Start measuring", self)
        self.start_button.clicked.connect(self.measure_moisture)

        # button to refresh the Weight label
        self.refresh_button = QtWidgets.QPushButton("Refresh", self)
        self.refresh_button.clicked.connect(self.refresh)

        # button to stop measuring
        self.stop_button = QtWidgets.QPushButton("Stop measuring", self)
        self.stop_button.clicked.connect(self.stop_measuring)

        # button to quit the program
        self.quit_button = QtWidgets.QPushButton("Quit", self)
        self.quit_button.clicked.connect(self.quit)

        # create a layout to hold the widgets
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.moisture_label)
        layout.addWidget(self.start_button)
        layout.addWidget(self.refresh_button)
        layout.addWidget(self.stop_button)
        layout.addWidget(self.reset_button)
        layout.addWidget(self.quit_button)
        self.setLayout(layout)

    def measure_moisture(self):
        client.JSON_Control["measure"] = True
    def refresh(self):
        # get current weight ( niederlag auf ein qm rechnen fehlt noch)
        self.moisture_level = round(client.JSON_Moisture["moisture_level"] - 2.7) / (1 - 2.7)
        print(self.moisture_level)
        # umrechnen von analogem Wert zu Prozentanteil
        print(self.moisture_level)
        # update the weight label with the current time
        self.moisture_label.setText('Bodenfeuchtigkeit:  ' + str(self.moisture_level)[:5] + '%')

    def stop_measuring(self):
        if client.JSON_Control["measure"]:
            client.JSON_Control["measure"] = False
        else:
            pass

    def quit(self):
        QtWidgets.QApplication.instance().quit()
        client.JSON_Control["exit"] = True
        sleep(2)
        client.exit = True
        client.thread_recv.join()
        client.thread_send.join()
        client.socket_connection.close()
        print("Server connection is closed")
        print('exiting...')
        sleep(1)
        sys.exit()


client = MyClient(1957, 1024, "192.168.86.121")

app = QtWidgets.QApplication()
window = UiDisplay()
window.show()
app.exec()


--------------------------------------------------------

The Server-side:


import sys
from socket import *
from threading import Thread
import pickle
from time import sleep
import Adafruit_ADS1x15


adc_channel_0 = 0


class SoilMoistureSensor:
    def __init__(self, gain, sps, dry_voltage, saturated_voltage):
        self.adc = Adafruit_ADS1x15.ADS1115()
        self.raw_data = None
        self.moisture_level = None
        # self.voltage = None
        self.gain = gain
        self.sps = sps
        self.dry_voltage = dry_voltage
        self.saturated_voltage = saturated_voltage


class MyServer:
    def __init__(self, echo_port, buf_size):
        self.buf_size = buf_size
        self.echo_port = echo_port
        self.data_send = None
        self.data_recv = None
        self.exit = False
        self.data_json = None
        self.moisture_sensor = SoilMoistureSensor(2, 32, 1, 2.7)  # gain, sps, saturated_voltage,             dry_voltage

        self.JSON_Control = {
            "measure": False,
            "exit": False
        }

        self.JSON_Moisture = {
            "moisture_level": 0,
        }

        self.socket_connection = socket(AF_INET, SOCK_STREAM)
        self.socket_connection.bind(("", self.echo_port))
        self.socket_connection.listen(1)

        print("Server gestartet")
        print("Name des Hosts: ", gethostname())
        print("IP des Hosts: ", gethostbyname(gethostname()))

        self.conn, (self.remotehost, self.remoteport) = self.socket_connection.accept()
        print("Verbunden mit %s %s " % (self.remotehost, self.remoteport))

        # thread for sending
        self.thread_send = Thread(target=self.worker_send)
        # thread for receiving
        self.thread_recv = Thread(target=self.worker_recv)
        # thread for checking Json Control
        self.thread_check_json_control = Thread(target=self.check_json_control)

        # starting Threads
        self.thread_send.start()
        self.thread_recv.start()
        self.thread_check_json_control.start()

    def worker_send(self):
        while not self.exit:
            self.data_send = pickle.dumps(self.JSON_Moisture)
            self.conn.send(self.data_send)
            sleep(0.5)

    def worker_recv(self):
        while not self.exit:
            self.data_recv = self.conn.recv(self.buf_size)
            if self.data_recv is not None:
                self.JSON_Control = pickle.loads(self.data_recv)

    def measure_moisture(self, channel):
        channel = adc_channel_0
        self.moisture_sensor.raw_data = self.moisture_sensor.adc.read_adc(
            channel, self.moisture_sensor.gain, self.moisture_sensor.sps)
        self.JSON_Moisture["moisture_level"] = self.moisture_sensor.raw_data
        print(self.moisture_sensor.raw_data)

    def stop_connection(self):
        self.thread_recv.join()
        self.thread_send.join()
        self.thread_check_json_control.join()
        self.socket_connection.close()
        print("Server connection is closed")
        print('exiting...')
        sys.exit()

    def check_json_control(self):
        while not self.exit:
            if self.JSON_Control["measure"]:
                self.measure_moisture(0)
            if self.JSON_Control["exit"]:
                self.stop_connection()
            sleep(0.5)


server = MyServer(1957, 1024)

I´d be ever so grateful for help and I´m incredibly sorry if I´ve disregarded any question conventions. Cheers!

Tom
  • 1
  • TCP doesn't work that way. https://stackoverflow.com/a/75214952/238704 – President James K. Polk Jan 24 '23 at 17:36
  • I apologize but could you be more specific? What would that mean for my code in layman's terms? I've looked through your link but don't quite get where exactly my error is and how to fix it :/ – Tom Jan 24 '23 at 20:21
  • Look at the assumptions you're making in `worker_recv()`. You're assuming that you get an entire pickled object in a single `recv()` call, but that assumption is invalid. You can't guarantee that. See also https://stackoverflow.com/a/43420503/238704 – President James K. Polk Jan 24 '23 at 20:31

0 Answers0