Blame view

src/devices/Device.py 6.52 KB
e8e6f017   Jeremy   Reworked devices ...
1
from django.conf import settings
ac26ad2b   haribo   Date: 22/07/2016
2
import socket
bb0fbab1   haribo   Fini de mettre la...
3
import configparser
e8e6f017   Jeremy   Reworked devices ...
4
5
import abc
import select
bca9a283   Jeremy   Reworked the sche...
6
import utils.Logger as L
d2dde3d0   Quentin Durand   Adding the abilit...
7
8
import time
import os
bb0fbab1   haribo   Fini de mettre la...
9

0b83e9b3   Quentin Durand   Activate Device a...
10
DEBUG_FILE = True
257abe9b   Jeremy   Added comments
11

e8e6f017   Jeremy   Reworked devices ...
12
'''
257abe9b   Jeremy   Added comments
13
    Generic object for the communication with all the devices
e8e6f017   Jeremy   Reworked devices ...
14
'''
9774228b   haribo   Date: 22/06/2016
15

65149de7   Jeremy   Update
16

ddf59dd4   haribo   Remaniement :
17
class DeviceController():
e8e6f017   Jeremy   Reworked devices ...
18
19
20
21
22
23
24
25
26
    __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
9b5bad52   haribo   Commented all the...
27

bb0fbab1   haribo   Fini de mettre la...
28
    def __init__(self, device_name):
e8e6f017   Jeremy   Reworked devices ...
29
30
31
32
33
        self.name = device_name
        self.getConfig()
        self.getConnection(device_name)
        self.connect()

d2dde3d0   Quentin Durand   Adding the abilit...
34

e8e6f017   Jeremy   Reworked devices ...
35
36
37
38
39
40
41
42
43
44
45
46
    @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

ce470283   Jeremy   Plc simulator fin...
47
48
49
50
    @abc.abstractmethod
    def getStatus(self):
        return

d2dde3d0   Quentin Durand   Adding the abilit...
51
    def sendMessage(self, message: str):
e8e6f017   Jeremy   Reworked devices ...
52
        if (not self.isConnected()):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
53
54
55
            # (EP) NON, return 0 !!!
            #return (1)
            return False
c7583f6e   Etienne Pallier   Cleaner isolation...
56
        # (EP) Here we are still not sure that we are connected to the device (it may be down and we do not know)
e8e6f017   Jeremy   Reworked devices ...
57
        try:
f7dd3df1   Jeremy   Update simulators...
58
            readable, writable, exceptional = select.select([], [self.sock], [self.sock], 0)
e8e6f017   Jeremy   Reworked devices ...
59
60
61
            if not (writable or exceptional):
                raise (Exception("Socket not writable"))
            self.sock.send(bytes(message, "UTF-8"))
605b65e5   Jeremy   Update simulators
62
        except Exception as e:
e8e6f017   Jeremy   Reworked devices ...
63
            if (settings.DEBUG):
c7583f6e   Etienne Pallier   Cleaner isolation...
64
65
                print("(ENV) Could not send message (on socket) to "+self.name+" : " + message + " -> " + str(e))
                #EP TODO: bugfix: ce log ne fait rien du tout !!
605b65e5   Jeremy   Update simulators
66
                self.log(self.name, "Could not send message on socket : " + message + " -> " + str(e))
d2dde3d0   Quentin Durand   Adding the abilit...
67
68
69
70

                ret = self.reconnect()
                while not ret:
                    ret = self.reconnect()
15e15006   Etienne Pallier   Nouvelles modifs ...
71
72
73
74
75
76
            # (EP) NON, 1 = true !!!
            #return (1)
            return False
        # (EP) NON, 0 = false !!!
        #return (0)
        return True
e8e6f017   Jeremy   Reworked devices ...
77
78

    def isError(self, message: str):
15e15006   Etienne Pallier   Nouvelles modifs ...
79
80
81
        #EP
        #if (message == "FAILED" or message == "NOT_SET" or message == "DISCONNECTED"):
        if (message == "FAILED" or message.startswith("NOT_SET") or message == "DISCONNECTED"):
e8e6f017   Jeremy   Reworked devices ...
82
83
84
            return (True)
        return (False)

c7583f6e   Etienne Pallier   Cleaner isolation...
85
    # MIND: Does not mean "is connected now" but "WAS connected once"
e8e6f017   Jeremy   Reworked devices ...
86
87
    def isConnected(self):
        if (not self.sock or not self.connected):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
88
89
            # (EP) NON, c'est totalement illisible !!! on n'est plus en 1970
            #if (self.connect()): return (False)
