PyVantagePro-MarcoGos 0.3.24__tar.gz → 0.3.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/PKG-INFO +1 -2
  2. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/PyVantagePro_MarcoGos.egg-info/PKG-INFO +1 -2
  3. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/PyVantagePro_MarcoGos.egg-info/SOURCES.txt +1 -0
  4. pyvantagepro_marcogos-0.3.26/PyVantagePro_MarcoGos.egg-info/requires.txt +1 -0
  5. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyproject.toml +1 -2
  6. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/__init__.py +1 -1
  7. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/compat.py +8 -0
  8. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/device.py +1 -1
  9. pyvantagepro_marcogos-0.3.26/pyvantagepro/link.py +396 -0
  10. pyvantagepro_marcogos-0.3.24/PyVantagePro_MarcoGos.egg-info/requires.txt +0 -2
  11. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/AUTHORS.rst +0 -0
  12. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/LICENSE +0 -0
  13. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/PyVantagePro_MarcoGos.egg-info/dependency_links.txt +0 -0
  14. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/PyVantagePro_MarcoGos.egg-info/top_level.txt +0 -0
  15. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/README.rst +0 -0
  16. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/__main__.py +0 -0
  17. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/logger.py +0 -0
  18. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/parser.py +0 -0
  19. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/tests/__init__.py +0 -0
  20. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/tests/test_parser.py +0 -0
  21. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/tests/test_utils.py +0 -0
  22. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/pyvantagepro/utils.py +0 -0
  23. {pyvantagepro_marcogos-0.3.24 → pyvantagepro_marcogos-0.3.26}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyVantagePro_MarcoGos
3
- Version: 0.3.24
3
+ Version: 0.3.26
4
4
  Summary: Communication tools for the Davis VantagePro2 devices
5
5
  Author-email: Salem Harrache <salem.harrache@gmail.com>, Marco Gosselink <pypi@famgosselink.nl>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -696,7 +696,6 @@ Requires-Python: >=3.8
696
696
  Description-Content-Type: text/x-rst
697
697
  License-File: LICENSE
698
698
  License-File: AUTHORS.rst
699
- Requires-Dist: PyLink-MarcoGos>=0.3.6
700
699
  Requires-Dist: progressbar-latest
701
700
 
702
701
  PyVantagePro
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyVantagePro_MarcoGos
3
- Version: 0.3.24
3
+ Version: 0.3.26
4
4
  Summary: Communication tools for the Davis VantagePro2 devices
5
5
  Author-email: Salem Harrache <salem.harrache@gmail.com>, Marco Gosselink <pypi@famgosselink.nl>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -696,7 +696,6 @@ Requires-Python: >=3.8
696
696
  Description-Content-Type: text/x-rst
697
697
  License-File: LICENSE
698
698
  License-File: AUTHORS.rst
699
- Requires-Dist: PyLink-MarcoGos>=0.3.6
700
699
  Requires-Dist: progressbar-latest
701
700
 
702
701
  PyVantagePro
@@ -11,6 +11,7 @@ pyvantagepro/__init__.py
11
11
  pyvantagepro/__main__.py
12
12
  pyvantagepro/compat.py
13
13
  pyvantagepro/device.py
14
+ pyvantagepro/link.py
14
15
  pyvantagepro/logger.py
15
16
  pyvantagepro/parser.py
16
17
  pyvantagepro/utils.py
@@ -4,13 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyVantagePro_MarcoGos"
7
- version = "0.3.24"
7
+ version = "0.3.26"
8
8
  authors = [
9
9
  { name="Salem Harrache", email="salem.harrache@gmail.com" },
10
10
  { name="Marco Gosselink", email="pypi@famgosselink.nl" },
11
11
  ]
12
12
  dependencies = [
13
- "PyLink-MarcoGos>=0.3.6",
14
13
  "progressbar-latest"
15
14
  ]
16
15
  description = "Communication tools for the Davis VantagePro2 devices"
