protobin 0.0.6__tar.gz → 0.0.8__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.6 → protobin-0.0.8}/PKG-INFO +2 -1
- {protobin-0.0.6 → protobin-0.0.8}/protobin/fields.py +71 -47
- protobin-0.0.8/protobin/interfaces.py +0 -0
- protobin-0.0.8/protobin/protocol.py +76 -0
- {protobin-0.0.6 → protobin-0.0.8}/pyproject.toml +4 -1
- protobin-0.0.8/tests/demo.json +43 -0
- {protobin-0.0.6 → protobin-0.0.8}/tests/demo.yaml +51 -49
- {protobin-0.0.6 → protobin-0.0.8}/tests/tests.py +150 -101
- protobin-0.0.6/protobin/protocol.py +0 -62
- protobin-0.0.6/tests/demo.json +0 -291
- {protobin-0.0.6 → protobin-0.0.8}/.gitignore +0 -0
- {protobin-0.0.6 → protobin-0.0.8}/LICENSE.txt +0 -0
- {protobin-0.0.6 → protobin-0.0.8}/README.md +0 -0
- {protobin-0.0.6 → protobin-0.0.8}/protobin/__init__.py +0 -0
- {protobin-0.0.6 → protobin-0.0.8}/protobin/errors.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: protobin
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
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
|
|
@@ -33,6 +33,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
33
33
|
Classifier: Operating System :: OS Independent
|
|
34
34
|
Classifier: Programming Language :: Python :: 3
|
|
35
35
|
Requires-Python: >=3.9
|
|
36
|
+
Requires-Dist: pyyaml~=6.0
|
|
36
37
|
Description-Content-Type: text/markdown
|
|
37
38
|
|
|
38
39
|
# protobin
|
|
@@ -13,6 +13,7 @@ class FieldEnum(enum.StrEnum):
|
|
|
13
13
|
CHAR = 'char'
|
|
14
14
|
DATE = 'date'
|
|
15
15
|
DATETIME = 'datetime'
|
|
16
|
+
ID = 'id'
|
|
16
17
|
FLAGS = 'flags'
|
|
17
18
|
FLOAT = 'float'
|
|
18
19
|
SIGNED = 'signed'
|
|
@@ -27,9 +28,9 @@ class FieldBase:
|
|
|
27
28
|
key: Union[str, List[str]]
|
|
28
29
|
type: FieldEnum
|
|
29
30
|
|
|
30
|
-
def __init__(self, js):
|
|
31
|
+
def __init__(self, k, js):
|
|
32
|
+
self.key = k
|
|
31
33
|
self.type = js['type']
|
|
32
|
-
self.key = js.get('key')
|
|
33
34
|
self.bytes = js.get('bytes')
|
|
34
35
|
|
|
35
36
|
def decode(self, binary):
|
|
@@ -77,19 +78,13 @@ class FieldBase:
|
|
|
77
78
|
return binary[:self.bytes], binary[self.bytes:]
|
|
78
79
|
return binary[1:binary[0] + 1], binary[binary[0] + 1:]
|
|
79
80
|
|
|
80
|
-
def to_dict(self):
|
|
81
|
-
return {
|
|
82
|
-
'key': self.key,
|
|
83
|
-
'bytes': self.bytes,
|
|
84
|
-
'type': self.type
|
|
85
|
-
}
|
|
86
81
|
|
|
87
82
|
|
|
88
83
|
class FieldArray(FieldBase):
|
|
89
84
|
length: int
|
|
90
85
|
|
|
91
|
-
def __init__(self, js):
|
|
92
|
-
super().__init__(js)
|
|
86
|
+
def __init__(self, k, js):
|
|
87
|
+
super().__init__(k, js)
|
|
93
88
|
self.array = js['array']
|
|
94
89
|
|
|
95
90
|
def decode(self, binary):
|
|
@@ -98,17 +93,12 @@ class FieldArray(FieldBase):
|
|
|
98
93
|
val, binary = self.from_binary(binary)
|
|
99
94
|
return val, binary
|
|
100
95
|
|
|
101
|
-
def to_dict(self):
|
|
102
|
-
d = super().to_dict()
|
|
103
|
-
d['array'] = self.array
|
|
104
|
-
return d
|
|
105
|
-
|
|
106
96
|
def to_binary(self, val):
|
|
107
97
|
binary = b''
|
|
108
98
|
length = len(val)
|
|
109
99
|
binary += length.to_bytes(1, 'big')
|
|
110
100
|
for i in range(length):
|
|
111
|
-
fields = [FIELD_MAP[f['type']](f) for f in self.array]
|
|
101
|
+
fields = [FIELD_MAP[f['type']](k, f) for k, f in self.array.items()]
|
|
112
102
|
for f in fields:
|
|
113
103
|
binary += f.encode(val[i])
|
|
114
104
|
return binary
|
|
@@ -117,7 +107,7 @@ class FieldArray(FieldBase):
|
|
|
117
107
|
lista = []
|
|
118
108
|
for i in range(self.length):
|
|
119
109
|
data = {}
|
|
120
|
-
fields = [FIELD_MAP[f['type']](f) for f in self.array]
|
|
110
|
+
fields = [FIELD_MAP[f['type']](k, f) for k, f in self.array.items()]
|
|
121
111
|
for f in fields:
|
|
122
112
|
val, binary = f.decode(binary)
|
|
123
113
|
data[f.key] = val
|
|
@@ -128,8 +118,8 @@ class FieldArray(FieldBase):
|
|
|
128
118
|
class FieldBits(FieldBase):
|
|
129
119
|
length: int
|
|
130
120
|
|
|
131
|
-
def __init__(self, js):
|
|
132
|
-
super().__init__(js)
|
|
121
|
+
def __init__(self, k, js):
|
|
122
|
+
super().__init__(k, js)
|
|
133
123
|
self.length = js.get('length', 0)
|
|
134
124
|
self.bytes = math.ceil(self.length / 8)
|
|
135
125
|
|
|
@@ -177,10 +167,21 @@ class FieldBool(FieldBase):
|
|
|
177
167
|
bytes = 1
|
|
178
168
|
|
|
179
169
|
def to_binary(self, val):
|
|
180
|
-
|
|
170
|
+
if val is None:
|
|
171
|
+
val = 2
|
|
172
|
+
else:
|
|
173
|
+
val = bool(val)
|
|
174
|
+
|
|
175
|
+
return val.to_bytes(1, 'big', signed=False)
|
|
181
176
|
|
|
182
177
|
def from_binary(self, binary):
|
|
183
|
-
|
|
178
|
+
val = int.from_bytes(binary, 'big', signed=False)
|
|
179
|
+
if val == 0:
|
|
180
|
+
return False
|
|
181
|
+
elif val == 1:
|
|
182
|
+
return True
|
|
183
|
+
else:
|
|
184
|
+
return None
|
|
184
185
|
|
|
185
186
|
|
|
186
187
|
class FieldChar(FieldBase):
|
|
@@ -197,8 +198,8 @@ class FieldChar(FieldBase):
|
|
|
197
198
|
|
|
198
199
|
class FieldDate(FieldBase):
|
|
199
200
|
|
|
200
|
-
def __init__(self, js):
|
|
201
|
-
super().__init__(js)
|
|
201
|
+
def __init__(self, k, js):
|
|
202
|
+
super().__init__(k, js)
|
|
202
203
|
self.bytes = 3
|
|
203
204
|
|
|
204
205
|
def to_binary(self, val: datetime.datetime | str):
|
|
@@ -219,12 +220,16 @@ class FieldDate(FieldBase):
|
|
|
219
220
|
|
|
220
221
|
class FieldDateTime(FieldBase):
|
|
221
222
|
|
|
222
|
-
def __init__(self, js):
|
|
223
|
-
super().__init__(js)
|
|
223
|
+
def __init__(self, k, js):
|
|
224
|
+
super().__init__(k, js)
|
|
224
225
|
self.bytes = 6
|
|
225
226
|
|
|
226
227
|
def to_binary(self, val: datetime.datetime | str):
|
|
227
|
-
if
|
|
228
|
+
if val is None:
|
|
229
|
+
val = datetime.datetime(2000, 1, 1)
|
|
230
|
+
elif not isinstance(val, datetime.datetime):
|
|
231
|
+
raise ValueError(f'Error en el campo "{self.key}" se espera un datetime pero se recibe {val}')
|
|
232
|
+
elif isinstance(val, str):
|
|
228
233
|
val = datetime.datetime.strptime(val, '%Y-%m-%d %H:%M:%S').date()
|
|
229
234
|
return bytes([
|
|
230
235
|
self.to_nible(val.day),
|
|
@@ -246,12 +251,11 @@ class FieldDateTime(FieldBase):
|
|
|
246
251
|
|
|
247
252
|
|
|
248
253
|
class FieldFlags(FieldBase):
|
|
249
|
-
keys: List[str]
|
|
250
254
|
|
|
251
|
-
def __init__(self, js):
|
|
252
|
-
super().__init__(js)
|
|
253
|
-
self.
|
|
254
|
-
self.length = len(self.
|
|
255
|
+
def __init__(self, k, js):
|
|
256
|
+
super().__init__(k, js)
|
|
257
|
+
self.key = self.key.split(',')
|
|
258
|
+
self.length = len(self.key)
|
|
255
259
|
self.bytes = math.ceil(self.length / 8)
|
|
256
260
|
|
|
257
261
|
def encode(self, data):
|
|
@@ -264,23 +268,23 @@ class FieldFlags(FieldBase):
|
|
|
264
268
|
for b in bits:
|
|
265
269
|
flags.append(b == '1')
|
|
266
270
|
val = {}
|
|
267
|
-
order = -len(self.
|
|
268
|
-
for k in self.
|
|
271
|
+
order = -len(self.key)
|
|
272
|
+
for k in self.key:
|
|
269
273
|
val[k] = flags[order]
|
|
270
274
|
order += 1
|
|
271
275
|
return val
|
|
272
276
|
|
|
273
277
|
def to_binary(self, data):
|
|
274
|
-
bits = '0' * (8 - (len(self.
|
|
275
|
-
for k in self.
|
|
278
|
+
bits = '0' * (8 - (len(self.key) % 8))
|
|
279
|
+
for k in self.key:
|
|
276
280
|
bits += '1' if data[k] else '0'
|
|
277
281
|
return int(bits, 2).to_bytes(self.bytes, 'big', signed=False)
|
|
278
282
|
|
|
279
283
|
|
|
280
284
|
class FieldFloat(FieldBase):
|
|
281
285
|
|
|
282
|
-
def __init__(self, js):
|
|
283
|
-
super().__init__(js)
|
|
286
|
+
def __init__(self, k, js):
|
|
287
|
+
super().__init__(k, js)
|
|
284
288
|
self.decimals = js['decimals']
|
|
285
289
|
|
|
286
290
|
def from_binary(self, binary):
|
|
@@ -290,10 +294,23 @@ class FieldFloat(FieldBase):
|
|
|
290
294
|
def to_binary(self, val):
|
|
291
295
|
return int(round(val * (10 ** self.decimals))).to_bytes(self.bytes, 'big', signed=True)
|
|
292
296
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
+
|
|
298
|
+
class FieldId(FieldBase):
|
|
299
|
+
|
|
300
|
+
def to_binary(self, val):
|
|
301
|
+
if val is None:
|
|
302
|
+
val = 0
|
|
303
|
+
max_value = 256 ** self.bytes - 1
|
|
304
|
+
val = min(val, max_value)
|
|
305
|
+
if val < 0:
|
|
306
|
+
raise ValueError('Negative values not allowed')
|
|
307
|
+
return int(val).to_bytes(self.bytes, 'big', signed=False)
|
|
308
|
+
|
|
309
|
+
def from_binary(self, binary):
|
|
310
|
+
val = int.from_bytes(binary[:self.bytes], 'big', signed=False)
|
|
311
|
+
if val == 0:
|
|
312
|
+
val = None
|
|
313
|
+
return val
|
|
297
314
|
|
|
298
315
|
|
|
299
316
|
class FieldSigned(FieldBase):
|
|
@@ -327,8 +344,12 @@ class FieldTime(FieldBase):
|
|
|
327
344
|
|
|
328
345
|
bytes = 2
|
|
329
346
|
|
|
330
|
-
def to_binary(self, val: datetime.datetime | str):
|
|
331
|
-
if
|
|
347
|
+
def to_binary(self, val: datetime.datetime | datetime.time | str):
|
|
348
|
+
if val is None:
|
|
349
|
+
val = datetime.time(0, 0)
|
|
350
|
+
elif not isinstance(val, datetime.datetime) and not isinstance(val, datetime.time):
|
|
351
|
+
raise ValueError(f'Error en el campo "{self.key}" se espera un datetime o time pero se recibe {val}')
|
|
352
|
+
elif isinstance(val, str):
|
|
332
353
|
val = datetime.datetime.strptime(val, '%H:%M').date()
|
|
333
354
|
return bytes([
|
|
334
355
|
self.to_nible(val.hour),
|
|
@@ -338,13 +359,15 @@ class FieldTime(FieldBase):
|
|
|
338
359
|
def from_binary(self, binary):
|
|
339
360
|
H, binary = self.get_nible(binary)
|
|
340
361
|
M, binary = self.get_nible(binary)
|
|
362
|
+
if H == 0 and M == 0:
|
|
363
|
+
return None
|
|
341
364
|
return datetime.time(H, M)
|
|
342
365
|
|
|
343
366
|
|
|
344
367
|
class FieldTimestamp(FieldBase):
|
|
345
368
|
|
|
346
|
-
def __init__(self, js):
|
|
347
|
-
super().__init__(js)
|
|
369
|
+
def __init__(self, k, js):
|
|
370
|
+
super().__init__(k, js)
|
|
348
371
|
self.bytes = 8
|
|
349
372
|
|
|
350
373
|
def to_binary(self, val: datetime.datetime | str):
|
|
@@ -360,11 +383,11 @@ class FieldUnsigned(FieldBase):
|
|
|
360
383
|
|
|
361
384
|
def to_binary(self, val):
|
|
362
385
|
if val is None:
|
|
363
|
-
|
|
386
|
+
raise ValueError(f'Error en el campo "{self.key}" no se permite None')
|
|
364
387
|
max_value = 256 ** self.bytes - 1
|
|
365
388
|
val = min(val, max_value)
|
|
366
389
|
if val < 0:
|
|
367
|
-
raise ValueError('
|
|
390
|
+
raise ValueError(f'Error en el campo "{self.key}" se espera enteros positivos y se recibió {val}')
|
|
368
391
|
return int(val).to_bytes(self.bytes, 'big', signed=False)
|
|
369
392
|
|
|
370
393
|
def from_binary(self, binary):
|
|
@@ -380,6 +403,7 @@ FIELD_MAP = {
|
|
|
380
403
|
'datetime': FieldDateTime,
|
|
381
404
|
'flags': FieldFlags,
|
|
382
405
|
'float': FieldFloat,
|
|
406
|
+
'id': FieldId,
|
|
383
407
|
'signed': FieldSigned,
|
|
384
408
|
'string': FieldString,
|
|
385
409
|
'time': FieldTime,
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import yaml
|
|
3
|
+
from protobin.fields import FieldBase, FIELD_MAP
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Format:
|
|
7
|
+
|
|
8
|
+
input_fields: [FieldBase]
|
|
9
|
+
output_fields: [FieldBase]
|
|
10
|
+
|
|
11
|
+
def __init__(self, name: str, format, server: bool):
|
|
12
|
+
self.name = name
|
|
13
|
+
self.input_fields = []
|
|
14
|
+
self.output_fields = []
|
|
15
|
+
self.header = format['header']
|
|
16
|
+
if server is None:
|
|
17
|
+
input_mode = 'fields'
|
|
18
|
+
output_mode = 'fields'
|
|
19
|
+
else:
|
|
20
|
+
input_mode = 'device' if server else 'server'
|
|
21
|
+
output_mode = 'server' if server else 'device'
|
|
22
|
+
for k, f in format[input_mode].items():
|
|
23
|
+
self.input_fields.append(FIELD_MAP[f['type']](k, f))
|
|
24
|
+
for k, f in format[output_mode].items():
|
|
25
|
+
self.output_fields.append(FIELD_MAP[f['type']](k, f))
|
|
26
|
+
|
|
27
|
+
def encode(self, data):
|
|
28
|
+
binary = self.header.encode('utf') + b'='
|
|
29
|
+
for f in self.output_fields:
|
|
30
|
+
binary += f.encode(data)
|
|
31
|
+
return binary
|
|
32
|
+
|
|
33
|
+
def decode(self, binary):
|
|
34
|
+
data = {}
|
|
35
|
+
for f in self.input_fields:
|
|
36
|
+
val, binary = f.decode(binary)
|
|
37
|
+
if isinstance(f.key, list):
|
|
38
|
+
for k in f.key:
|
|
39
|
+
data[k] = val[k]
|
|
40
|
+
else:
|
|
41
|
+
data[f.key] = val
|
|
42
|
+
return data
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Protocol:
|
|
46
|
+
|
|
47
|
+
def __init__(self, server: bool = None, file=None, js=None):
|
|
48
|
+
self.server = server
|
|
49
|
+
self.headers = {}
|
|
50
|
+
if file:
|
|
51
|
+
with open(file, 'r') as f:
|
|
52
|
+
if 'json' in file:
|
|
53
|
+
js = json.loads(f.read())
|
|
54
|
+
self.load_format(js)
|
|
55
|
+
elif 'yaml' in file:
|
|
56
|
+
js = yaml.full_load(f.read())
|
|
57
|
+
self.load_format(js)
|
|
58
|
+
else:
|
|
59
|
+
self.load_format(js)
|
|
60
|
+
|
|
61
|
+
def load_format(self, js):
|
|
62
|
+
self.formats = {}
|
|
63
|
+
for k in js.keys():
|
|
64
|
+
self.formats[k] = Format(name=k, format=js[k], server=self.server)
|
|
65
|
+
self.headers[js[k]['header']] = k
|
|
66
|
+
|
|
67
|
+
def get_format(self, h):
|
|
68
|
+
return self.formats[self.headers[h.decode('utf')]]
|
|
69
|
+
|
|
70
|
+
def encode(self, data, format):
|
|
71
|
+
return self.formats[format].encode(data)
|
|
72
|
+
|
|
73
|
+
def decode(self, binary):
|
|
74
|
+
h, binary = binary.split(b'=')
|
|
75
|
+
format = self.get_format(h)
|
|
76
|
+
return format.name, format.decode(binary)
|
|
@@ -4,10 +4,13 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "protobin"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.8"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Daniel Robles", email="drm.electronic@gmail.com" },
|
|
10
10
|
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
'PyYAML ~= 6.0'
|
|
13
|
+
]
|
|
11
14
|
description = "Python library for encode and decode data in protobin format"
|
|
12
15
|
readme = "README.md"
|
|
13
16
|
license = { file="LICENSE.txt" }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"login": {
|
|
3
|
+
"header": "T",
|
|
4
|
+
"device": {
|
|
5
|
+
"serial": {"bytes": 0, "type": "string"}
|
|
6
|
+
},
|
|
7
|
+
"server": {
|
|
8
|
+
"id": {"bytes": 2, "type": "id"},
|
|
9
|
+
"bus_number": {"bytes": 2, "type": "id"},
|
|
10
|
+
"route": {"bytes": 1, "type": "id"},
|
|
11
|
+
"direction": {"bytes": 1, "type": "bool"},
|
|
12
|
+
"geofence": {"bytes": 2, "type": "id"},
|
|
13
|
+
"state": {"bytes": 1, "type": "char"},
|
|
14
|
+
"trip": {"bytes": 4, "type": "id"},
|
|
15
|
+
"driver": {"bytes": 4, "type": "id"}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"report": {
|
|
19
|
+
"header": "P",
|
|
20
|
+
"device": {
|
|
21
|
+
"positions": {"bytes": 19, "type": "array", "array": {
|
|
22
|
+
"time": {"bytes": 6, "type": "datetime"},
|
|
23
|
+
"lng": {"bytes": 4, "type": "float", "decimals": 6},
|
|
24
|
+
"lat": {"bytes": 4, "type": "float", "decimals": 6},
|
|
25
|
+
"speed": {"bytes": 1, "type": "unsigned"},
|
|
26
|
+
"mark": {"bytes": 2, "type": "id"},
|
|
27
|
+
"busstop": {"bytes": 2, "type": "id"}}
|
|
28
|
+
},
|
|
29
|
+
"trip": {"bytes": 4, "type": "unsigned"},
|
|
30
|
+
"route": {"bytes": 1, "type": "unsigned"},
|
|
31
|
+
"direction": {"bytes": 1, "type": "bool"},
|
|
32
|
+
"state": {"bytes": 1, "type": "char"},
|
|
33
|
+
"sales": {"bytes": 3, "type": "unsigned"},
|
|
34
|
+
"events": {"bytes": 3, "type": "array", "array": {
|
|
35
|
+
"id": {"bytes": 2, "type": "unsigned"},
|
|
36
|
+
"value": {"bytes": 1, "type": "unsigned"}}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"server": {
|
|
40
|
+
"positions": {"bytes": 1, "type": "unsigned"}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,53 +1,55 @@
|
|
|
1
1
|
report:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
2
|
+
header: P
|
|
3
|
+
format:
|
|
4
|
+
positions:
|
|
5
|
+
bytes: 19
|
|
6
|
+
type: array
|
|
7
|
+
array:
|
|
8
|
+
time:
|
|
9
|
+
bytes: 6
|
|
10
|
+
type: datetime
|
|
11
|
+
lng:
|
|
12
|
+
bytes: 4
|
|
13
|
+
decimals: 6
|
|
14
|
+
type: float
|
|
15
|
+
lat:
|
|
16
|
+
bytes: 4
|
|
17
|
+
decimals: 6
|
|
18
|
+
type: float
|
|
19
|
+
speed:
|
|
20
|
+
bytes: 1
|
|
21
|
+
type: unsigned
|
|
22
|
+
mark:
|
|
23
|
+
bytes: 2
|
|
24
|
+
type: unsigned
|
|
25
|
+
busstop:
|
|
26
|
+
bytes: 2
|
|
27
|
+
type: unsigned
|
|
28
|
+
trip:
|
|
29
|
+
bytes: 4
|
|
30
|
+
type: unsigned
|
|
31
|
+
route:
|
|
32
|
+
bytes: 1
|
|
33
|
+
type: unsigned
|
|
34
|
+
direction:
|
|
35
|
+
bytes: 1
|
|
36
|
+
type: bool
|
|
37
|
+
state:
|
|
38
|
+
bytes: 1
|
|
39
|
+
type: char
|
|
40
|
+
sales:
|
|
41
|
+
bytes: 3
|
|
42
|
+
type: unsigned
|
|
43
|
+
events:
|
|
44
|
+
bytes: 3
|
|
45
|
+
type: array
|
|
46
|
+
array:
|
|
47
|
+
id:
|
|
48
|
+
bytes: 2
|
|
49
|
+
type: unsigned
|
|
50
|
+
value:
|
|
51
|
+
bytes: 1
|
|
52
|
+
type: unsigned
|
|
51
53
|
|
|
52
54
|
ask_schedule:
|
|
53
55
|
id:
|
|
@@ -12,7 +12,7 @@ DATA = {
|
|
|
12
12
|
'lng': -11.485014,
|
|
13
13
|
'lat': -77.621845,
|
|
14
14
|
'speed': 20,
|
|
15
|
-
'mark':
|
|
15
|
+
'mark': None,
|
|
16
16
|
'busstop': 16
|
|
17
17
|
},
|
|
18
18
|
{
|
|
@@ -20,7 +20,7 @@ DATA = {
|
|
|
20
20
|
'lng': -11.485414,
|
|
21
21
|
'lat': -77.622245,
|
|
22
22
|
'speed': 25,
|
|
23
|
-
'mark':
|
|
23
|
+
'mark': None,
|
|
24
24
|
'busstop': 16
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -28,7 +28,7 @@ DATA = {
|
|
|
28
28
|
'lng': -11.485514,
|
|
29
29
|
'lat': -77.621945,
|
|
30
30
|
'speed': 18,
|
|
31
|
-
'mark':
|
|
31
|
+
'mark': None,
|
|
32
32
|
'busstop': 16
|
|
33
33
|
},
|
|
34
34
|
{
|
|
@@ -62,73 +62,69 @@ DATA = {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
class FormatTest(unittest.TestCase):
|
|
66
|
-
|
|
67
|
-
def test_format_array(self):
|
|
68
|
-
parser = Protocol(js={
|
|
69
|
-
'array': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
|
|
70
|
-
{'key': 'test', 'bytes': 0, 'type': 'string'}
|
|
71
|
-
]}]
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
def test_format_bits(self):
|
|
75
|
-
parser = Protocol(js={
|
|
76
|
-
'bits': [{'key': 'test', 'bytes': 2, 'type': 'bits'}],
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
def test_format_date(self):
|
|
80
|
-
|
|
81
|
-
self.parser = Protocol(js={
|
|
82
|
-
'date': [{'key': 'test', 'bytes': 1, 'type': 'date'}],
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
def test_format_flags(self):
|
|
86
|
-
|
|
87
|
-
self.parser = Protocol(js={
|
|
88
|
-
'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'bytes': 1, 'type': 'flags'}],
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
def test_format(self):
|
|
92
|
-
|
|
93
|
-
self.parser = Protocol(js={
|
|
94
|
-
'array': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
|
|
95
|
-
{'key': 'test', 'bytes': 0, 'type': 'string'}
|
|
96
|
-
]}],
|
|
97
|
-
'bits': [{'key': 'test', 'bytes': 2, 'type': 'bits'}],
|
|
98
|
-
'bool': [{'key': 'test', 'bytes': 1, 'type': 'bool'}],
|
|
99
|
-
'char': [{'key': 'test', 'bytes': 1, 'type': 'char'}],
|
|
100
|
-
'date': [{'key': 'test', 'bytes': 3, 'type': 'date'}],
|
|
101
|
-
'datetime': [{'key': 'test', 'bytes': 6, 'type': 'datetime'}],
|
|
102
|
-
'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'bytes': 1, 'type': 'flags'}],
|
|
103
|
-
'float': [{'key': 'test', 'bytes': 4, 'decimals': 6, 'type': 'float'}],
|
|
104
|
-
'signed': [{'key': 'test', 'bytes': 2, 'type': 'signed'}],
|
|
105
|
-
'string': [{'key': 'test', 'bytes': 0, 'type': 'string'}],
|
|
106
|
-
'time': [{'key': 'test', 'bytes': 1, 'type': 'time'}],
|
|
107
|
-
'timestamp': [{'key': 'test', 'bytes': 8, 'type': 'string'}],
|
|
108
|
-
'unsigned': [{'key': 'test', 'bytes': 3, 'type': 'unsigned'}]
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
|
|
112
65
|
class BasicTest(unittest.TestCase):
|
|
113
66
|
|
|
114
67
|
def setUp(self):
|
|
115
68
|
self.protocol = Protocol(js={
|
|
116
|
-
'array':
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
'
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
'
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
'
|
|
69
|
+
'array': {
|
|
70
|
+
"header": "A",
|
|
71
|
+
"fields": {
|
|
72
|
+
'test': {'bytes': 0, 'type': 'array', 'array': {
|
|
73
|
+
'test': {'bytes': 0, 'type': 'string'}
|
|
74
|
+
}}}
|
|
75
|
+
},
|
|
76
|
+
'bits': {
|
|
77
|
+
"header": "B",
|
|
78
|
+
"fields": {'test': {'type': 'bits'}}
|
|
79
|
+
},
|
|
80
|
+
'bits_fixed': {
|
|
81
|
+
"header": "b",
|
|
82
|
+
"fields": {'test': {'type': 'bits', 'length': 7}}
|
|
83
|
+
},
|
|
84
|
+
'bool': {
|
|
85
|
+
"header": "BO",
|
|
86
|
+
"fields": {'test': {'bytes': 1, 'type': 'bool'}}
|
|
87
|
+
},
|
|
88
|
+
'char': {
|
|
89
|
+
"header": "C",
|
|
90
|
+
"fields": {'test': {'bytes': 1, 'type': 'char'}}
|
|
91
|
+
},
|
|
92
|
+
'date': {
|
|
93
|
+
"header": "D",
|
|
94
|
+
"fields": {'test': {'bytes': 1, 'type': 'date'}}
|
|
95
|
+
},
|
|
96
|
+
'datetime': {
|
|
97
|
+
"header": "d",
|
|
98
|
+
"fields": {'test': {'bytes': 1, 'type': 'datetime'}}
|
|
99
|
+
},
|
|
100
|
+
'flags': {
|
|
101
|
+
"header": "F",
|
|
102
|
+
"fields": {'f1,f2,f3,f4': {'type': 'flags'}}
|
|
103
|
+
},
|
|
104
|
+
'float': {
|
|
105
|
+
"header": "f",
|
|
106
|
+
"fields": {'test': {'bytes': 4, 'decimals': 6, 'type': 'float'}}
|
|
107
|
+
},
|
|
108
|
+
'signed': {
|
|
109
|
+
"header": "+",
|
|
110
|
+
"fields": {'test': {'bytes': 2, 'type': 'signed'}}
|
|
111
|
+
},
|
|
112
|
+
'string': {
|
|
113
|
+
"header": "S",
|
|
114
|
+
"fields": {'test': {'bytes': 0, 'type': 'string'}}
|
|
115
|
+
},
|
|
116
|
+
'time': {
|
|
117
|
+
"header": "T",
|
|
118
|
+
"fields": {'test': {'bytes': 2, 'type': 'time'}}
|
|
119
|
+
},
|
|
120
|
+
'timestamp': {
|
|
121
|
+
"header": "TS",
|
|
122
|
+
"fields": {'test': {'bytes': 8, 'type': 'timestamp'}}
|
|
123
|
+
},
|
|
124
|
+
'unsigned': {
|
|
125
|
+
"header": "u",
|
|
126
|
+
"fields": {'test': {'bytes': 3, 'type': 'unsigned'}}
|
|
127
|
+
}
|
|
132
128
|
})
|
|
133
129
|
|
|
134
130
|
def test_array(self):
|
|
@@ -138,7 +134,7 @@ class BasicTest(unittest.TestCase):
|
|
|
138
134
|
{'test': 'otra más'}]
|
|
139
135
|
}
|
|
140
136
|
binary = self.protocol.encode(data, 'array')
|
|
141
|
-
recv = self.protocol.decode(binary
|
|
137
|
+
h, recv = self.protocol.decode(binary)
|
|
142
138
|
self.assertEqual(data, recv)
|
|
143
139
|
data = {'test': [
|
|
144
140
|
{'test': 'texto2 de prueba'},
|
|
@@ -147,123 +143,155 @@ class BasicTest(unittest.TestCase):
|
|
|
147
143
|
{'test': 'y una última'}]
|
|
148
144
|
}
|
|
149
145
|
binary = self.protocol.encode(data, 'array')
|
|
150
|
-
recv = self.protocol.decode(binary
|
|
146
|
+
h, recv = self.protocol.decode(binary)
|
|
151
147
|
self.assertEqual(data, recv)
|
|
152
148
|
|
|
153
149
|
def test_bits(self):
|
|
154
150
|
data = {'test': [True, False, True, False, False] * 3}
|
|
155
151
|
binary = self.protocol.encode(data, 'bits')
|
|
156
|
-
recv = self.protocol.decode(binary
|
|
152
|
+
h, recv = self.protocol.decode(binary)
|
|
157
153
|
self.assertEqual(data, recv)
|
|
158
154
|
data = {'test': [True, False, True, False, False] * 5}
|
|
159
155
|
binary = self.protocol.encode(data, 'bits')
|
|
160
|
-
recv = self.protocol.decode(binary
|
|
156
|
+
h, recv = self.protocol.decode(binary)
|
|
161
157
|
self.assertEqual(data, recv)
|
|
162
158
|
|
|
163
159
|
def test_bits_fixed(self):
|
|
164
160
|
data = {'test': [True, False, True, False, False, True, True]}
|
|
165
161
|
binary = self.protocol.encode(data, 'bits_fixed')
|
|
166
|
-
recv = self.protocol.decode(binary
|
|
162
|
+
h, recv = self.protocol.decode(binary)
|
|
167
163
|
self.assertEqual(data, recv)
|
|
168
164
|
|
|
169
165
|
def test_bool(self):
|
|
170
166
|
data = {'test': False}
|
|
171
167
|
binary = self.protocol.encode(data, 'bool')
|
|
172
|
-
recv = self.protocol.decode(binary
|
|
168
|
+
h, recv = self.protocol.decode(binary)
|
|
169
|
+
self.assertEqual(data, recv)
|
|
170
|
+
|
|
171
|
+
def test_bool_none(self):
|
|
172
|
+
data = {'test': None}
|
|
173
|
+
binary = self.protocol.encode(data, 'bool')
|
|
174
|
+
h, recv = self.protocol.decode(binary)
|
|
173
175
|
self.assertEqual(data, recv)
|
|
174
176
|
|
|
175
177
|
def test_char(self):
|
|
176
178
|
data = {'test': 'F'}
|
|
177
179
|
binary = self.protocol.encode(data, 'char')
|
|
178
|
-
recv = self.protocol.decode(binary
|
|
180
|
+
h, recv = self.protocol.decode(binary)
|
|
179
181
|
self.assertEqual(data, recv)
|
|
180
182
|
|
|
181
183
|
def test_date(self):
|
|
182
184
|
data = {'test': datetime.date(2024, 9, 13)}
|
|
183
185
|
binary = self.protocol.encode(data, 'date')
|
|
184
|
-
recv = self.protocol.decode(binary
|
|
186
|
+
h, recv = self.protocol.decode(binary)
|
|
185
187
|
self.assertEqual(data, recv)
|
|
186
188
|
|
|
187
189
|
def test_datetime(self):
|
|
188
190
|
data = {'test': datetime.datetime(2024, 9, 13, 15, 23, 51)}
|
|
189
191
|
binary = self.protocol.encode(data, 'datetime')
|
|
190
|
-
|
|
192
|
+
print('binary', binary)
|
|
193
|
+
h, recv = self.protocol.decode(binary)
|
|
194
|
+
print('recv', recv)
|
|
191
195
|
self.assertEqual(data, recv)
|
|
192
196
|
|
|
197
|
+
def test_datetime_error_type(self):
|
|
198
|
+
data = {'test': []}
|
|
199
|
+
with self.assertRaises(ValueError) as er:
|
|
200
|
+
self.protocol.encode(data, 'datetime')
|
|
201
|
+
|
|
202
|
+
def test_datetime_none(self):
|
|
203
|
+
data = {'test': None}
|
|
204
|
+
binary = self.protocol.encode(data, 'datetime')
|
|
205
|
+
print('binary', binary)
|
|
206
|
+
h, recv = self.protocol.decode(binary)
|
|
207
|
+
print('recv', recv)
|
|
208
|
+
self.assertEqual(datetime.datetime(2000, 1, 1), recv['test'])
|
|
209
|
+
|
|
193
210
|
def test_time(self):
|
|
194
211
|
data = {'test': datetime.time(15, 23)}
|
|
195
212
|
binary = self.protocol.encode(data, 'time')
|
|
196
|
-
recv = self.protocol.decode(binary
|
|
213
|
+
h, recv = self.protocol.decode(binary)
|
|
214
|
+
self.assertEqual(data, recv)
|
|
215
|
+
|
|
216
|
+
def test_time_none(self):
|
|
217
|
+
data = {'test': None}
|
|
218
|
+
binary = self.protocol.encode(data, 'time')
|
|
219
|
+
h, recv = self.protocol.decode(binary)
|
|
197
220
|
self.assertEqual(data, recv)
|
|
198
221
|
|
|
199
222
|
def test_flags(self):
|
|
200
223
|
data = {'f1': True, 'f2': False, 'f3': False, 'f4': True}
|
|
201
224
|
binary = self.protocol.encode(data, 'flags')
|
|
202
|
-
recv = self.protocol.decode(binary
|
|
225
|
+
h, recv = self.protocol.decode(binary)
|
|
203
226
|
self.assertEqual(data, recv)
|
|
204
227
|
|
|
205
228
|
def test_float(self):
|
|
206
229
|
data = {'test': -11.659812}
|
|
207
230
|
binary = self.protocol.encode(data, 'float')
|
|
208
|
-
|
|
231
|
+
print(binary)
|
|
232
|
+
h, recv = self.protocol.decode(binary)
|
|
209
233
|
self.assertEqual(data, recv)
|
|
210
234
|
|
|
211
235
|
def test_signed(self):
|
|
212
236
|
data = {'test': -11812}
|
|
213
237
|
binary = self.protocol.encode(data, 'signed')
|
|
214
|
-
recv = self.protocol.decode(binary
|
|
238
|
+
h, recv = self.protocol.decode(binary)
|
|
215
239
|
self.assertEqual(data, recv)
|
|
216
240
|
|
|
217
241
|
def test_unsigned(self):
|
|
218
242
|
data = {'test': 9811812}
|
|
219
243
|
binary = self.protocol.encode(data, 'unsigned')
|
|
220
|
-
recv = self.protocol.decode(binary
|
|
244
|
+
h, recv = self.protocol.decode(binary)
|
|
221
245
|
self.assertEqual(data, recv)
|
|
222
246
|
|
|
223
247
|
def test_string(self):
|
|
224
248
|
data = {'test': 'texto de prueba'}
|
|
225
249
|
binary = self.protocol.encode(data, 'string')
|
|
226
|
-
recv = self.protocol.decode(binary
|
|
250
|
+
h, recv = self.protocol.decode(binary)
|
|
227
251
|
self.assertEqual(data, recv)
|
|
228
252
|
data = {'test': 'otro texto de prueba más largo'}
|
|
229
253
|
binary = self.protocol.encode(data, 'string')
|
|
230
|
-
recv = self.protocol.decode(binary
|
|
254
|
+
h, recv = self.protocol.decode(binary)
|
|
231
255
|
self.assertEqual(data, recv)
|
|
232
256
|
|
|
233
257
|
def test_timestamp(self):
|
|
234
258
|
data = {'test': datetime.datetime(2024, 9, 13, 15, 23, 51, 265981)}
|
|
235
259
|
binary = self.protocol.encode(data, 'timestamp')
|
|
236
|
-
recv = self.protocol.decode(binary
|
|
260
|
+
h, recv = self.protocol.decode(binary)
|
|
237
261
|
self.assertEqual(data, recv)
|
|
238
262
|
|
|
239
263
|
|
|
240
264
|
class AdvancedTest(unittest.TestCase):
|
|
241
265
|
|
|
242
266
|
def test_file_json(self):
|
|
243
|
-
|
|
244
|
-
binary =
|
|
245
|
-
|
|
267
|
+
device = Protocol(file='demo.json', server=False)
|
|
268
|
+
binary = device.encode(DATA, 'report')
|
|
269
|
+
server = Protocol(file='demo.json', server=True)
|
|
270
|
+
name, recv = server.decode(binary)
|
|
246
271
|
self.assertEqual(DATA, recv)
|
|
272
|
+
self.assertEqual(name, 'report')
|
|
247
273
|
|
|
248
|
-
def test_file_yaml(self):
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
274
|
+
# def test_file_yaml(self):
|
|
275
|
+
# protocol = Protocol(file='demo.yaml')
|
|
276
|
+
# binary = protocol.encode(DATA, 'report')
|
|
277
|
+
# h, recv = protocol.decode(binary)
|
|
278
|
+
# self.assertEqual(h, 'P')
|
|
253
279
|
|
|
254
280
|
def test_json(self):
|
|
255
|
-
protocol = Protocol(js={'medida':
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
281
|
+
protocol = Protocol(js={'medida':
|
|
282
|
+
{'header': 'M',
|
|
283
|
+
'fields': {
|
|
284
|
+
'id': {'bytes': 1, 'type': 'unsigned'},
|
|
285
|
+
'nombre': {'type': 'string'},
|
|
286
|
+
'valor': {'bytes': 2, 'type': 'signed'}
|
|
287
|
+
}}})
|
|
260
288
|
data = {'id': 2, 'nombre': 'Voltaje', 'valor': -20}
|
|
261
289
|
binary = protocol.encode(data, 'medida')
|
|
262
|
-
recv = protocol.decode(binary
|
|
290
|
+
h, recv = protocol.decode(binary)
|
|
263
291
|
self.assertEqual(data, recv)
|
|
264
292
|
data = {'id': 4, 'nombre': 'Corriente', 'valor': 240}
|
|
265
293
|
binary = protocol.encode(data, 'medida')
|
|
266
|
-
recv = protocol.decode(binary
|
|
294
|
+
h, recv = protocol.decode(binary)
|
|
267
295
|
self.assertEqual(data, recv)
|
|
268
296
|
|
|
269
297
|
def test_new_yaml(self):
|
|
@@ -319,8 +347,29 @@ class AdvancedTest(unittest.TestCase):
|
|
|
319
347
|
type: unsigned
|
|
320
348
|
""")
|
|
321
349
|
js = json.dumps(ym, indent=2)
|
|
322
|
-
print(js)
|
|
323
350
|
|
|
324
351
|
def test_convert_json_to_yaml(self):
|
|
325
|
-
protocol = Protocol(file='demo.json')
|
|
326
|
-
|
|
352
|
+
protocol = Protocol(file='demo.json', server=True)
|
|
353
|
+
|
|
354
|
+
def test_login(self):
|
|
355
|
+
device = Protocol(file='demo.json', server=False)
|
|
356
|
+
server = Protocol(file='demo.json', server=True)
|
|
357
|
+
data = {'serial': '15984316545'}
|
|
358
|
+
binary = device.encode(data, 'login')
|
|
359
|
+
header, recv = server.decode(binary)
|
|
360
|
+
self.assertEqual(header, 'login')
|
|
361
|
+
self.assertEqual(data, recv)
|
|
362
|
+
data = {
|
|
363
|
+
'id': 43,
|
|
364
|
+
'bus_number': 18,
|
|
365
|
+
'route': 2,
|
|
366
|
+
'direction': True,
|
|
367
|
+
'geofence': None,
|
|
368
|
+
'state': 'R',
|
|
369
|
+
'trip': 5681121,
|
|
370
|
+
'driver': 1432
|
|
371
|
+
}
|
|
372
|
+
binary = server.encode(data, 'login')
|
|
373
|
+
header, recv = device.decode(binary)
|
|
374
|
+
self.assertEqual(header, 'login')
|
|
375
|
+
self.assertEqual(data, recv)
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
|
-
import yaml
|
|
4
|
-
|
|
5
|
-
from protobin.fields import FieldBase, FIELD_MAP
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Format:
|
|
9
|
-
|
|
10
|
-
fields: [FieldBase]
|
|
11
|
-
|
|
12
|
-
def __init__(self, fields: [object]):
|
|
13
|
-
self.fields = []
|
|
14
|
-
for f in fields:
|
|
15
|
-
self.fields.append(FIELD_MAP[f['type']](f))
|
|
16
|
-
|
|
17
|
-
def encode(self, data):
|
|
18
|
-
binary = b''
|
|
19
|
-
for f in self.fields:
|
|
20
|
-
binary += f.encode(data)
|
|
21
|
-
return binary
|
|
22
|
-
|
|
23
|
-
def decode(self, binary):
|
|
24
|
-
data = {}
|
|
25
|
-
for f in self.fields:
|
|
26
|
-
val, binary = f.decode(binary)
|
|
27
|
-
if f.key:
|
|
28
|
-
data[f.key] = val
|
|
29
|
-
else:
|
|
30
|
-
for k in f.keys:
|
|
31
|
-
data[k] = val[k]
|
|
32
|
-
return data
|
|
33
|
-
|
|
34
|
-
def to_dict(self):
|
|
35
|
-
return [f.to_dict() for f in self.fields]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class Protocol:
|
|
39
|
-
|
|
40
|
-
def __init__(self, file=None, js=None):
|
|
41
|
-
if file:
|
|
42
|
-
with open(file, 'r') as f:
|
|
43
|
-
if 'json' in file:
|
|
44
|
-
js = json.loads(f.read())
|
|
45
|
-
self.formats = {}
|
|
46
|
-
for k in js.keys():
|
|
47
|
-
self.formats[k] = Format(js[k])
|
|
48
|
-
elif 'yaml' in file:
|
|
49
|
-
js = yaml.full_load(f.read())
|
|
50
|
-
self.formats = {}
|
|
51
|
-
for k in js.keys():
|
|
52
|
-
self.formats[k] = Format(js[k])
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def temp_format(self, k):
|
|
56
|
-
return self.formats[k].to_dict()
|
|
57
|
-
|
|
58
|
-
def encode(self, data, format):
|
|
59
|
-
return self.formats[format].encode(data)
|
|
60
|
-
|
|
61
|
-
def decode(self, binary, format):
|
|
62
|
-
return self.formats[format].decode(binary)
|
protobin-0.0.6/tests/demo.json
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ask_schedule1": {
|
|
3
|
-
"id": [{"bytes": 4, "type": "unsigned"}],
|
|
4
|
-
"inicio": [{"bytes": 6, "type": "datetime"}]},
|
|
5
|
-
|
|
6
|
-
"fare": [
|
|
7
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
8
|
-
{"key": "color", "bytes": 7, "type": "string"},
|
|
9
|
-
{"key": "orden", "bytes": 1, "type": "unsigned"},
|
|
10
|
-
{"key": "nombre", "bytes": 13, "type": "string"},
|
|
11
|
-
{"keys": ["activo", "reintegro"], "bytes": 1, "type": "flags"},
|
|
12
|
-
{"keys": ["lunes", "martes", "miercoles", "jueves", "viernes", "sabado", "domingo", "feriado"], "bytes": 1, "type": "flags"},
|
|
13
|
-
{"key": "ruta", "bytes": 2, "type": "unsigned"},
|
|
14
|
-
{"key": "tarifa", "bytes": 2, "type": "float", "decimals": 2},
|
|
15
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
16
|
-
],
|
|
17
|
-
"command": [
|
|
18
|
-
{"key": "comando", "bytes": 1, "type": "char"},
|
|
19
|
-
{"key": "id", "bytes": 0, "type": "string"},
|
|
20
|
-
{"key": "value", "bytes": 0, "type": "string"}
|
|
21
|
-
],
|
|
22
|
-
"route_settings": [
|
|
23
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
24
|
-
{"key": "nombre", "bytes": 0, "type": "string"},
|
|
25
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
26
|
-
{"key": "tipo", "bytes": 0, "type": "string"},
|
|
27
|
-
{"key": "data", "bytes": 0, "type": "string"},
|
|
28
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
29
|
-
],
|
|
30
|
-
"forward_datero": [
|
|
31
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
32
|
-
{"key": "salida", "bytes": 4, "type": "unsigned"},
|
|
33
|
-
{"key": "hora", "bytes": 6, "type": "datetime"},
|
|
34
|
-
{"key": "dateros", "bytes": 0, "type": "array", "array": [
|
|
35
|
-
{"key": "padron", "bytes": 2, "type": "unsigned"},
|
|
36
|
-
{"key": "delta", "bytes": 1, "type": "unsigned"}
|
|
37
|
-
]}
|
|
38
|
-
],
|
|
39
|
-
"backward_datero": [
|
|
40
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
41
|
-
{"key": "i", "bytes": 1, "type": "unsigned"},
|
|
42
|
-
{"key": "delta", "bytes": 1, "type": "unsigned"},
|
|
43
|
-
{"key": "padron", "bytes": 2, "type": "unsigned"},
|
|
44
|
-
{"key": "id", "bytes": 0, "type": "string"}
|
|
45
|
-
],
|
|
46
|
-
"error": [
|
|
47
|
-
{"key": "error", "bytes": 0, "type": "string"}
|
|
48
|
-
],
|
|
49
|
-
"geocerca": [
|
|
50
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
51
|
-
{"key": "orden", "bytes": 1, "type": "unsigned"},
|
|
52
|
-
{"key": "longitud", "bytes": 4, "type": "float", "decimals": 6},
|
|
53
|
-
{"key": "latitud", "bytes": 4, "type": "float", "decimals": 6},
|
|
54
|
-
{"key": "radio", "bytes": 2, "type": "unsigned"},
|
|
55
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
56
|
-
{"keys": ["lado", "control", "datear", "activo"], "bytes": 1, "type": "flags"},
|
|
57
|
-
{"key": "nombre", "bytes": 15, "type": "string"},
|
|
58
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
59
|
-
],
|
|
60
|
-
"ask_trip": [
|
|
61
|
-
{"key": "salida", "bytes": 4, "type": "unsigned"}
|
|
62
|
-
],
|
|
63
|
-
"schedule": [
|
|
64
|
-
{"key": "salida", "bytes": 4, "type": "unsigned"},
|
|
65
|
-
{"key": "controles", "bytes": 0, "type": "array", "array": [
|
|
66
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"}
|
|
67
|
-
]}
|
|
68
|
-
],
|
|
69
|
-
"ask_schedule": [
|
|
70
|
-
{"key": "id", "bytes": 4, "type": "unsigned"},
|
|
71
|
-
{"key": "inicio", "bytes": 6, "type": "datetime"},
|
|
72
|
-
{"key": "controles", "bytes": 0, "type": "array", "array": [
|
|
73
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
74
|
-
{"key": "tiempo", "bytes": 1, "type": "signed"},
|
|
75
|
-
{"key": "volada", "bytes": 1, "type": "signed"}
|
|
76
|
-
]}
|
|
77
|
-
],
|
|
78
|
-
"login": [
|
|
79
|
-
{"key": "serial", "bytes": 0, "type": "string"}
|
|
80
|
-
],
|
|
81
|
-
"new_ip": [
|
|
82
|
-
{"key": "ip", "bytes": 0, "type": "string"}
|
|
83
|
-
],
|
|
84
|
-
"login_device": [
|
|
85
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
86
|
-
{"key": "padron", "bytes": 2, "type": "unsigned"},
|
|
87
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
88
|
-
{"key": "lado", "bytes": 1, "type": "bool"},
|
|
89
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
90
|
-
{"key": "estado", "bytes": 1, "type": "char"},
|
|
91
|
-
{"key": "salida", "bytes": 4, "type": "unsigned"},
|
|
92
|
-
{"key": "conductor", "bytes": 4, "type": "unsigned"},
|
|
93
|
-
{"key": "orden", "bytes": 1, "type": "unsigned"},
|
|
94
|
-
{"key": "logueado", "bytes": 1, "type": "bool"},
|
|
95
|
-
{"key": "data", "bytes": 6, "type": "datetime"},
|
|
96
|
-
{"key": "programada", "bytes": 2, "type": "time"}
|
|
97
|
-
],
|
|
98
|
-
"start_sales": [
|
|
99
|
-
{"key": "clave", "bytes": 0, "type": "string"},
|
|
100
|
-
{"key": "dni", "bytes": 0, "type": "string"},
|
|
101
|
-
{"key": "lado", "bytes": 1, "type": "bool"},
|
|
102
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
103
|
-
{"key": "unidad", "bytes": 2, "type": "unsigned"}
|
|
104
|
-
],
|
|
105
|
-
"start_sales_response": [
|
|
106
|
-
{"key": "error", "bytes": 1, "type": "bool"},
|
|
107
|
-
{"key": "title", "bytes": 0, "type": "string"},
|
|
108
|
-
{"key": "mensaje", "bytes": 0, "type": "string"},
|
|
109
|
-
{"key": "sesiones", "bytes": 0, "type": "array", "array": [
|
|
110
|
-
{"key": "id", "bytes": 4, "type": "unsigned"},
|
|
111
|
-
{"key": "conductor_id", "bytes": 2, "type": "unsigned"},
|
|
112
|
-
{"key": "conductor_codigo", "bytes": 0, "type": "string"},
|
|
113
|
-
{"keys": ["activo", "castigado", "conductor", "vencido"], "bytes": 1, "type": "flags"},
|
|
114
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
115
|
-
{"key": "lado", "bytes": 1, "type": "bool"},
|
|
116
|
-
{"key": "inicio", "bytes": 6, "type": "datetime"}
|
|
117
|
-
]}
|
|
118
|
-
],
|
|
119
|
-
"finalize_sales": [
|
|
120
|
-
{"key": "sesion", "bytes": 4, "type": "unsigned"},
|
|
121
|
-
{"key": "unidad", "bytes": 2, "type": "unsigned"},
|
|
122
|
-
{"key": "fin", "bytes": 6, "type": "datetime"},
|
|
123
|
-
{"key": "produccion", "bytes": 4, "type": "unsigned"},
|
|
124
|
-
{"key": "primero", "bytes": 4, "type": "unsigned"},
|
|
125
|
-
{"key": "ultimo", "bytes": 4, "type": "unsigned"}
|
|
126
|
-
],
|
|
127
|
-
"finalize_sales_response": [
|
|
128
|
-
{"key": "error", "bytes": 1, "type": "bool"},
|
|
129
|
-
{"key": "title", "bytes": 0, "type": "string"},
|
|
130
|
-
{"key": "mensaje", "bytes": 0, "type": "string"},
|
|
131
|
-
{"key": "id", "bytes": 4, "type": "unsigned"}
|
|
132
|
-
],
|
|
133
|
-
"message": [
|
|
134
|
-
{"key": "id", "bytes": 4, "type": "unsigned"},
|
|
135
|
-
{"key": "texto", "bytes": 0, "type": "string"}
|
|
136
|
-
],
|
|
137
|
-
"message_response": [
|
|
138
|
-
{"key": "id", "bytes": 4, "type": "unsigned"},
|
|
139
|
-
{"key": "read", "bytes": 1, "type": "bool"}
|
|
140
|
-
],
|
|
141
|
-
"operation": [
|
|
142
|
-
{"key": "id", "bytes": 0, "type": "string"},
|
|
143
|
-
{"key": "section", "bytes": 0, "type": "string"},
|
|
144
|
-
{"key": "key", "bytes": 0, "type": "string"},
|
|
145
|
-
{"key": "value", "bytes": 0, "type": "string"}
|
|
146
|
-
],
|
|
147
|
-
"operation_response": [
|
|
148
|
-
{"key": "id", "bytes": 0, "type": "string"}
|
|
149
|
-
],
|
|
150
|
-
"busstop": [
|
|
151
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
152
|
-
{"key": "orden", "bytes": 1, "type": "unsigned"},
|
|
153
|
-
{"key": "longitud", "bytes": 4, "type": "float", "decimals": 6},
|
|
154
|
-
{"key": "latitud", "bytes": 4, "type": "float", "decimals": 6},
|
|
155
|
-
{"key": "radio", "bytes": 2, "type": "unsigned"},
|
|
156
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
157
|
-
{"keys": ["liquidar", "lado", "terminal", "activo"], "bytes": 1, "type": "flags"},
|
|
158
|
-
{"key": "nombre", "bytes": 14, "type": "string"},
|
|
159
|
-
{"key": "velocidad", "bytes": 1, "type": "unsigned"},
|
|
160
|
-
{"key": "tarifas", "bytes": 0, "type": "array", "array": [
|
|
161
|
-
{"key": "boleto", "bytes": 2, "type": "unsigned"},
|
|
162
|
-
{"key": "fin", "bytes": 2, "type": "unsigned"}
|
|
163
|
-
]},
|
|
164
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
165
|
-
],
|
|
166
|
-
"parameter": [
|
|
167
|
-
{"key": "id", "bytes": 0, "type": "string"},
|
|
168
|
-
{"key": "nombre", "bytes": 0, "type": "string"},
|
|
169
|
-
{"key": "valor", "bytes": 0, "type": "string"}
|
|
170
|
-
],
|
|
171
|
-
"report": [
|
|
172
|
-
{"key": "positions", "bytes": 19, "type": "array", "array": [
|
|
173
|
-
{"key": "time", "bytes": 6, "type": "datetime"},
|
|
174
|
-
{"key": "lng", "bytes": 4, "type": "float", "decimals": 6},
|
|
175
|
-
{"key": "lat", "bytes": 4, "type": "float", "decimals": 6},
|
|
176
|
-
{"key": "speed", "bytes": 1, "type": "unsigned"},
|
|
177
|
-
{"key": "mark", "bytes": 2, "type": "unsigned"},
|
|
178
|
-
{"key": "busstop", "bytes": 2, "type": "unsigned"}
|
|
179
|
-
]},
|
|
180
|
-
{"key": "trip", "bytes": 4, "type": "unsigned"},
|
|
181
|
-
{"key": "route", "bytes": 1, "type": "unsigned"},
|
|
182
|
-
{"key": "direction", "bytes": 1, "type": "bool"},
|
|
183
|
-
{"key": "state", "bytes": 1, "type": "char"},
|
|
184
|
-
{"key": "sales", "bytes": 3, "type": "unsigned"},
|
|
185
|
-
{"key": "events", "bytes": 3, "type": "array", "array": [
|
|
186
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
187
|
-
{"key": "value", "bytes": 1, "type": "unsigned"}
|
|
188
|
-
]}
|
|
189
|
-
],
|
|
190
|
-
"report": {
|
|
191
|
-
"positions": {"bytes": 19,"type": "array",
|
|
192
|
-
"array": {
|
|
193
|
-
"time": {"bytes": 6,"type": "datetime"},
|
|
194
|
-
"lng": {"bytes": 4,"decimals": 6,"type": "float"},
|
|
195
|
-
"lat": {"bytes": 4,"decimals": 6,"type": "float"},
|
|
196
|
-
"speed": {"bytes": 1,"type": "unsigned"},
|
|
197
|
-
"mark": {"bytes": 2,"type": "unsigned"},
|
|
198
|
-
"busstop": {"bytes": 2,"type": "unsigned"}
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
"trip": {"bytes": 4,"type": "unsigned"},
|
|
202
|
-
"route": {"bytes": 1,"type": "unsigned"},
|
|
203
|
-
"direction": {"bytes": 1,"type": "bool"},
|
|
204
|
-
"state": {"bytes": 1,"type": "char"},
|
|
205
|
-
"sales": {"bytes": 3,"type": "unsigned"},
|
|
206
|
-
"events": {"bytes": 3,"type": "array",
|
|
207
|
-
"array": {
|
|
208
|
-
"id": {"bytes": 2,"type": "unsigned"},
|
|
209
|
-
"value": {"bytes": 1,"type": "unsigned"}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
"position_response": [
|
|
214
|
-
{"key": "reportes", "bytes": 1, "type": "unsigned"},
|
|
215
|
-
{"key": "ids", "bytes": 0, "type": "array", "array": [
|
|
216
|
-
{"key": "id", "bytes": 2, "type": "unsigned"}
|
|
217
|
-
]}
|
|
218
|
-
],
|
|
219
|
-
"route": [
|
|
220
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
221
|
-
{"key": "codigo", "bytes": 0, "type": "string"},
|
|
222
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
223
|
-
],
|
|
224
|
-
"trip": [
|
|
225
|
-
{"key": "id", "bytes": 4, "type": "unsigned"},
|
|
226
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
227
|
-
{"key": "lado", "bytes": 1, "type": "bool"},
|
|
228
|
-
{"key": "inicio", "bytes": 6, "type": "datetime"},
|
|
229
|
-
{"key": "estado", "bytes": 1, "type": "char"},
|
|
230
|
-
{"key": "frecuencia", "bytes": 1, "type": "unsigned"},
|
|
231
|
-
{"key": "conductor", "bytes": 4, "type": "unsigned"},
|
|
232
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
233
|
-
{"key": "controles", "bytes": 0, "type": "array", "array": [
|
|
234
|
-
{"key": "geocerca", "bytes": 2, "type": "unsigned"},
|
|
235
|
-
{"key": "tiempo", "bytes": 1, "type": "signed"},
|
|
236
|
-
{"key": "volada", "bytes": 1, "type": "signed"}
|
|
237
|
-
]},
|
|
238
|
-
{"key": "marcados", "bytes": 0, "type": "bits"}
|
|
239
|
-
],
|
|
240
|
-
"settings": [
|
|
241
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
242
|
-
{"key": "nombre", "bytes": 0, "type": "string"},
|
|
243
|
-
{"key": "tipo", "bytes": 0, "type": "string"},
|
|
244
|
-
{"key": "data", "bytes": 0, "type": "string"},
|
|
245
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
246
|
-
],
|
|
247
|
-
"tickets": [
|
|
248
|
-
{"key": "tickets", "bytes": 0, "type": "array", "array": [
|
|
249
|
-
{"key": "boleto", "bytes": 2, "type": "unsigned"},
|
|
250
|
-
{"key": "conductor", "bytes": 2, "type": "unsigned"},
|
|
251
|
-
{"key": "correlativo", "bytes": 4, "type": "unsigned"},
|
|
252
|
-
{"key": "dia", "bytes": 3, "type": "date"},
|
|
253
|
-
{"key": "fin", "bytes": 2, "type": "unsigned"},
|
|
254
|
-
{"key": "hora", "bytes": 6, "type": "datetime"},
|
|
255
|
-
{"key": "inicio", "bytes": 4, "type": "unsigned"},
|
|
256
|
-
{"key": "inspector", "bytes": 2, "type": "unsigned"},
|
|
257
|
-
{"key": "medio_pago", "bytes": 1, "type": "unsigned"},
|
|
258
|
-
{"key": "numero", "bytes": 4, "type": "unsigned"},
|
|
259
|
-
{"key": "precio", "bytes": 2, "type": "unsigned"},
|
|
260
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"},
|
|
261
|
-
{"key": "sesion", "bytes": 4, "type": "unsigned"},
|
|
262
|
-
{"key": "unidad", "bytes": 2, "type": "unsigned"},
|
|
263
|
-
{"key": "tarjeta", "bytes": 0, "type": "string"}
|
|
264
|
-
]}
|
|
265
|
-
],
|
|
266
|
-
"tickets_response": [
|
|
267
|
-
{"key": "tickets", "bytes": 0, "type": "array", "array": [
|
|
268
|
-
{"key": "correlativo", "bytes": 4, "type": "unsigned"},
|
|
269
|
-
{"key": "id", "bytes": 0, "type": "string"}
|
|
270
|
-
]}
|
|
271
|
-
],
|
|
272
|
-
"timestamp": [
|
|
273
|
-
{"key": "timestamp", "bytes": 6, "type": "timestamp"}
|
|
274
|
-
],
|
|
275
|
-
"timestamp_us": [
|
|
276
|
-
{"key": "timestamp", "bytes": 8, "type": "timestamp"}
|
|
277
|
-
],
|
|
278
|
-
"remaining_data": [
|
|
279
|
-
{"key": "faltantes", "bytes": 4, "type": "unsigned"},
|
|
280
|
-
{"key": "tabla", "bytes": 1, "type": "char"}
|
|
281
|
-
],
|
|
282
|
-
"user_route": [
|
|
283
|
-
{"key": "id", "bytes": 2, "type": "unsigned"},
|
|
284
|
-
{"key": "celular", "bytes": 9, "type": "string"},
|
|
285
|
-
{"key": "nombre", "bytes": 14, "type": "string"},
|
|
286
|
-
{"key": "rutas", "bytes": 1, "type": "array", "array": [
|
|
287
|
-
{"key": "ruta", "bytes": 1, "type": "unsigned"}
|
|
288
|
-
]},
|
|
289
|
-
{"key": "timestamp", "bytes": 6, "type": "datetime"}
|
|
290
|
-
]
|
|
291
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|