c7583f6e   Etienne Pallier   Cleaner isolation...
90
            print("something is wrong with this device, now trying to connect again...")
15e15006   Etienne Pallier   Nouvelles modifs ...
91
            if not self.connect(): return False
c7583f6e   Etienne Pallier   Cleaner isolation...
92
            #self.connected = True
15e15006   Etienne Pallier   Nouvelles modifs ...
93
        return True
e8e6f017   Jeremy   Reworked devices ...
94
95
96

    def readBytes(self, size) -> str:
        if (not self.isConnected()):
15e15006   Etienne Pallier   Nouvelles modifs ...
97
            return ("NOT_SET2")
65149de7   Jeremy   Update
98
        try:
f7dd3df1   Jeremy   Update simulators...
99
            readable, writable, exceptional = select.select([self.sock], [], [self.sock], 0)
e8e6f017   Jeremy   Reworked devices ...
100
101
102
103
104
105
106
107
            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")
605b65e5   Jeremy   Update simulators
108
        except Exception as e:
e8e6f017   Jeremy   Reworked devices ...
109
            if (settings.DEBUG):
605b65e5   Jeremy   Update simulators
110
                self.log(self.name, "Socket not readable : " + str(e))
e8e6f017   Jeremy   Reworked devices ...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
            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):
c53a13e0   Jeremy   Updating a lot of...
142
143
        if DEBUG_FILE and settings.DEBUG:
            self.logger.info("From device : " + device_name + " -> " + message)
e8e6f017   Jeremy   Reworked devices ...
144
145
146
147
148
        return (0)

    def connect(self):
        if (self.ip is None or self.port is None):
            self.log(self.name, "Ip or Port not initialized")
1a2dc19f   Etienne Pallier   nombreux bugfixes...
149
150
            # (EP) It's a serious bug, so raise exception !!!
            #return (1)
c7583f6e   Etienne Pallier   Cleaner isolation...
151
            raise (Exception(self.name +"Controller has no ip or port to connect to"))
e8e6f017   Jeremy   Reworked devices ...
152
        try:
15e15006   Etienne Pallier   Nouvelles modifs ...
153
            # Create a TCP/IP socket
e8e6f017   Jeremy   Reworked devices ...
154
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
15e15006   Etienne Pallier   Nouvelles modifs ...
155
            # Connect the socket to the port on the server
d2dde3d0   Quentin Durand   Adding the abilit...
156
157
158
159
            r = self.sock.connect_ex((self.ip, self.port))
            if (r != 0):
                raise Exception("sock.connect_ex failed : " + os.strerror(r))

15e15006   Etienne Pallier   Nouvelles modifs ...
160
161
162
163
164
165
166
167
168
169
            '''
            Socket set to non blocking (by default, it is blocking)
            In non-blocking mode, if a recv() call doesn’t find any data, 
            or if a send() call can’t immediately dispose of the data, 
            an error exception is raised. 
            (In blocking mode, the calls block until they can proceed) 
            s.setblocking(0) is equivalent to s.settimeout(0.0); 
            s.setblocking(1) is equivalent to s.settimeout(None).
            '''
            self.sock.setblocking(0)
e8e6f017   Jeremy   Reworked devices ...
170
        except Exception as e:
d2dde3d0   Quentin Durand   Adding the abilit...
171
            print(e)
c7583f6e   Etienne Pallier   Cleaner isolation...
172
            print("FAILED TO CONNECT TO DEVICE {}".format(self.name))
e8e6f017   Jeremy   Reworked devices ...
173
            if (settings.DEBUG):
15e15006   Etienne Pallier   Nouvelles modifs ...
174
                #TODO: Bugfix: Ce log ne fait rien !
605b65e5   Jeremy   Update simulators
175
                self.log(self.name, "Failed to connect to " + str(self.ip) + ":" + str(self.port) + " -> " + str(e))
1a2dc19f   Etienne Pallier   nombreux bugfixes...
176
177
178
            # (EP) return TRUE??? (for python, 1=true !!!)
            #return (1)
            return False
e8e6f017   Jeremy   Reworked devices ...
179
        self.connected = True
1a2dc19f   Etienne Pallier   nombreux bugfixes...
180
181
        # (EP) return FALSE ??? (for python, 0=false !!!)
        #return (0)
d2dde3d0   Quentin Durand   Adding the abilit...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
        return True

    def reconnect(self):

        self.getConfig()
        self.getConnection(self.name)
        try:
            print("Trying to reconnect to " + str(self.name))
            self.connect()
            return True
        except Exception as e:
            print(str(e))
            time.sleep(1)
            return False