@@ -13,5 +13,5 @@
13
13
  from .logger import LOGGER, active_logger
14
14
  from .device import VantagePro2
15
15
 
16
- VERSION = '0.3.24'
16
+ VERSION = '0.3.26'
17
17
  __version__ = VERSION
@@ -90,3 +90,11 @@ elif is_py3:
90
90
  bytes = bytes
91
91
  stdout = sys.stdout.buffer
92
92
  xrange = range
93
+
94
+
95
+ def format_string(s, encoding='utf-8'):
96
+ if isinstance(s, str):
97
+ return s.encode(encoding)
98
+ if isinstance(s, basestring):
99
+ return s
100
+ return str(s)
@@ -12,7 +12,7 @@
12
12
  from __future__ import division, unicode_literals
13
13
  import struct
14
14
  from datetime import datetime, timedelta
15
- from pylink import link_from_url, SerialLink
15
+ from .link import link_from_url, SerialLink
16
16
 
17
17
  from .logger import LOGGER
18
18
  from .utils import (cached_property, retry, bytes_to_hex,
@@ -0,0 +1,396 @@
1
+ # -*- coding: utf-8 -*-
2
+ '''
3
+ pylink.link
4
+ -----------
5
+
6
+ :copyright: Copyright 2012 Salem Harrache and contributors, see AUTHORS.
7
+ :license: BSD, see LICENSE for details.
8
+
9
+ '''
10
+ from __future__ import unicode_literals
11
+ import socket
12
+ import time
13
+ import serial
14
+ import binascii
15
+
16
+ from .logger import LOGGER
17
+ from .compat import bytes, str, format_string
18
+
19
+
20
+ class Link(object):
21
+ '''Abstract base class for all links.'''
22
+ MAX_STRING_SIZE = 4048
23
+
24
+ def open(self):
25
+ '''Open the link.'''
26
+ pass
27
+
28
+ def close(self):
29
+ '''Close the link.'''
30
+ pass
31
+
32
+ def byte_to_hex(self, bytes):
33
+ '''Convert a byte string to it's hex string representation.'''
34
+ hexstr = str(binascii.hexlify(bytes), "utf-8")
35
+ data = []
36
+ for i in range(0, len(hexstr), 2):
37
+ data.append("%s" % hexstr[i:i + 2].upper())
38
+ return ' '.join(data)
39
+
40
+ def log(self, message, data):
41
+ if not self.is_text(data):
42
+ LOGGER.info("%s : <%s>" % (message, self.byte_to_hex(data)))
43
+ else:
44
+ LOGGER.info("%s : <%s>" % (message, repr(data)))
45
+
46
+ def is_text(self, data):
47
+ return isinstance(data, str)
48
+
49
+ def is_bytes(self, data):
50
+ return isinstance(data, bytes)
51
+
52
+ def __del__(self):
53
+ '''Close link when object is deleted.'''
54
+ self.close()
55
+
56
+ def __unicode__(self):
57
+ name = self.__class__.__name__
58
+ return "<%s %s>" % (name, self.url)
59
+
60
+ def __str__(self):
61
+ return str(self.__unicode__())
62
+
63
+ def __repr__(self):
64
+ return str(self.__unicode__())
65
+
66
+
67
+ class TCPLink(Link):
68
+ '''TCPLink class allows TCP/IP protocol communication with File-like
69
+ API.'''
70
+ def __init__(self, host, port, timeout=1):
71
+ self.timeout = timeout
72
+ self.host = socket.gethostbyname(host)
73
+ self.port = port
74
+ self._socket = None
75
+
76
+ @property
77
+ def address(self):
78
+ '''Return a tuple of (`host`, `port`).'''
79
+ return (self.host, self.port)
80
+
81
+ @property
82
+ def url(self):
83
+ '''Make a connection url from `host` and `port`.'''
84
+ return 'tcp:%s:%d' % self.address
85
+
86
+ def open(self):
87
+ '''Open the socket.'''
88
+ if self._socket is None:
89
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
90
+ self._socket.connect(self.address)
91
+ self.socket.setblocking(0)
92
+ LOGGER.info('new %s was initialized' % self)
93
+
94
+ def settimeout(self, timeout):
95
+ self.timeout = timeout
96
+
97
+ def close(self):
98
+ '''Close the socket.'''
99
+ if self._socket is not None:
100
+ LOGGER.info('Close connection %s' % self)
101
+ self.empty_socket()
102
+ self._socket.close()
103
+ LOGGER.info('Connection %s was closed' % self)
104
+ self._socket = None
105
+
106
+ @property
107
+ def socket(self):
108
+ '''Return an opened socket object.'''
109
+ self.open()
110
+ return self._socket
111
+
112
+ def write(self, data):
113
+ '''Write all `data` to socket.'''
114
+ if self.is_text(data):
115
+ self.send_to_socket(bytes(data.encode('utf-8')))
116
+ else:
117
+ self.send_to_socket(data)
118
+ self.log("Write", data)
119
+
120
+ def read(self, size=None, timeout=None, binary=False):
121
+ '''Read data from socket. The maximum amount of data to be received at
122
+ once is specified by `size`. If `is_byte` is True, the data will be
123
+ convert to hexadecimal array.'''
124
+ size = size or self.MAX_STRING_SIZE
125
+ timeout = (timeout or 1) * (self.timeout or 1)
126
+ data = self.recv_timeout(size, timeout, binary)
127
+ if len(data) != 0 :
128
+ self.log("Read", data)
129
+ return data
130
+
131
+ def recv_timeout(self, size, timeout, binary=False):
132
+ '''Uses a non-blocking sockets in order to continue trying to get data
133
+ as long as the client manages to even send a single byte.
134
+ This is useful for moving data which you know very little about
135
+ (like encrypted data), so cannot check for completion in a sane way.
136
+ '''
137
+ begin = time.time()
138
+ data = bytearray()
139
+ total_data = []
140
+ while True:
141
+ #if you got some data, then break after wait sec
142
+ if total_data and time.time() - begin > timeout:
143
+ break
144
+ #if you got no data at all, wait a little longer
145
+ elif time.time() - begin > (timeout * 2):
146
+ break
147
+ try:
148
+ data = self.recv_from_socket(size)
149
+ if data:
150
+ total_data.append(data)
151
+ size = size - len(data)
152
+ if size == 0:
153
+ break
154
+ begin = time.time()
155
+ else:
156
+ time.sleep(0.1)
157
+ except:
158
+ pass
159
+ # Try to convert into str
160
+ if not binary:
161
+ try:
162
+ return str(b"".join(total_data), encoding='utf8')
163
+ except:
164
+ pass
165
+ return b"".join(total_data)
166
+
167
+ def send_to_socket(self, data):
168
+ '''Send data to TCP socket.'''
169
+ self.socket.sendall(data)
170
+
171
+ def recv_from_socket(self, size):
172
+ '''Read data from TCP socket.'''
173
+ return self.socket.recv(size)
174
+
175
+ def empty_socket(self):
176
+ '''Read data from TCP socket.'''
177
+ # empty buffer reception
178
+ self.recv_timeout(self.MAX_STRING_SIZE, timeout=0.1)
179
+
180
+
181
+ class UDPLink(TCPLink):
182
+ '''TCPLink class allows UDP/IP protocol communication with File-like
183
+ API.'''
184
+
185
+ @property
186
+ def url(self):
187
+ '''Make a connection url from `host` and `port`.'''
188
+ return 'udp:%s:%d' % self.address
189
+
190
+ def open(self):
191
+ '''Open the socket.'''
192
+ if self._socket is None:
193
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
194
+ LOGGER.info('new %s was initialized' % self)
195
+
196
+ def send_to_socket(self, data):
197
+ '''Send data to TCP socket.'''
198
+ self.socket.sendto(data, self.address)
199
+
200
+ def recv_from_socket(self, size):
201
+ '''Read data from TCP socket.'''
202
+ data, address = self.socket.recvfrom(size)
203
+ if address == self.address:
204
+ return data
205
+
206
+
207
+ class SerialLink(Link):
208
+ '''SerialLink class allows serial communication with File-like API.
209
+ Possible values for the parameter port:
210
+ - Number: number of device, numbering starts at zero.
211
+ - Device name: depending on operating system.
212
+ e.g. /dev/ttyUSB0 on GNU/Linux or COM3 on Windows.'''
213
+ def __init__(self, port, baudrate=19200, bytesize=8, parity='N',
214
+ stopbits=1, timeout=1):
215
+ self.port = port
216
+ self.timeout = timeout
217
+ self.baudrate = baudrate
218
+ self.bytesize = bytesize
219
+ self.parity = parity
220
+ self.stopbits = stopbits
221
+ self._serial = None
222
+
223
+ @property
224
+ def url(self):
225
+ '''Make a connection url.'''
226
+ return 'serial:%s:%d:%d%s%d' % (self.port, self.baudrate,
227
+ self.bytesize, self.parity,
228
+ self.stopbits)
229
+
230
+ def open(self):
231
+ '''Open the serial connection.'''
232
+ if self._serial is None:
233
+ self._serial = serial.Serial(self.port, self.baudrate,
234
+ timeout=self.timeout,
235
+ bytesize=self.bytesize,
236
+ parity=self.parity,
237
+ stopbits=self.stopbits)
238
+ self._serial.reset_output_buffer()
239
+ LOGGER.info('new %s was initialized' % self)
240
+
241
+ def settimeout(self, timeout):
242
+ self.timeout = timeout
243
+ self.serial.timeout = self.timeout
244
+
245
+ def close(self):
246
+ '''Close the serial connection.'''
247
+ if self._serial is not None:
248
+ if self._serial.isOpen():
249
+ self._serial.close()
250
+ LOGGER.info('Connection %s was closed' % self)
251
+ self._serial = None
252
+
253
+ @property
254
+ def serial(self):
255
+ '''Return an opened serial object.'''
256
+ self.open()
257
+ return self._serial
258
+
259
+ def write(self, data):
260
+ '''Write all `data` to the serial connection.'''
261
+ data = format_string(data)
262
+ self.serial.write(data)
263
+ try:
264
+ self.log("Write", str(data, encoding='utf8'))
265
+ except:
266
+ self.log("Write", data)
267
+
268
+ def read(self, size=None, timeout=None, binary=False):
269
+ '''Read data from the serial connection. The maximum amount of data
270
+ to be received at once is specified by `size`. If `is_byte` is True,
271
+ the data will be convert to byte array.'''
272
+ size = size or self.MAX_STRING_SIZE
273
+ timeout = (timeout or 1) * (self.timeout or 1)
274
+ self.serial.timeout = timeout
275
+ data = self.serial.read(size)
276
+ if not binary:
277
+ try:
278
+ data = str(data, encoding='utf8')
279
+ except:
280
+ pass
281
+ if len(data) != 0 :
282
+ self.log("Read", data)
283
+ self.serial.timeout = self.timeout
284
+ return data
285
+
286
+
287
+ class GSMLink(Link):
288
+ '''GSM link class.'''
289
+
290
+ def __init__(self, phone, link,timeout=1): #EGC added timeout (the aplication throws an error if the object doesn't have an attribute when call packbus read method)
291
+ self.link = link
292
+ self.phone = phone
293
+ self.is_open = False
294
+ self.timeout = timeout #EGC set timeout
295
+
296
+ def _call(self):
297
+ LOGGER.info("GSM : Call %s" % self.phone)
298
+ self.link.write("ATD%s\r\n" % self.phone)
299
+ for i in range(100): #EGC Change While to For (While never ends, in case of error program won't stop, infinite loop)
300
+ response = self.link.read(22)
301
+ if ("BUSY" in response or "NO CARRIER" in response
302
+ or "ERROR" in response):
303
+ LOGGER.error("GSM : <%s>" % repr(response))
304
+ return False
305
+ if "CONNECT" in response:
306
+ self.log("GSM", "Client is ready (%s)" % response)
307
+ self.link.read()
308
+ return True
309
+ self.log("GSM", "call in progress")
310
+ time.sleep(1)
311
+ return False
312
+
313
+ def _hangup(self):
314
+ #EGC my modem (Citerion (formerly SIEMENS) gprs mc35i) send two additional weird characters before the OK response, something that looks like ᤙᤙOK and it makes the function never ends
315
+ #So I have had to delete the response checking and also the is_open checking because sometimes the modem wasn't able to hang up despite aparently the conexion was closed is_open=false
316
+ self.link.write("+++")
317
+ self.link.read(6)
318
+ self.link.write("ATH\r\n")
319
+ resp=self.link.read(6)
320
+ LOGGER.info("GSM : Hang-up")
321
+
322
+ def open(self):
323
+ '''Open the gsm connection.'''
324
+ if not self.is_open:
325
+ self.link.open()
326
+ self.is_open = self._call()
327
+ if not self.is_open:
328
+ self.link.close() #EGC Close Serial port because sometimes if a error occurrs let the serial port open and busy and it makes impossible restart a new comunication.
329
+ raise ValueError('no GSM device')
330
+
331
+ def close(self):
332
+ '''Close the gsm connection.'''
333
+ if self.is_open:
334
+ self._hangup()
335
+ self.link.close()
336
+ self.is_open = False
337
+ else:
338
+ self.link.close() #EGC to ensure te correct close of the serial port to avoid futures problems when someone wants to restart a serial com
339
+
340
+ @property
341
+ def url(self):
342
+ '''Connection url.'''
343
+ return 'gsm:%s:%s' % (self.phone, str(self.link))
344
+
345
+ def settimeout(self, timeout):
346
+ self.timeout=timeout #EGC Set GSM timeout
347
+ self.link.settimeout(timeout) #EGC Also Set the serial port timeout
348
+
349
+ def write(self, data):
350
+ '''Write all `data` to the gsm connection.'''
351
+ self.link.write(data)
352
+
353
+ def read(self, size=None, timeout=None):
354
+ '''Read data from the serial connection.'''
355
+ return self.link.read(size, timeout)
356
+
357
+ def link_from_url(url):
358
+ '''Get link from url'''
359
+ link = None
360
+ bad_url = False
361
+ args = url.split(':')
362
+ try:
363
+ if len(args) > 1:
364
+ mode = args[0].lower()
365
+ if mode == "gsm":
366
+ phone = args[1]
367
+ parent_link = link_from_url(':'.join(args[2:]))
368
+ link = GSMLink(phone, parent_link)
369
+ if mode == "tcp" or mode == "udp":
370
+ host = args[1]
371
+ port = int(args[2])
372
+ if mode == "tcp":
373
+ link = TCPLink(host, port)
374
+ else:
375
+ link = UDPLink(host, port)
376
+ elif mode == "serial":
377
+ if len(args) == 2:
378
+ port = args[1]
379
+ link = SerialLink(port)
380
+ elif len(args) == 3:
381
+ port = args[1]
382
+ baudrate = int(args[2])
383
+ link = SerialLink(port, baudrate)
384
+ elif len(args) == 4:
385
+ port = args[1]
386
+ baudrate = int(args[2])
387
+ bytesize = int(args[3][0])
388
+ parity = args[3][1]
389
+ stopbits = int(args[3][2])
390
+ link = SerialLink(port, baudrate, bytesize, parity,
391
+ stopbits)
392
+ except IndexError:
393
+ bad_url = True
394
+ if link is None or bad_url:
395
+ raise ValueError('Bad url link sepecified')
396
+ return link
@@ -1,2 +0,0 @@
1
- PyLink-MarcoGos>=0.3.6
2
- progressbar-latest