import threading
import socket

NODE_RED_SERVER_PORT = 4445
NODE_RED_CLIENT_PORT = 4444

class NodeRedDoorbellServerThread(threading.Thread):
    """
    Get doorbell triggers from NodeRed.
    """
    def __init__(self, intercom):
        super(NodeRedDoorbellServerThread, self).__init__()
        self.intercom = intercom
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.running = True
        

    def run(self):
        self.server_socket.bind(('', NODE_RED_SERVER_PORT))
        self.server_socket.listen(1)
        conn, addr = self.server_socket.accept()
        while self.running:
            data = conn.recv(1024)
            if not data:
                print("no data breaking")
                break
            else:
                self.intercom.onBellPressed()
        conn.close()


class NodeRedDoorOpenClient():
    """
    Send open door commands to NodeRed.
    """
    def __init__(self):
        super(NodeRedDoorOpenClient, self).__init__()
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(("127.0.0.1", NODE_RED_CLIENT_PORT))

    def sendOpenDoor(self):
        self.client_socket.send(b'open')

import threading
import socket

NODE_RED_SERVER_PORT = 4445
NODE_RED_CLIENT_PORT = 4444

class NodeRedDoorbellServerThread(threading.Thread):
    """
    Get doorbell triggers from NodeRed.
    """
    def __init__(self, intercom):
        super(NodeRedDoorbellServerThread, self).__init__()
        self.intercom = intercom

    def run(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
            self.running = True
            self.server_socket.bind(('', NODE_RED_SERVER_PORT))
            self.server_socket.listen(1)
            while self.running:
                conn, addr = self.server_socket.accept()
                with conn:
                    while self.running:
                        data = conn.recv(1024)
                        if not data:
                            print("no data breaking")
                            break
                        else:
                            self.intercom.onBellPressed()


class NodeRedDoorOpenClient():
    """
    Send open door commands to NodeRed.
    """
    def __init__(self):
        super(NodeRedDoorOpenClient, self).__init__()
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(("127.0.0.1", NODE_RED_CLIENT_PORT))

    def sendOpenDoor(self):
        self.client_socket.send(b'open')

Use with handler to safely close the server socket and connection
Use with handler to safely close the server socket and connection

  import threading
  import socket
  
  NODE_RED_SERVER_PORT = 4445
  NODE_RED_CLIENT_PORT = 4444
  
  class NodeRedDoorbellServerThread(threading.Thread):
      """
      Get doorbell triggers from NodeRed.
      """
      def __init__(self, intercom):
          super(NodeRedDoorbellServerThread, self).__init__()
          self.intercom = intercom
-         self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-         self.running = True
-         
  
      def run(self):
+         with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
+             self.running = True
-         self.server_socket.bind(('', NODE_RED_SERVER_PORT))
+             self.server_socket.bind(('', NODE_RED_SERVER_PORT))
-         self.server_socket.listen(1)
+             self.server_socket.listen(1)
-         conn, addr = self.server_socket.accept()
-         while self.running:
+             while self.running:
+                 conn, addr = self.server_socket.accept()
+                 with conn:
+                     while self.running:
-             data = conn.recv(1024)
+                         data = conn.recv(1024)
-             if not data:
+                         if not data:
-                 print("no data breaking")
+                             print("no data breaking")
-                 break
+                             break
-             else:
+                         else:
-                 self.intercom.onBellPressed()
+                             self.intercom.onBellPressed()
-         conn.close()
  
  
  class NodeRedDoorOpenClient():
      """
      Send open door commands to NodeRed.
      """
      def __init__(self):
          super(NodeRedDoorOpenClient, self).__init__()
          self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          self.client_socket.connect(("127.0.0.1", NODE_RED_CLIENT_PORT))
  
      def sendOpenDoor(self):
          self.client_socket.send(b'open')
  
Use with handler to safely close the server socket and connection
## Code Before:
import threading
import socket

NODE_RED_SERVER_PORT = 4445
NODE_RED_CLIENT_PORT = 4444

class NodeRedDoorbellServerThread(threading.Thread):
    """
    Get doorbell triggers from NodeRed.
    """
    def __init__(self, intercom):
        super(NodeRedDoorbellServerThread, self).__init__()
        self.intercom = intercom
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.running = True
        

    def run(self):
        self.server_socket.bind(('', NODE_RED_SERVER_PORT))
        self.server_socket.listen(1)
        conn, addr = self.server_socket.accept()
        while self.running:
            data = conn.recv(1024)
            if not data:
                print("no data breaking")
                break
            else:
                self.intercom.onBellPressed()
        conn.close()


class NodeRedDoorOpenClient():
    """
    Send open door commands to NodeRed.
    """
    def __init__(self):
        super(NodeRedDoorOpenClient, self).__init__()
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(("127.0.0.1", NODE_RED_CLIENT_PORT))

    def sendOpenDoor(self):
        self.client_socket.send(b'open')

## Instruction:
Use with handler to safely close the server socket and connection
## Code After:
import threading
import socket

NODE_RED_SERVER_PORT = 4445
NODE_RED_CLIENT_PORT = 4444

class NodeRedDoorbellServerThread(threading.Thread):
    """
    Get doorbell triggers from NodeRed.
    """
    def __init__(self, intercom):
        super(NodeRedDoorbellServerThread, self).__init__()
        self.intercom = intercom

    def run(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
            self.running = True
            self.server_socket.bind(('', NODE_RED_SERVER_PORT))
            self.server_socket.listen(1)
            while self.running:
                conn, addr = self.server_socket.accept()
                with conn:
                    while self.running:
                        data = conn.recv(1024)
                        if not data:
                            print("no data breaking")
                            break
                        else:
                            self.intercom.onBellPressed()


class NodeRedDoorOpenClient():
    """
    Send open door commands to NodeRed.
    """
    def __init__(self):
        super(NodeRedDoorOpenClient, self).__init__()
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(("127.0.0.1", NODE_RED_CLIENT_PORT))

    def sendOpenDoor(self):
        self.client_socket.send(b'open')
