from django.conf import settings import socket import configparser import abc import select import utils.config as L ''' Generic object for the communication with all the devices (need inheritance) ''' class DeviceController(): __metaclass__ = abc.ABCMeta logger = L.setupLogger("DeviceLogger", "Devices") name = "" config_file = "../config/socket_config.ini" config = None connected = False sock = None ip = None port = None def __init__(self, device_name): self.name = device_name self.getConfig() self.getConnection(device_name) self.connect() @abc.abstractmethod def set(self, command: str, *args): return @abc.abstractmethod def do(self, command: str, *args): return @abc.abstractmethod def get(self, command: str, *args): return def sendMessage(self, message: str) -> int: if (not self.isConnected()): return (1) try: readable, writable, exceptional = select.select([], [self.sock], [self.sock]) if not (writable or exceptional): raise (Exception("Socket not writable")) self.sock.send(bytes(message, "UTF-8")) except Exception as e: if (settings.DEBUG): self.log(self.name, "Could not send message on socket : " + message + " -> " + str(e)) return (1) return (0) def isError(self, message: str): if (message == "FAILED" or message == "NOT_SET" or message == "DISCONNECTED"): return (True) return (False) def isConnected(self): if (not self.sock or not self.connected): if (self.connect()): return (False) self.connected = True return (True) def readBytes(self, size) -> str: if (not self.isConnected()): return ("NOT_SET") try: readable, writable, exceptional = select.select([self.sock], [], [self.sock]) if not (readable or exceptional): raise (Exception("Socket not readable")) ret = self.sock.recv(size).decode() if (not ret): if (settings.DEBUG): self.log(self.name, "Connection has been killed") self.connected = False return ("DISCONNECTED") except Exception as e: if (settings.DEBUG): self.log(self.name, "Socket not readable : " + str(e)) return ("FAILED") return (ret) def blockAndReadBytes(self, size) -> str: self.sock.setblocking(1) return (self.readBytes(size)) def blockAndReadMessage(self) -> str: return (self.blockAndReadBytes(1024)) def setBlocking(self, flag): if (not self.sock): return (1) self.sock.setblocking(flag) return (0) # TODO maybe read more than 1024 bytes ????? def readMessage(self) -> str: return self.readBytes(1024) def getConnection(self, device_name): self.ip = self.config.get(device_name, "ip") self.port = int(self.config.get(device_name, "port")) return (0) def getConfig(self): self.config = configparser.ConfigParser() self.config.read(self.config_file) return (0) def log(self, device_name: str, message: str): self.logger.info("From device : " + device_name + " -> " + message) return (0) def connect(self): if (self.ip is None or self.port is None): self.log(self.name, "Ip or Port not initialized") return (1) try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.ip, self.port)) self.sock.setblocking(0) # Default : socket non blocking except Exception as e: if (settings.DEBUG): self.log(self.name, "Failed to connect to " + str(self.ip) + ":" + str(self.port) + " -> " + str(e)) return (1) self.connected = True return (0) # def __init__(self, device_name): # with open(GRAMMAR_FILE) as grammar_file: # grammar = json.load(grammar_file) # # enums = grammar["Enums"] # # for enum in enums: # self.enums[enum] = enums[enum] # # if device_name[:6] == "Camera": # device = grammar["Camera"] # # for item in device["set"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # ''' This transforms 'int' string to type ''' # param_type = locate(param_type) # self.set_msgs.append((item["name"], item["nb_param"], param_type)) # for item in device["get"]: # self.get_msgs.append(item) # for item in device["do"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.do_msgs.append((item["name"], item["nb_param"], param_type)) # # device = grammar[device_name] # # for item in device["set"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.set_msgs.append((item["name"], item["nb_param"], param_type)) # for item in device["get"]: # self.get_msgs.append(item) # for item in device["do"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.do_msgs.append((item["name"], item["nb_param"], param_type)) # # def init_socket(self): # if self.ip is None or self.port is None: # raise ValueError("IP and/or PORT not initialized") # # TODO: gérer un fail de connexion # self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # try: # self.sock.connect((self.ip, self.port)) # except ConnectionError: # print("Connection failed to ip : " + str(self.ip) + " Port : " + str(self.port), file=sys.stderr) # return (1) # return (0) # # def set(self, cmd, *args): # ''' # Send a SET message to the device # ''' # msg = [msg for msg in self.set_msgs if msg[0] == cmd] # if len(msg) == 0: # raise ValueError("Invalid message argument %s" % (cmd,)) # msg = msg[0] # if len(args) not in msg[1]: # raise ValueError("Bad number of arguments") # # if type(msg[2]) is str: # if msg[2] not in self.enums.keys(): # raise TypeError("Enum %s doesn't exist. Please check the grammar.json file." % (msg[2],)) # enum = self.enums[msg[2]] # for arg in args: # if arg not in enum: # raise TypeError("Bad value '%s' for enum '%s'" % (arg, msg[2])) # else: # for arg in args: # if type(arg) != msg[2]: # raise TypeError("Bad type of argument: expected %s" % (msg[2],)) # # # # if self.init_socket() == 1: # # self._message_queue # message = "SET " + cmd + " " + " ".join([str(arg) for arg in args]) # self.sock.send(bytes(message, "UTF-8")) # # print("set ", cmd) # # # def get(self, cmd): # ''' # Send a GET message to the device # ''' # if cmd not in self.get_msgs: # raise ValueError("Invalid message argument %s" % (cmd,)) # # self.init_socket() # message = "GET " + cmd # self.sock.send(bytes(message, "UTF-8")) # # print("get ", cmd) # # TODO: gérer le timeout # ret = self.sock.recv(1024).decode() # # print("return : ", ret) # return ret # # # def do(self, cmd, *args): # ''' # Send a DO message to the device # ''' # msg = [msg for msg in self.do_msgs if msg[0] == cmd] # if len(msg) == 0: # raise ValueError("Invalid message argument %s" % (cmd,)) # msg = msg[0] # if len(args) not in msg[1]: # raise ValueError("Bad number of arguments") # # if type(msg[2]) is str: # if msg[2] not in self.enums.keys(): # raise TypeError("Enum %s doesn't exist. Please check the grammar.json file." % (msg[2],)) # enum = self.enums[msg[2]] # for arg in args: # if arg not in enum: # raise TypeError("Bad value '%s' for enum '%s'" % (arg, msg[2])) # else: # for arg in args: # if type(arg) != msg[2]: # raise TypeError("Bad type of argument: expected %s" % (msg[2],)) # # self.init_socket() # message = "DO " + cmd + " " + " ".join([str(arg) for arg in args]) # self.sock.send(bytes(message, "UTF-8")) # # print("do ", cmd)