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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: protobin
3
- Version: 0.0.6
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
- return bool(val).to_bytes(1, 'big', signed=False)
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
- return bool(int.from_bytes(binary, 'big', signed=False))
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 isinstance(val, str):
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.keys = js.get('keys')
254
- self.length = len(self.keys)
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.keys)
268
- for k in self.keys:
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.keys) % 8))
275
- for k in self.keys:
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
- def to_dict(self):
294
- d = super().to_dict()
295
- d['decimals'] = self.decimals
296
- return d
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 isinstance(val, str):
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
- val = 0
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('Negative values not allowed')
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.6"
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
- positions:
3
- bytes: 19
4
- type: array
5
- array:
6
- time:
7
- bytes: 6
8
- type: datetime
9
- lng:
10
- bytes: 4
11
- decimals: 6
12
- type: float
13
- lat:
14
- bytes: 4
15
- decimals: 6
16
- type: float
17
- speed:
18
- bytes: 1
19
- type: unsigned
20
- mark:
21
- bytes: 2
22
- type: unsigned
23
- busstop:
24
- bytes: 2
25
- type: unsigned
26
- trip:
27
- bytes: 4
28
- type: unsigned
29
- route:
30
- bytes: 1
31
- type: unsigned
32
- direction:
33
- bytes: 1
34
- type: bool
35
- state:
36
- bytes: 1
37
- type: char
38
- sales:
39
- bytes: 3
40
- type: unsigned
41
- events:
42
- bytes: 3
43
- type: array
44
- array:
45
- id:
46
- bytes: 2
47
- type: unsigned
48
- value:
49
- bytes: 1
50
- type: unsigned
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': 0,
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': 0,
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': 0,
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': [{'key': 'test', 'bytes': 0, 'type': 'array', 'array': [
117
- {'key': 'test', 'bytes': 0, 'type': 'string'}
118
- ]}],
119
- 'bits': [{'key': 'test', 'type': 'bits'}],
120
- 'bits_fixed': [{'key': 'test', 'type': 'bits', 'length': 7}],
121
- 'bool': [{'key': 'test', 'bytes': 1, 'type': 'bool'}],
122
- 'char': [{'key': 'test', 'bytes': 1, 'type': 'char'}],
123
- 'date': [{'key': 'test', 'bytes': 1, 'type': 'date'}],
124
- 'datetime': [{'key': 'test', 'bytes': 1, 'type': 'datetime'}],
125
- 'flags': [{'keys': ['f1', 'f2', 'f3', 'f4'], 'type': 'flags'}],
126
- 'float': [{'key': 'test', 'bytes': 4, 'decimals': 6, 'type': 'float'}],
127
- 'signed': [{'key': 'test', 'bytes': 2, 'type': 'signed'}],
128
- 'string': [{'key': 'test', 'bytes': 0, 'type': 'string'}],
129
- 'time': [{'key': 'test', 'bytes': 2, 'type': 'time'}],
130
- 'timestamp': [{'key': 'test', 'bytes': 8, 'type': 'timestamp'}],
131
- 'unsigned': [{'key': 'test', 'bytes': 3, 'type': 'unsigned'}]
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, 'array')
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, 'array')
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, 'bits')
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, 'bits')
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, 'bits_fixed')
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, 'bool')
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, 'char')
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, 'date')
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
- recv = self.protocol.decode(binary, 'datetime')
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, 'time')
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, 'flags')
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
- recv = self.protocol.decode(binary, 'float')
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, 'signed')
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, 'unsigned')
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, 'string')
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, 'string')
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, 'timestamp')
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
- protocol = Protocol(file='demo.json')
244
- binary = protocol.encode(DATA, 'report')
245
- recv = protocol.decode(binary, 'report')
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
- protocol = Protocol(file='demo.yaml')
250
- binary = protocol.encode(DATA, 'report')
251
- recv = protocol.decode(binary, 'report')
252
- self.assertEqual(DATA, recv)
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
- {'key': 'id', 'bytes': 1, 'type': 'unsigned'},
257
- {'key': 'nombre', 'type': 'string'},
258
- {'key': 'valor', 'bytes': 2, 'type': 'signed'}
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, 'medida')
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, 'medida')
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)
@@ -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