protobin 0.0.38__tar.gz → 0.0.40__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.
- {protobin-0.0.38 → protobin-0.0.40}/PKG-INFO +1 -1
- {protobin-0.0.38 → protobin-0.0.40}/protobin/errors.py +1 -1
- {protobin-0.0.38 → protobin-0.0.40}/protobin/fields.py +8 -5
- {protobin-0.0.38 → protobin-0.0.40}/pyproject.toml +1 -1
- {protobin-0.0.38 → protobin-0.0.40}/tests/codec8.json +1 -1
- {protobin-0.0.38 → protobin-0.0.40}/tests/demo.json +10 -0
- {protobin-0.0.38 → protobin-0.0.40}/tests/teltonika.json +9 -1
- {protobin-0.0.38 → protobin-0.0.40}/tests/tests.py +52 -2
- {protobin-0.0.38 → protobin-0.0.40}/.gitignore +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/LICENSE.txt +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/README.md +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/protobin/__init__.py +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/protobin/interfaces.py +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/protobin/protocol.py +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/protobin/singleton.py +0 -0
- {protobin-0.0.38 → protobin-0.0.40}/tests/demo.yaml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: protobin
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.40
|
|
4
4
|
Summary: Python library for encode and decode data in protobin format
|
|
5
5
|
Project-URL: Homepage, https://github.com/drmelectronic/protobin-python
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/drmelectronic/protobin-python/issues
|
|
@@ -3,7 +3,7 @@ import datetime
|
|
|
3
3
|
import math
|
|
4
4
|
from typing import Union, List
|
|
5
5
|
|
|
6
|
-
from protobin.errors import
|
|
6
|
+
from protobin.errors import DecodeError, FormatError
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
# removed for python 3.8
|
|
@@ -50,7 +50,7 @@ class FieldBase:
|
|
|
50
50
|
def ensure_length(self, binary):
|
|
51
51
|
if self.bytes:
|
|
52
52
|
if len(binary) < self.bytes:
|
|
53
|
-
raise
|
|
53
|
+
raise DecodeError(f'Binary has not enough data for {self}')
|
|
54
54
|
|
|
55
55
|
def from_binary(self, binary):
|
|
56
56
|
raise NotImplementedError()
|
|
@@ -398,7 +398,10 @@ class StringField(FieldBase):
|
|
|
398
398
|
return f'StringField<key: {self.key}, bytes: {self.bytes}>'
|
|
399
399
|
|
|
400
400
|
def from_binary(self, binary):
|
|
401
|
-
|
|
401
|
+
try:
|
|
402
|
+
return binary.decode('utf')
|
|
403
|
+
except UnicodeEncodeError:
|
|
404
|
+
raise DecodeError(f"Can't decode string: {binary}")
|
|
402
405
|
|
|
403
406
|
def split(self, binary):
|
|
404
407
|
if self.bytes:
|
|
@@ -460,7 +463,7 @@ class TimestampField(FieldBase):
|
|
|
460
463
|
|
|
461
464
|
def __init__(self, k, js):
|
|
462
465
|
super().__init__(k, js)
|
|
463
|
-
self.bytes =
|
|
466
|
+
self.bytes = js.get('bytes', 6)
|
|
464
467
|
self.decimals = js.get('decimals', 6)
|
|
465
468
|
|
|
466
469
|
def __repr__(self):
|
|
@@ -472,7 +475,7 @@ class TimestampField(FieldBase):
|
|
|
472
475
|
if val is None:
|
|
473
476
|
return bytes([0] * 8)
|
|
474
477
|
timestamp = val.timestamp() * (10 ** self.decimals)
|
|
475
|
-
return int(timestamp).to_bytes(
|
|
478
|
+
return int(timestamp).to_bytes(self.bytes, 'big', signed=False)
|
|
476
479
|
|
|
477
480
|
def from_binary(self, binary):
|
|
478
481
|
d = int.from_bytes(binary, 'big')
|
|
@@ -64,6 +64,16 @@
|
|
|
64
64
|
"id": {"type": "string"},
|
|
65
65
|
"value": {"type": "string"}
|
|
66
66
|
}
|
|
67
|
+
},
|
|
68
|
+
"timestamp": {
|
|
69
|
+
"header": "#T",
|
|
70
|
+
"server": {
|
|
71
|
+
"faltantes": {"bytes": 4, "type": "unsigned"},
|
|
72
|
+
"tabla": {"bytes": 1, "type": "char"}
|
|
73
|
+
},
|
|
74
|
+
"client": {
|
|
75
|
+
"timestamp":{"bytes": 6, "decimals": 3, "type": "timestamp"}
|
|
76
|
+
}
|
|
67
77
|
}
|
|
68
78
|
}
|
|
69
79
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"crc_size": 2,
|
|
15
15
|
"header": "P",
|
|
16
16
|
"fields": {
|
|
17
|
-
"
|
|
17
|
+
"padron": {"type": "string"},
|
|
18
18
|
"company": {"type": "string"},
|
|
19
19
|
"route": {"type": "string"}
|
|
20
20
|
}
|
|
@@ -139,6 +139,14 @@
|
|
|
139
139
|
"datero_dif_5": {"type": "unsigned", "bytes": 1}
|
|
140
140
|
}
|
|
141
141
|
},
|
|
142
|
+
"message": {
|
|
143
|
+
"crc": false,
|
|
144
|
+
"crc_size": 2,
|
|
145
|
+
"header": "M",
|
|
146
|
+
"fields": {
|
|
147
|
+
"text": {"type": "string"}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
142
150
|
"command": {
|
|
143
151
|
"codec": 12,
|
|
144
152
|
"fields": {
|
|
@@ -134,6 +134,10 @@ class BasicTest(unittest.TestCase):
|
|
|
134
134
|
"header": "TS",
|
|
135
135
|
"fields": {'test': {'bytes': 8, 'type': 'timestamp'}}
|
|
136
136
|
},
|
|
137
|
+
'timestamp6': {
|
|
138
|
+
"header": "T6",
|
|
139
|
+
"fields": {'test': {'bytes': 6, "decimals": 3, 'type': 'timestamp'}}
|
|
140
|
+
},
|
|
137
141
|
'unsigned': {
|
|
138
142
|
"header": "u",
|
|
139
143
|
"fields": {'test': {'bytes': 3, 'type': 'unsigned'}}
|
|
@@ -290,6 +294,31 @@ class BasicTest(unittest.TestCase):
|
|
|
290
294
|
with self.assertRaises(ValueError) as er:
|
|
291
295
|
self.protocol.encode(data, 'unsigned')
|
|
292
296
|
|
|
297
|
+
protocol = Protocol(js={'formats': {
|
|
298
|
+
'unsigned': {
|
|
299
|
+
"header": "u",
|
|
300
|
+
"fields": {
|
|
301
|
+
"geofence": {"bytes": 2, "type": "unsigned"},
|
|
302
|
+
"orden": {"bytes": 1, "type": "unsigned"},
|
|
303
|
+
"delta": {"bytes": 1, "type": "unsigned"},
|
|
304
|
+
"origin": {"bytes": 2, "type": "unsigned"},
|
|
305
|
+
"id": {"bytes": 0, "type": "string"}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}})
|
|
309
|
+
data = {
|
|
310
|
+
"id": "11",
|
|
311
|
+
"orden": 0,
|
|
312
|
+
"origin": 57,
|
|
313
|
+
"delta": 5,
|
|
314
|
+
"geofence": 200
|
|
315
|
+
}
|
|
316
|
+
binary = protocol.encode(data, 'unsigned')
|
|
317
|
+
print(binary)
|
|
318
|
+
h, recv = protocol.decode(binary)
|
|
319
|
+
print(recv)
|
|
320
|
+
self.assertEqual(data, recv)
|
|
321
|
+
|
|
293
322
|
def test_id(self):
|
|
294
323
|
data = {'test': 254}
|
|
295
324
|
binary = self.protocol.encode(data, 'id')
|
|
@@ -318,6 +347,13 @@ class BasicTest(unittest.TestCase):
|
|
|
318
347
|
h, recv = self.protocol.decode(binary)
|
|
319
348
|
self.assertEqual(data, recv)
|
|
320
349
|
|
|
350
|
+
def test_timestamp6(self):
|
|
351
|
+
data = {'test': datetime.datetime(2025, 1, 24, 9, 18, 24, 896000)}
|
|
352
|
+
binary = self.protocol.encode(data, 'timestamp6')
|
|
353
|
+
print(binary)
|
|
354
|
+
h, recv = self.protocol.decode(binary)
|
|
355
|
+
self.assertEqual(data, recv)
|
|
356
|
+
|
|
321
357
|
def test_timestamp_null(self):
|
|
322
358
|
data = {'test': None}
|
|
323
359
|
binary = self.protocol.encode(data, 'timestamp')
|
|
@@ -635,7 +671,7 @@ report:
|
|
|
635
671
|
data = {'status': 'E', 'direction': 'A', 'next_next_control': '', 'next_next_time': ' ', 'next_control': '', 'next_time': ' ', 'previous_control': '', 'delay': 0, 'front_control': '', 'back_control': '', 'back_back_control': '', 'datero_bus_-1': 0, 'datero_dif_-1': 0, 'datero_bus_0': 0, 'datero_dif_0': 0, 'datero_bus_1': 0, 'datero_dif_1': 0, 'datero_bus_2': 0, 'datero_dif_2': 0, 'datero_bus_3': 256, 'datero_dif_3': 0, 'datero_bus_4': 0, 'datero_dif_4': 0, 'datero_bus_5': 0, 'datero_dif_5': 0}
|
|
636
672
|
client = Protocol(file='codec8.json')
|
|
637
673
|
binary = client.encode(data, 'status3')
|
|
638
|
-
self.assertEqual(b's=EA\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\
|
|
674
|
+
self.assertEqual(b's=EA\x00 \x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\xb6\xd6', binary)
|
|
639
675
|
header, recv = client.decode(binary)
|
|
640
676
|
self.assertEqual(data, recv)
|
|
641
677
|
|
|
@@ -723,7 +759,21 @@ report:
|
|
|
723
759
|
|
|
724
760
|
def test_teltonika_login(self):
|
|
725
761
|
client = Protocol(file='codec8.json', server=None)
|
|
726
|
-
data = {'
|
|
762
|
+
data = {'padron': '110', 'company': 'roma', 'route': 'IO37'}
|
|
727
763
|
binary = client.encode(data, 'login_status')
|
|
728
764
|
print(binary)
|
|
729
765
|
self.assertEqual(b'P=\x03110\x04roma\x04IO37\x19\x8f', binary)
|
|
766
|
+
|
|
767
|
+
def test_teltonika_login_urbanito(self):
|
|
768
|
+
client = Protocol(file='codec8.json', server=None)
|
|
769
|
+
data = {'company': 'urbanito', 'route': '9802'}
|
|
770
|
+
binary = client.encode(data, 'login_status')
|
|
771
|
+
print(binary)
|
|
772
|
+
self.assertEqual(b'P=\x00\x08urbanito\x049802+\xbf', binary)
|
|
773
|
+
|
|
774
|
+
def test_message_teltonika(self):
|
|
775
|
+
data = {'text': 'prueba de mensaje'}
|
|
776
|
+
client = Protocol(file='teltonika.json', server=None)
|
|
777
|
+
binary = client.encode(data, 'message')
|
|
778
|
+
print(binary)
|
|
779
|
+
self.assertEqual(binary, b'M=\x11prueba de mensaje48')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|