ents 2.3.4__py3-none-any.whl → 2.3.5__py3-none-any.whl

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.
ents/__init__.py CHANGED
@@ -3,10 +3,11 @@ from .proto.encode import (
3
3
  encode_power_measurement,
4
4
  encode_teros12_measurement,
5
5
  encode_phytos31_measurement,
6
+ encode_user_configuration,
6
7
  encode_bme280_measurement,
7
8
  )
8
9
 
9
- from .proto.decode import decode_response, decode_measurement
10
+ from .proto.decode import decode_response, decode_measurement, decode_user_configuration
10
11
 
11
12
  from .proto.esp32 import encode_esp32command, decode_esp32command
12
13
 
@@ -20,4 +21,6 @@ __all__ = [
20
21
  "decode_measurement",
21
22
  "encode_esp32command",
22
23
  "decode_esp32command",
24
+ "encode_user_configuration",
25
+ "decode_user_configuration",
23
26
  ]
ents/cli.py CHANGED
@@ -29,6 +29,13 @@ from .proto.encode import (
29
29
  from .proto.decode import decode_measurement, decode_response
30
30
  from .proto.esp32 import encode_esp32command, decode_esp32command
31
31
 
32
+ from .proto.sensor import (
33
+ encode_repeated_sensor_measurements,
34
+ decode_repeated_sensor_measurements,
35
+ encode_sensor_response,
36
+ decode_sensor_response,
37
+ )
38
+
32
39
  from .simulator.node import NodeSimulator
33
40
 
34
41
 
@@ -37,17 +44,68 @@ def entry():
37
44
 
38
45
  parser = argparse.ArgumentParser()
39
46
 
40
- subparsers = parser.add_subparsers(help="Ents Utilities")
47
+ subparsers = parser.add_subparsers(help="Ents Utilities", required=True)
41
48
 
42
49
  create_encode_parser(subparsers)
50
+ create_encode_generic_parser(subparsers)
43
51
  create_decode_parser(subparsers)
52
+ create_decode_generic_parser(subparsers)
44
53
  create_calib_parser(subparsers)
45
54
  create_sim_parser(subparsers)
55
+ create_sim_generic_parser(subparsers)
46
56
 
47
57
  args = parser.parse_args()
48
58
  args.func(args)
49
59
 
50
60
 
61
+ def create_sim_generic_parser(subparsers):
62
+ """Creates the generic simulation subparser
63
+
64
+ Args:
65
+ subparsers: Reference to subparser group
66
+ Returns:
67
+ Reference to new subparser
68
+ """
69
+
70
+ sim_p = subparsers.add_parser("sim_generic", help="Simluate generic sensor uploads")
71
+ sim_p.add_argument(
72
+ "--url",
73
+ required=True,
74
+ type=str,
75
+ help="URL of the dirtviz instance (default: http://localhost:8000)",
76
+ )
77
+ sim_p.add_argument(
78
+ "--mode",
79
+ required=True,
80
+ choices=["batch", "stream"],
81
+ type=str,
82
+ help="Upload mode",
83
+ )
84
+ sim_p.add_argument(
85
+ "--sensor",
86
+ required=True,
87
+ type=str,
88
+ nargs="+",
89
+ help="Type of sensor to simulate",
90
+ )
91
+ sim_p.add_argument(
92
+ "--min", type=float, default=-1.0, help="Minimum sensor value (default: -1.0)"
93
+ )
94
+ sim_p.add_argument(
95
+ "--max", type=float, default=1.0, help="Maximum sensor value (default: 1.0)"
96
+ )
97
+ sim_p.add_argument("--cell", required=True, type=int, help="Cell Id")
98
+ sim_p.add_argument("--logger", required=True, type=int, help="Logger Id")
99
+ sim_p.add_argument("--start", type=str, help="Start date")
100
+ sim_p.add_argument("--end", type=str, help="End date")
101
+ sim_p.add_argument(
102
+ "--freq", default=10.0, type=float, help="Frequency of uploads (default: 10s)"
103
+ )
104
+ sim_p.set_defaults(func=simulate_generic)
105
+
106
+ return sim_p
107
+
108
+
51
109
  def create_sim_parser(subparsers):
52
110
  """Creates the simulation subparser
53
111
 
@@ -90,6 +148,49 @@ def create_sim_parser(subparsers):
90
148
  return sim_p
91
149
 
92
150
 
151
+ def simulate_generic(args):
152
+ simulation = NodeSimulator(
153
+ cell=args.cell,
154
+ logger=args.logger,
155
+ sensors=args.sensor,
156
+ _min=args.min,
157
+ _max=args.max,
158
+ )
159
+
160
+ if args.mode == "batch":
161
+ if (args.start is None) or (args.end is None):
162
+ raise ValueError("Start and end date must be provided for batch mode.")
163
+
164
+ # format dates
165
+ curr_dt = datetime.fromisoformat(args.start)
166
+ end_dt = datetime.fromisoformat(args.end)
167
+
168
+ # create list of measurements
169
+ while curr_dt <= end_dt:
170
+ ts = int(curr_dt.timestamp())
171
+ simulation.measure(ts)
172
+ curr_dt += timedelta(seconds=args.freq)
173
+
174
+ # send measurements
175
+ while simulation.send_next(args.url):
176
+ print(simulation)
177
+
178
+ print("Done!")
179
+
180
+ elif args.mode == "stream":
181
+ print("Use CTRL+C to stop the simulation")
182
+ try:
183
+ while True:
184
+ dt = datetime.now()
185
+ ts = int(dt.timestamp())
186
+ simulation.measure(ts)
187
+ while simulation.send_next(args.url):
188
+ print(simulation)
189
+ time.sleep(args.freq)
190
+ except KeyboardInterrupt as _:
191
+ print("Stopping simulation")
192
+
193
+
93
194
  def simulate(args):
94
195
  simulation = NodeSimulator(
95
196
  cell=args.cell,
@@ -169,6 +270,133 @@ def create_calib_parser(subparsers):
169
270
  return calib_p
170
271
 
171
272
 
273
+ def create_encode_generic_parser(subparsers):
274
+ """Create generic encode command subparser
275
+
276
+ Args:
277
+ subparsers: Reference to subparser group
278
+
279
+ Returns:
280
+ Reference to new subparser
281
+ """
282
+
283
+ encode_parser = subparsers.add_parser("encode_generic", help="Encode generic data")
284
+
285
+ print_format = encode_parser.add_mutually_exclusive_group()
286
+ print_format.add_argument(
287
+ "--hex", action="store_true", help="Print as hex values (default)"
288
+ )
289
+ print_format.add_argument(
290
+ "--raw", action="store_true", help="Print raw bytes object"
291
+ )
292
+ print_format.add_argument(
293
+ "--c", action="store_true", help="Print bytes for copying to c"
294
+ )
295
+
296
+ encode_subparsers = encode_parser.add_subparsers(
297
+ title="Message type", dest="type", required=True
298
+ )
299
+
300
+ # sensor measurement
301
+ measurement_parser = encode_subparsers.add_parser(
302
+ "meas", help='Proto "Measurement" message'
303
+ )
304
+ measurement_parser.add_argument("--ts", type=int, help="Unix epoch timestamp")
305
+ measurement_parser.add_argument("--cell", type=int, help="Cell Id")
306
+ measurement_parser.add_argument("--logger", type=int, help="Logger Id")
307
+ measurement_parser.add_argument("--idx", type=int, default=1, help="Upload index")
308
+ measurement_parser.add_argument(
309
+ "--sensor",
310
+ nargs=2,
311
+ metavar=("type", "value"),
312
+ action="append",
313
+ required=True,
314
+ help="Specify as: --sensor <type> <value>",
315
+ )
316
+ measurement_parser.set_defaults(func=handle_encode_generic_measurement)
317
+
318
+ # response
319
+ response_parser = encode_subparsers.add_parser(
320
+ "resp", help='Proto "Response" message'
321
+ )
322
+ response_parser.add_argument(
323
+ "--resp",
324
+ nargs=2,
325
+ metavar=("idx", "status"),
326
+ action="append",
327
+ required=True,
328
+ help="Specify as: --resp <idx> <status>",
329
+ )
330
+ response_parser.set_defaults(func=handle_encode_generic_response)
331
+
332
+ return encode_parser
333
+
334
+
335
+ def parse_number(s: str) -> tuple:
336
+ try:
337
+ i = int(s)
338
+ if i >= 0:
339
+ return i, "unsignedInt"
340
+ return i, "signedInt"
341
+ except ValueError:
342
+ pass
343
+
344
+ try:
345
+ return float(s), "decimal"
346
+ except ValueError:
347
+ pass
348
+
349
+ raise ValueError(f"Invalid numeric value: {s}")
350
+
351
+
352
+ def handle_encode_generic_measurement(args):
353
+ """Take arguments and encode a repeated senosr measurement message"""
354
+
355
+ meas = {
356
+ "meta": {
357
+ "ts": args.ts,
358
+ "cellId": args.cell,
359
+ "loggerId": args.logger,
360
+ },
361
+ "measurements": [],
362
+ }
363
+
364
+ for s in args.sensor:
365
+ val, val_type = parse_number(s[1])
366
+ meas["measurements"].append(
367
+ {
368
+ "type": s[0],
369
+ val_type: val,
370
+ "idx": args.idx,
371
+ }
372
+ )
373
+ args.idx += 1
374
+
375
+ data = encode_repeated_sensor_measurements(meas)
376
+ print_data(args, data)
377
+
378
+
379
+ def handle_encode_generic_response(args):
380
+ """Takes arguments and encode a sensor response message"""
381
+
382
+ resp = {
383
+ "responses": [],
384
+ }
385
+
386
+ for r in args.resp:
387
+ idx = int(r[0])
388
+ status = r[1]
389
+ resp["responses"].append(
390
+ {
391
+ "uploadIndex": idx,
392
+ "status": status,
393
+ }
394
+ )
395
+
396
+ data = encode_sensor_response(resp)
397
+ print_data(args, data)
398
+
399
+
172
400
  def create_encode_parser(subparsers):
173
401
  """Create encode command subparser
174
402
 
@@ -192,14 +420,19 @@ def create_encode_parser(subparsers):
192
420
  "--c", action="store_true", help="Print bytes for copying to c"
193
421
  )
194
422
 
195
- encode_subparsers = encode_parser.add_subparsers(title="Message type", dest="type")
423
+ encode_subparsers = encode_parser.add_subparsers(
424
+ title="Message type",
425
+ dest="type",
426
+ required=True,
427
+ )
196
428
 
197
429
  def create_measurement_parser(encode_subparsers):
198
430
  measurement_parser = encode_subparsers.add_parser(
199
431
  "measurement", help='Proto "Measurement" message'
200
432
  )
201
433
  measurement_subparser = measurement_parser.add_subparsers(
202
- title="Measurement type"
434
+ title="Measurement type",
435
+ required=True,
203
436
  )
204
437
 
205
438
  # metadata
@@ -246,7 +479,9 @@ def create_encode_parser(subparsers):
246
479
  "esp32command", help='Proto "Esp32Command" message'
247
480
  )
248
481
  esp32command_subparser = esp32command_parser.add_subparsers(
249
- title="type", help="PageCommand"
482
+ title="type",
483
+ help="PageCommand",
484
+ required=True,
250
485
  )
251
486
 
252
487
  test_parser = esp32command_subparser.add_parser("test", help="TestCommand")
@@ -383,6 +618,55 @@ def print_bytes_c(data: bytes) -> str:
383
618
  print(f"size_t data_len = {len(hex_str)};")
384
619
 
385
620
 
621
+ def create_decode_generic_parser(subparsers):
622
+ """Create generic decode command parser
623
+
624
+ Args:
625
+ subparsers: Reference to subparser group
626
+
627
+ Returns:
628
+ Reference to new subparser
629
+ """
630
+
631
+ decode_parser = subparsers.add_parser("decode_generic", help="Decode generic data")
632
+
633
+ decode_subparsers = decode_parser.add_subparsers(
634
+ title="Message type",
635
+ dest="type",
636
+ required=True,
637
+ )
638
+
639
+ decode_parser.add_argument(
640
+ "data", type=str, help="Protobuf serialized data in hex format"
641
+ )
642
+
643
+ # sensor measurement
644
+ measurement_parser = decode_subparsers.add_parser(
645
+ "meas", help='Proto "Measurement" message'
646
+ )
647
+ measurement_parser.set_defaults(func=handle_decode_generic_measurement)
648
+
649
+ # response
650
+ response_parser = decode_subparsers.add_parser(
651
+ "resp", help='Proto "Response" message'
652
+ )
653
+ response_parser.set_defaults(func=handle_decode_generic_response)
654
+
655
+ return decode_parser
656
+
657
+
658
+ def handle_decode_generic_measurement(args):
659
+ data = bytes.fromhex(args.data)
660
+ vals = decode_repeated_sensor_measurements(data)
661
+ print(vals)
662
+
663
+
664
+ def handle_decode_generic_response(args):
665
+ data = bytes.fromhex(args.data)
666
+ vals = decode_sensor_response(data)
667
+ print(vals)
668
+
669
+
386
670
  def create_decode_parser(subparsers):
387
671
  """Create decode command parser
388
672
 
@@ -395,7 +679,11 @@ def create_decode_parser(subparsers):
395
679
 
396
680
  decode_parser = subparsers.add_parser("decode", help="Decode data")
397
681
 
398
- decode_subparsers = decode_parser.add_subparsers(title="Message type", dest="type")
682
+ decode_subparsers = decode_parser.add_subparsers(
683
+ title="Message type",
684
+ dest="type",
685
+ required=True,
686
+ )
399
687
 
400
688
  # measurement
401
689
  measurement_parser = decode_subparsers.add_parser(
@@ -24,10 +24,7 @@ import sys
24
24
  import serial
25
25
  import serial.tools.list_ports
26
26
  import re # For validating URL input
27
- from ents.proto import (
28
- encode_user_configuration,
29
- decode_user_configuration,
30
- )
27
+ from ..proto import encode_user_configuration, decode_user_configuration
31
28
 
32
29
 
33
30
  class Ui_MainWindow(object):
ents/proto/sensor.py ADDED
@@ -0,0 +1,290 @@
1
+ """Module for sensor measurements
2
+
3
+ Encode/decoding functions are wrappers around the protobuf messages. These take
4
+ in the json dictionary format of the messages and return serialized byte
5
+ arrays.
6
+
7
+ Format/parse functions implement the protocol for repeated sensor measurements.
8
+ These take in a list of measurements and automatically optimize repeated
9
+ metadata fields.
10
+ """
11
+
12
+ from google.protobuf.json_format import MessageToDict, ParseDict
13
+
14
+ from .sensor_pb2 import (
15
+ SensorMeasurement,
16
+ RepeatedSensorMeasurements,
17
+ SensorType,
18
+ RepeatedSensorResponses,
19
+ )
20
+
21
+
22
+ def parse_sensor_measurement(data: bytes) -> list:
23
+ """Parses a sensor measurement into a usable dictionary.
24
+
25
+ Function does the following:
26
+ 1. Decodes the serialized byte array
27
+ 2. Updates metadata for each measurement if missing
28
+ 3. Adds names, descriptions, and units to metadata
29
+
30
+ Args:
31
+ data: Byte array of message.
32
+
33
+ Returns:
34
+ Dictionary of sensor measurement.
35
+ """
36
+
37
+ meas = decode_repeated_sensor_measurements(data)
38
+ meas = update_repeated_metadata(meas)
39
+ for m in meas["measurements"]:
40
+ sensor_data = get_sensor_data(m["type"])
41
+ m.update(sensor_data)
42
+
43
+ return meas
44
+
45
+
46
+ def format_sensor_measurement(meas: list) -> bytes:
47
+ """Formats a sensor measurement dictionary into a serialized byte array.
48
+
49
+ Function does the following:
50
+ 1. Uses top level metadata for duplicate measurement metadata fields
51
+ 2. Encodes the dictionary into a serialized byte array
52
+
53
+ Args:
54
+ meas: Dictionary of sensor measurement.
55
+
56
+ Returns:
57
+ Byte array of serialized message.
58
+ """
59
+
60
+ # TODO Implement optimization of repeated metadata fields
61
+ meas_dict = {
62
+ "measurements": meas,
63
+ }
64
+
65
+ data = encode_repeated_sensor_measurements(meas_dict)
66
+ return data
67
+
68
+
69
+ def get_sensor_data(meas_type: int) -> dict:
70
+ """Gets sensor data information.
71
+
72
+ Args:
73
+ meas_type: Sensor measurement dictionary.
74
+
75
+ Returns:
76
+ Metadata associated with the sensor type.
77
+ """
78
+
79
+ SENSOR_DATA = {
80
+ SensorType.POWER_VOLTAGE: {
81
+ "name": "Voltage",
82
+ "unit": "mV",
83
+ },
84
+ SensorType.POWER_CURRENT: {
85
+ "name": "Current",
86
+ "unit": "uA",
87
+ },
88
+ SensorType.TEROS12_VWC: {
89
+ "name": "Volumetric Water Content",
90
+ "unit": "%",
91
+ },
92
+ SensorType.TEROS12_TEMP: {
93
+ "name": "Temperature",
94
+ "unit": "C",
95
+ },
96
+ SensorType.TEROS12_EC: {
97
+ "name": "Electrical Conductivity",
98
+ "unit": "uS/cm",
99
+ },
100
+ SensorType.PHYTOS31_VOLTAGE: {
101
+ "name": "Voltage",
102
+ "unit": "mV",
103
+ },
104
+ SensorType.PHYTOS31_LEAF_WETNESS: {
105
+ "name": "Leaf Wetness",
106
+ "unit": "%",
107
+ },
108
+ SensorType.BME280_PRESSURE: {
109
+ "name": "Pressure",
110
+ "unit": "kPa",
111
+ },
112
+ SensorType.BME280_TEMP: {
113
+ "name": "Temperature",
114
+ "unit": "C",
115
+ },
116
+ SensorType.BME280_HUMIDITY: {
117
+ "name": "Humidity",
118
+ "unit": "%",
119
+ },
120
+ SensorType.TEROS21_MATRIC_POT: {
121
+ "name": "Matric Potential",
122
+ "unit": "kPa",
123
+ },
124
+ SensorType.TEROS21_TEMP: {
125
+ "name": "Temperature",
126
+ "unit": "C",
127
+ },
128
+ SensorType.SEN0308_VOLTAGE: {
129
+ "name": "Voltage",
130
+ "unit": "mV",
131
+ },
132
+ SensorType.SEN0308_HUMIDITY: {
133
+ "name": "Humidity",
134
+ "unit": "%",
135
+ },
136
+ SensorType.SEN0257_VOLTAGE: {
137
+ "name": "Voltage",
138
+ "unit": "mV",
139
+ },
140
+ SensorType.SEN0257_PRESSURE: {
141
+ "name": "Pressure",
142
+ "unit": "kPa",
143
+ },
144
+ SensorType.YFS210C_FLOW: {
145
+ "name": "Flow Rate",
146
+ "unit": "L/min",
147
+ },
148
+ }
149
+
150
+ meta = SENSOR_DATA[SensorType.Value(meas_type)]
151
+ return meta
152
+
153
+
154
+ def encode_sensor_measurement(meas_dict: dict) -> bytes:
155
+ meas = SensorMeasurement()
156
+ ParseDict(meas_dict, meas)
157
+
158
+ return meas.SerializeToString()
159
+
160
+
161
+ def encode_repeated_sensor_measurements(meas_dict: dict) -> bytes:
162
+ """Encodes a SensorMeasurement message
163
+
164
+ Args:
165
+ rep_meas: Repeated sensor measurement dictionary.
166
+
167
+ Returns:
168
+ Byte array of encoded RepeatedSensorMeasurements message.
169
+ """
170
+
171
+ meas = RepeatedSensorMeasurements()
172
+ ParseDict(meas_dict, meas)
173
+
174
+ return meas.SerializeToString()
175
+
176
+
177
+ def decode_sensor_measurement(data: bytes) -> dict:
178
+ """Decodes a SensorMeasurement message
179
+
180
+ Args:
181
+ data: Byte array of SensorMeasurement message.
182
+
183
+ Returns:
184
+ Decoded sensor measurement dictionary.
185
+ """
186
+
187
+ meas = SensorMeasurement()
188
+ meas.ParseFromString(data)
189
+
190
+ parsed_meas = MessageToDict(meas)
191
+
192
+ return parsed_meas
193
+
194
+
195
+ def decode_repeated_sensor_measurements(data: bytes) -> dict:
196
+ """Decodes repeated sensor measurements
197
+
198
+ Args:
199
+ data: Byte array from RepeatedSensorMeasurements
200
+
201
+ Returns:
202
+ List of decoded sensor measurement dictionaries.
203
+ """
204
+
205
+ rep_meas = RepeatedSensorMeasurements()
206
+ rep_meas.ParseFromString(data)
207
+ return MessageToDict(rep_meas)
208
+
209
+
210
+ def update_repeated_metadata(meas: dict) -> dict:
211
+ """Ensures every measurements has metadata field set.
212
+
213
+ If a measurement is missing the metadata field, it is filled in from the
214
+ repeated sensor measurement. Existing measurement metadata fields are not
215
+ overwritten.
216
+
217
+ Args:
218
+ meas: Sensor measurement dictionary.
219
+
220
+ Returns:
221
+ Updated sensor measurement dictionary.
222
+ """
223
+
224
+ # if top level meta does not exist, ensure all measurements have meta
225
+ if "meta" not in meas:
226
+ for m in meas["measurements"]:
227
+ if "meta" not in m:
228
+ raise ValueError("Repeated measurement missing metadata field.")
229
+ # otherwise populate missing measurement meta from top level
230
+ else:
231
+ for m in meas["measurements"]:
232
+ if "meta" not in m:
233
+ m["meta"] = meas["meta"]
234
+ del meas["meta"]
235
+
236
+ return meas
237
+
238
+
239
+ def encode_sensor_response(resp_dict: dict) -> bytes:
240
+ """Encodes a sensor response message.
241
+
242
+ {
243
+ responses: [
244
+ {
245
+ status: int,
246
+ message: str,
247
+ },
248
+ ...
249
+ ]
250
+ }
251
+
252
+ Args:
253
+ resp_dict: Sensor response dictionary.
254
+
255
+ Returns:
256
+ Byte array of encoded SensorResponse message.
257
+ """
258
+
259
+ resp = RepeatedSensorResponses()
260
+ ParseDict(resp_dict, resp)
261
+
262
+ return resp.SerializeToString()
263
+
264
+
265
+ def decode_sensor_response(data: bytes) -> dict:
266
+ """Decodes a sensor response message.
267
+
268
+ {
269
+ responses: [
270
+ {
271
+ status: int,
272
+ message: str,
273
+ },
274
+ ...
275
+ ]
276
+ }
277
+
278
+ Args:
279
+ data: Byte array of SensorResponse message.
280
+
281
+ Returns:
282
+ Decoded sensor response dictionary.
283
+ """
284
+
285
+ resp = RepeatedSensorResponses()
286
+ resp.ParseFromString(data)
287
+
288
+ parsed_resp = MessageToDict(resp)
289
+
290
+ return parsed_resp
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: sensor.proto
5
+ # Protobuf Python Version: 6.33.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 33,
16
+ 1,
17
+ '',
18
+ 'sensor.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+
26
+
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0csensor.proto\":\n\x08Metadata\x12\x0f\n\x07\x63\x65ll_id\x18\x01 \x01(\r\x12\x11\n\tlogger_id\x18\x02 \x01(\r\x12\n\n\x02ts\x18\x03 \x01(\r\":\n\x0eSensorResponse\x12\x0b\n\x03idx\x18\x01 \x01(\r\x12\x1b\n\x05\x65rror\x18\x02 \x01(\x0e\x32\x0c.SensorError\"=\n\x17RepeatedSensorResponses\x12\"\n\tresponses\x18\x01 \x03(\x0b\x32\x0f.SensorResponse\"\x9e\x01\n\x11SensorMeasurement\x12\x17\n\x04meta\x18\x01 \x01(\x0b\x32\t.Metadata\x12\x19\n\x04type\x18\x02 \x01(\x0e\x32\x0b.SensorType\x12\x16\n\x0cunsigned_int\x18\x03 \x01(\rH\x00\x12\x14\n\nsigned_int\x18\x04 \x01(\x05H\x00\x12\x11\n\x07\x64\x65\x63imal\x18\x05 \x01(\x01H\x00\x12\x0b\n\x03idx\x18\x06 \x01(\rB\x07\n\x05value\"z\n\x1aRepeatedSensorMeasurements\x12\x17\n\x04meta\x18\x01 \x01(\x0b\x32\t.Metadata\x12\x19\n\x04type\x18\x02 \x01(\x0e\x32\x0b.SensorType\x12(\n\x0cmeasurements\x18\x03 \x03(\x0b\x32\x12.SensorMeasurement*\x9a\x03\n\nSensorType\x12\x08\n\x04NONE\x10\x00\x12\x11\n\rPOWER_VOLTAGE\x10\x01\x12\x11\n\rPOWER_CURRENT\x10\x02\x12\x0f\n\x0bTEROS12_VWC\x10\x03\x12\x13\n\x0fTEROS12_VWC_ADJ\x10\x04\x12\x10\n\x0cTEROS12_TEMP\x10\x05\x12\x0e\n\nTEROS12_EC\x10\x06\x12\x14\n\x10PHYTOS31_VOLTAGE\x10\x07\x12\x19\n\x15PHYTOS31_LEAF_WETNESS\x10\x08\x12\x13\n\x0f\x42ME280_PRESSURE\x10\t\x12\x0f\n\x0b\x42ME280_TEMP\x10\n\x12\x13\n\x0f\x42ME280_HUMIDITY\x10\x0b\x12\x16\n\x12TEROS21_MATRIC_POT\x10\x0c\x12\x10\n\x0cTEROS21_TEMP\x10\r\x12\x13\n\x0fSEN0308_VOLTAGE\x10\x0e\x12\x14\n\x10SEN0308_HUMIDITY\x10\x0f\x12\x13\n\x0fSEN0257_VOLTAGE\x10\x10\x12\x14\n\x10SEN0257_PRESSURE\x10\x11\x12\x10\n\x0cYFS210C_FLOW\x10\x12\x12\x16\n\x12PCAP02_CAPACITANCE\x10\x13*b\n\x0bSensorError\x12\x06\n\x02OK\x10\x00\x12\x0b\n\x07GENERAL\x10\x01\x12\n\n\x06LOGGER\x10\x02\x12\x08\n\x04\x43\x45LL\x10\x03\x12\x0f\n\x0bUNSUPPORTED\x10\x04\x12\x0b\n\x07INVALID\x10\x05\x12\n\n\x06\x44\x45\x43ODE\x10\x06\x62\x06proto3')
28
+
29
+ _globals = globals()
30
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'sensor_pb2', _globals)
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ DESCRIPTOR._loaded_options = None
34
+ _globals['_SENSORTYPE']._serialized_start=485
35
+ _globals['_SENSORTYPE']._serialized_end=895
36
+ _globals['_SENSORERROR']._serialized_start=897
37
+ _globals['_SENSORERROR']._serialized_end=995
38
+ _globals['_METADATA']._serialized_start=16
39
+ _globals['_METADATA']._serialized_end=74
40
+ _globals['_SENSORRESPONSE']._serialized_start=76
41
+ _globals['_SENSORRESPONSE']._serialized_end=134
42
+ _globals['_REPEATEDSENSORRESPONSES']._serialized_start=136
43
+ _globals['_REPEATEDSENSORRESPONSES']._serialized_end=197
44
+ _globals['_SENSORMEASUREMENT']._serialized_start=200
45
+ _globals['_SENSORMEASUREMENT']._serialized_end=358
46
+ _globals['_REPEATEDSENSORMEASUREMENTS']._serialized_start=360
47
+ _globals['_REPEATEDSENSORMEASUREMENTS']._serialized_end=482
48
+ # @@protoc_insertion_point(module_scope)
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: soil_power_sensor.proto
5
- # Protobuf Python Version: 6.31.1
5
+ # Protobuf Python Version: 6.33.1
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -12,7 +12,7 @@ from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
14
  6,
15
- 31,
15
+ 33,
16
16
  1,
17
17
  '',
18
18
  'soil_power_sensor.proto'
@@ -24,67 +24,95 @@ _sym_db = _symbol_database.Default()
24
24
 
25
25
 
26
26
 
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17soil_power_sensor.proto\"E\n\x13MeasurementMetadata\x12\x0f\n\x07\x63\x65ll_id\x18\x01 \x01(\r\x12\x11\n\tlogger_id\x18\x02 \x01(\r\x12\n\n\x02ts\x18\x03 \x01(\r\"4\n\x10PowerMeasurement\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x01\"P\n\x12Teros12Measurement\x12\x0f\n\x07vwc_raw\x18\x02 \x01(\x01\x12\x0f\n\x07vwc_adj\x18\x03 \x01(\x01\x12\x0c\n\x04temp\x18\x04 \x01(\x01\x12\n\n\x02\x65\x63\x18\x05 \x01(\r\"6\n\x12Teros21Measurement\x12\x12\n\nmatric_pot\x18\x01 \x01(\x01\x12\x0c\n\x04temp\x18\x02 \x01(\x01\"<\n\x13Phytos31Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x14\n\x0cleaf_wetness\x18\x02 \x01(\x01\"L\n\x11\x42ME280Measurement\x12\x10\n\x08pressure\x18\x01 \x01(\r\x12\x13\n\x0btemperature\x18\x02 \x01(\x05\x12\x10\n\x08humidity\x18\x03 \x01(\r\"7\n\x12SEN0308Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x10\n\x08humidity\x18\x02 \x01(\x01\"7\n\x12SEN0257Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x10\n\x08pressure\x18\x02 \x01(\x01\"\"\n\x12YFS210CMeasurement\x12\x0c\n\x04\x66low\x18\x01 \x01(\x01\"\xfc\x02\n\x0bMeasurement\x12\"\n\x04meta\x18\x01 \x01(\x0b\x32\x14.MeasurementMetadata\x12\"\n\x05power\x18\x02 \x01(\x0b\x32\x11.PowerMeasurementH\x00\x12&\n\x07teros12\x18\x03 \x01(\x0b\x32\x13.Teros12MeasurementH\x00\x12(\n\x08phytos31\x18\x04 \x01(\x0b\x32\x14.Phytos31MeasurementH\x00\x12$\n\x06\x62me280\x18\x05 \x01(\x0b\x32\x12.BME280MeasurementH\x00\x12&\n\x07teros21\x18\x06 \x01(\x0b\x32\x13.Teros21MeasurementH\x00\x12&\n\x07sen0308\x18\x07 \x01(\x0b\x32\x13.SEN0308MeasurementH\x00\x12&\n\x07sen0257\x18\x08 \x01(\x0b\x32\x13.SEN0257MeasurementH\x00\x12&\n\x07yfs210c\x18\t \x01(\x0b\x32\x13.YFS210CMeasurementH\x00\x42\r\n\x0bmeasurement\"X\n\x08Response\x12$\n\x04resp\x18\x01 \x01(\x0e\x32\x16.Response.ResponseType\"&\n\x0cResponseType\x12\x0b\n\x07SUCCESS\x10\x00\x12\t\n\x05\x45RROR\x10\x01\"\xe9\x01\n\x0c\x45sp32Command\x12$\n\x0cpage_command\x18\x01 \x01(\x0b\x32\x0c.PageCommandH\x00\x12$\n\x0ctest_command\x18\x02 \x01(\x0b\x32\x0c.TestCommandH\x00\x12$\n\x0cwifi_command\x18\x03 \x01(\x0b\x32\x0c.WiFiCommandH\x00\x12*\n\x0fmicrosd_command\x18\x04 \x01(\x0b\x32\x0f.MicroSDCommandH\x00\x12\x30\n\x12irrigation_command\x18\x05 \x01(\x0b\x32\x12.IrrigationCommandH\x00\x42\t\n\x07\x63ommand\"\xb6\x01\n\x0bPageCommand\x12.\n\x0c\x66ile_request\x18\x01 \x01(\x0e\x32\x18.PageCommand.RequestType\x12\x17\n\x0f\x66ile_descriptor\x18\x02 \x01(\r\x12\x12\n\nblock_size\x18\x03 \x01(\r\x12\x11\n\tnum_bytes\x18\x04 \x01(\r\"7\n\x0bRequestType\x12\x08\n\x04OPEN\x10\x00\x12\t\n\x05\x43LOSE\x10\x01\x12\x08\n\x04READ\x10\x02\x12\t\n\x05WRITE\x10\x03\"\x82\x01\n\x0bTestCommand\x12\'\n\x05state\x18\x01 \x01(\x0e\x32\x18.TestCommand.ChangeState\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x05\"<\n\x0b\x43hangeState\x12\x0b\n\x07RECEIVE\x10\x00\x12\x13\n\x0fRECEIVE_REQUEST\x10\x01\x12\x0b\n\x07REQUEST\x10\x02\"\xfe\x01\n\x0bWiFiCommand\x12\x1f\n\x04type\x18\x01 \x01(\x0e\x32\x11.WiFiCommand.Type\x12\x0c\n\x04ssid\x18\x02 \x01(\t\x12\x0e\n\x06passwd\x18\x03 \x01(\t\x12\x0b\n\x03url\x18\x04 \x01(\t\x12\x0c\n\x04port\x18\x08 \x01(\r\x12\n\n\x02rc\x18\x05 \x01(\r\x12\n\n\x02ts\x18\x06 \x01(\r\x12\x0c\n\x04resp\x18\x07 \x01(\x0c\"o\n\x04Type\x12\x0b\n\x07\x43ONNECT\x10\x00\x12\x08\n\x04POST\x10\x01\x12\t\n\x05\x43HECK\x10\x02\x12\x08\n\x04TIME\x10\x03\x12\x0e\n\nDISCONNECT\x10\x04\x12\x0e\n\nCHECK_WIFI\x10\x05\x12\r\n\tCHECK_API\x10\x06\x12\x0c\n\x08NTP_SYNC\x10\x07\"\x86\x03\n\x0eMicroSDCommand\x12\"\n\x04type\x18\x01 \x01(\x0e\x32\x14.MicroSDCommand.Type\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\x12&\n\x02rc\x18\x03 \x01(\x0e\x32\x1a.MicroSDCommand.ReturnCode\x12\x1c\n\x04meas\x18\x04 \x01(\x0b\x32\x0c.MeasurementH\x00\x12 \n\x02uc\x18\x05 \x01(\x0b\x32\x12.UserConfigurationH\x00\" \n\x04Type\x12\x08\n\x04SAVE\x10\x00\x12\x0e\n\nUSERCONFIG\x10\x01\"\xab\x01\n\nReturnCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x11\n\rERROR_GENERAL\x10\x01\x12\x1e\n\x1a\x45RROR_MICROSD_NOT_INSERTED\x10\x02\x12#\n\x1f\x45RROR_FILE_SYSTEM_NOT_MOUNTABLE\x10\x03\x12\x1d\n\x19\x45RROR_PAYLOAD_NOT_DECODED\x10\x04\x12\x19\n\x15\x45RROR_FILE_NOT_OPENED\x10\x05\x42\x06\n\x04\x64\x61ta\"\x94\x01\n\x11IrrigationCommand\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.IrrigationCommand.Type\x12\'\n\x05state\x18\x02 \x01(\x0e\x32\x18.IrrigationCommand.State\"\x11\n\x04Type\x12\t\n\x05\x43HECK\x10\x00\"\x1c\n\x05State\x12\x08\n\x04OPEN\x10\x00\x12\t\n\x05\x43LOSE\x10\x01\"\xdc\x02\n\x11UserConfiguration\x12\x11\n\tlogger_id\x18\x01 \x01(\r\x12\x0f\n\x07\x63\x65ll_id\x18\x02 \x01(\r\x12$\n\rUpload_method\x18\x03 \x01(\x0e\x32\r.Uploadmethod\x12\x17\n\x0fUpload_interval\x18\x04 \x01(\r\x12\'\n\x0f\x65nabled_sensors\x18\x05 \x03(\x0e\x32\x0e.EnabledSensor\x12\x15\n\rVoltage_Slope\x18\x06 \x01(\x01\x12\x16\n\x0eVoltage_Offset\x18\x07 \x01(\x01\x12\x15\n\rCurrent_Slope\x18\x08 \x01(\x01\x12\x16\n\x0e\x43urrent_Offset\x18\t \x01(\x01\x12\x11\n\tWiFi_SSID\x18\n \x01(\t\x12\x15\n\rWiFi_Password\x18\x0b \x01(\t\x12\x18\n\x10\x41PI_Endpoint_URL\x18\x0c \x01(\t\x12\x19\n\x11\x41PI_Endpoint_Port\x18\r \x01(\r*O\n\rEnabledSensor\x12\x0b\n\x07Voltage\x10\x00\x12\x0b\n\x07\x43urrent\x10\x01\x12\x0b\n\x07Teros12\x10\x02\x12\x0b\n\x07Teros21\x10\x03\x12\n\n\x06\x42ME280\x10\x04*\"\n\x0cUploadmethod\x12\x08\n\x04LoRa\x10\x00\x12\x08\n\x04WiFi\x10\x01\x62\x06proto3')
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17soil_power_sensor.proto\"E\n\x13MeasurementMetadata\x12\x0f\n\x07\x63\x65ll_id\x18\x01 \x01(\r\x12\x11\n\tlogger_id\x18\x02 \x01(\r\x12\n\n\x02ts\x18\x03 \x01(\r\"4\n\x10PowerMeasurement\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x01\"*\n\x17VoltageDeltaMeasurement\x12\x0f\n\x07voltage\x18\x01 \x01(\r\"*\n\x17\x43urrentDeltaMeasurement\x12\x0f\n\x07\x63urrent\x18\x01 \x01(\r\"%\n\x12VoltageMeasurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\"%\n\x12\x43urrentMeasurement\x12\x0f\n\x07\x63urrent\x18\x01 \x01(\x01\"K\n\x0fPowerDeltaEntry\x12\n\n\x02ts\x18\x01 \x01(\r\x12\x15\n\rvoltage_delta\x18\x02 \x01(\r\x12\x15\n\rcurrent_delta\x18\x03 \x01(\r\"E\n\x15PowerMeasurementDelta\x12\x15\n\rvoltage_delta\x18\x02 \x01(\r\x12\x15\n\rcurrent_delta\x18\x03 \x01(\r\"\\\n\x13RepeatedPowerDeltas\x12\x11\n\tlogger_id\x18\x01 \x01(\r\x12\x0f\n\x07\x63\x65ll_id\x18\x02 \x01(\r\x12!\n\x07\x65ntries\x18\x03 \x03(\x0b\x32\x10.PowerDeltaEntry\"P\n\x12Teros12Measurement\x12\x0f\n\x07vwc_raw\x18\x02 \x01(\x01\x12\x0f\n\x07vwc_adj\x18\x03 \x01(\x01\x12\x0c\n\x04temp\x18\x04 \x01(\x01\x12\n\n\x02\x65\x63\x18\x05 \x01(\r\"6\n\x12Teros21Measurement\x12\x12\n\nmatric_pot\x18\x01 \x01(\x01\x12\x0c\n\x04temp\x18\x02 \x01(\x01\"<\n\x13Phytos31Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x14\n\x0cleaf_wetness\x18\x02 \x01(\x01\"L\n\x11\x42ME280Measurement\x12\x10\n\x08pressure\x18\x01 \x01(\r\x12\x13\n\x0btemperature\x18\x02 \x01(\x05\x12\x10\n\x08humidity\x18\x03 \x01(\r\"7\n\x12SEN0308Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x10\n\x08humidity\x18\x02 \x01(\x01\"7\n\x12SEN0257Measurement\x12\x0f\n\x07voltage\x18\x01 \x01(\x01\x12\x10\n\x08pressure\x18\x02 \x01(\x01\"\"\n\x12YFS210CMeasurement\x12\x0c\n\x04\x66low\x18\x01 \x01(\x01\"(\n\x11PCAP02Measurement\x12\x13\n\x0b\x63\x61pacitance\x18\x01 \x01(\x01\"\xa2\x03\n\x0bMeasurement\x12\"\n\x04meta\x18\x01 \x01(\x0b\x32\x14.MeasurementMetadata\x12\"\n\x05power\x18\x02 \x01(\x0b\x32\x11.PowerMeasurementH\x00\x12&\n\x07teros12\x18\x03 \x01(\x0b\x32\x13.Teros12MeasurementH\x00\x12(\n\x08phytos31\x18\x04 \x01(\x0b\x32\x14.Phytos31MeasurementH\x00\x12$\n\x06\x62me280\x18\x05 \x01(\x0b\x32\x12.BME280MeasurementH\x00\x12&\n\x07teros21\x18\x06 \x01(\x0b\x32\x13.Teros21MeasurementH\x00\x12&\n\x07sen0308\x18\x07 \x01(\x0b\x32\x13.SEN0308MeasurementH\x00\x12&\n\x07sen0257\x18\x08 \x01(\x0b\x32\x13.SEN0257MeasurementH\x00\x12&\n\x07yfs210c\x18\t \x01(\x0b\x32\x13.YFS210CMeasurementH\x00\x12$\n\x06pcap02\x18\n \x01(\x0b\x32\x12.PCAP02MeasurementH\x00\x42\r\n\x0bmeasurement\"X\n\x08Response\x12$\n\x04resp\x18\x01 \x01(\x0e\x32\x16.Response.ResponseType\"&\n\x0cResponseType\x12\x0b\n\x07SUCCESS\x10\x00\x12\t\n\x05\x45RROR\x10\x01\"\xc4\x02\n\x0c\x45sp32Command\x12$\n\x0cpage_command\x18\x01 \x01(\x0b\x32\x0c.PageCommandH\x00\x12$\n\x0ctest_command\x18\x02 \x01(\x0b\x32\x0c.TestCommandH\x00\x12$\n\x0cwifi_command\x18\x03 \x01(\x0b\x32\x0c.WiFiCommandH\x00\x12*\n\x0fmicrosd_command\x18\x04 \x01(\x0b\x32\x0f.MicroSDCommandH\x00\x12\x30\n\x12irrigation_command\x18\x05 \x01(\x0b\x32\x12.IrrigationCommandH\x00\x12\x31\n\x13user_config_command\x18\x06 \x01(\x0b\x32\x12.UserConfigCommandH\x00\x12&\n\rpower_command\x18\x07 \x01(\x0b\x32\r.PowerCommandH\x00\x42\t\n\x07\x63ommand\"\xb6\x01\n\x0bPageCommand\x12.\n\x0c\x66ile_request\x18\x01 \x01(\x0e\x32\x18.PageCommand.RequestType\x12\x17\n\x0f\x66ile_descriptor\x18\x02 \x01(\r\x12\x12\n\nblock_size\x18\x03 \x01(\r\x12\x11\n\tnum_bytes\x18\x04 \x01(\r\"7\n\x0bRequestType\x12\x08\n\x04OPEN\x10\x00\x12\t\n\x05\x43LOSE\x10\x01\x12\x08\n\x04READ\x10\x02\x12\t\n\x05WRITE\x10\x03\"\x82\x01\n\x0bTestCommand\x12\'\n\x05state\x18\x01 \x01(\x0e\x32\x18.TestCommand.ChangeState\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x05\"<\n\x0b\x43hangeState\x12\x0b\n\x07RECEIVE\x10\x00\x12\x13\n\x0fRECEIVE_REQUEST\x10\x01\x12\x0b\n\x07REQUEST\x10\x02\"\xc5\x02\n\x0bWiFiCommand\x12\x1f\n\x04type\x18\x01 \x01(\x0e\x32\x11.WiFiCommand.Type\x12\x0c\n\x04ssid\x18\x02 \x01(\t\x12\x0e\n\x06passwd\x18\x03 \x01(\t\x12\x0b\n\x03url\x18\x04 \x01(\t\x12\x0c\n\x04port\x18\x08 \x01(\r\x12\n\n\x02rc\x18\x05 \x01(\r\x12\n\n\x02ts\x18\x06 \x01(\r\x12\x0c\n\x04resp\x18\x07 \x01(\x0c\x12\x0b\n\x03mac\x18\t \x01(\t\x12\x0f\n\x07\x63lients\x18\n \x01(\r\"\x97\x01\n\x04Type\x12\x0b\n\x07\x43ONNECT\x10\x00\x12\x08\n\x04POST\x10\x01\x12\t\n\x05\x43HECK\x10\x02\x12\x08\n\x04TIME\x10\x03\x12\x0e\n\nDISCONNECT\x10\x04\x12\x0e\n\nCHECK_WIFI\x10\x05\x12\r\n\tCHECK_API\x10\x06\x12\x0c\n\x08NTP_SYNC\x10\x07\x12\x08\n\x04HOST\x10\x08\x12\r\n\tSTOP_HOST\x10\t\x12\r\n\tHOST_INFO\x10\n\"\xad\x01\n\x11UserConfigCommand\x12,\n\x04type\x18\x01 \x01(\x0e\x32\x1e.UserConfigCommand.RequestType\x12\'\n\x0b\x63onfig_data\x18\x02 \x01(\x0b\x32\x12.UserConfiguration\"A\n\x0bRequestType\x12\x12\n\x0eREQUEST_CONFIG\x10\x00\x12\x13\n\x0fRESPONSE_CONFIG\x10\x01\x12\t\n\x05START\x10\x02\"\x86\x03\n\x0eMicroSDCommand\x12\"\n\x04type\x18\x01 \x01(\x0e\x32\x14.MicroSDCommand.Type\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\x12&\n\x02rc\x18\x03 \x01(\x0e\x32\x1a.MicroSDCommand.ReturnCode\x12\x1c\n\x04meas\x18\x04 \x01(\x0b\x32\x0c.MeasurementH\x00\x12 \n\x02uc\x18\x05 \x01(\x0b\x32\x12.UserConfigurationH\x00\" \n\x04Type\x12\x08\n\x04SAVE\x10\x00\x12\x0e\n\nUSERCONFIG\x10\x01\"\xab\x01\n\nReturnCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x11\n\rERROR_GENERAL\x10\x01\x12\x1e\n\x1a\x45RROR_MICROSD_NOT_INSERTED\x10\x02\x12#\n\x1f\x45RROR_FILE_SYSTEM_NOT_MOUNTABLE\x10\x03\x12\x1d\n\x19\x45RROR_PAYLOAD_NOT_DECODED\x10\x04\x12\x19\n\x15\x45RROR_FILE_NOT_OPENED\x10\x05\x42\x06\n\x04\x64\x61ta\"\x94\x01\n\x11IrrigationCommand\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.IrrigationCommand.Type\x12\'\n\x05state\x18\x02 \x01(\x0e\x32\x18.IrrigationCommand.State\"\x11\n\x04Type\x12\t\n\x05\x43HECK\x10\x00\"\x1c\n\x05State\x12\x08\n\x04OPEN\x10\x00\x12\t\n\x05\x43LOSE\x10\x01\"\xab\x03\n\x0cPowerCommand\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.PowerCommand.Type\x12*\n\x06reason\x18\x02 \x01(\x0e\x32\x1a.PowerCommand.WakeupReason\x12\x12\n\nboot_count\x18\x03 \x01(\r\"\x1d\n\x04Type\x12\t\n\x05SLEEP\x10\x00\x12\n\n\x06WAKEUP\x10\x01\"\x99\x02\n\x0cWakeupReason\x12\x15\n\x11POWER_WAKEUP_EXT0\x10\x00\x12\x15\n\x11POWER_WAKEUP_EXT1\x10\x01\x12\x16\n\x12POWER_WAKEUP_TIMER\x10\x02\x12\x19\n\x15POWER_WAKEUP_TOUCHPAD\x10\x03\x12\x14\n\x10POWER_WAKEUP_ULP\x10\x04\x12\x15\n\x11POWER_WAKEUP_GPIO\x10\x05\x12\x15\n\x11POWER_WAKEUP_UART\x10\x06\x12\x15\n\x11POWER_WAKEUP_WIFI\x10\x07\x12\x16\n\x12POWER_WAKEUP_COCPU\x10\x08\x12 \n\x1cPOWER_WAKEUP_COCPU_TRAP_TRIG\x10\t\x12\x13\n\x0fPOWER_WAKEUP_BT\x10\n\"\xdc\x02\n\x11UserConfiguration\x12\x11\n\tlogger_id\x18\x01 \x01(\r\x12\x0f\n\x07\x63\x65ll_id\x18\x02 \x01(\r\x12$\n\rUpload_method\x18\x03 \x01(\x0e\x32\r.Uploadmethod\x12\x17\n\x0fUpload_interval\x18\x04 \x01(\r\x12\'\n\x0f\x65nabled_sensors\x18\x05 \x03(\x0e\x32\x0e.EnabledSensor\x12\x15\n\rVoltage_Slope\x18\x06 \x01(\x01\x12\x16\n\x0eVoltage_Offset\x18\x07 \x01(\x01\x12\x15\n\rCurrent_Slope\x18\x08 \x01(\x01\x12\x16\n\x0e\x43urrent_Offset\x18\t \x01(\x01\x12\x11\n\tWiFi_SSID\x18\n \x01(\t\x12\x15\n\rWiFi_Password\x18\x0b \x01(\t\x12\x18\n\x10\x41PI_Endpoint_URL\x18\x0c \x01(\t\x12\x19\n\x11\x41PI_Endpoint_Port\x18\r \x01(\r\"\x17\n\x08\x61\x64\x63Value\x12\x0b\n\x03\x61\x64\x63\x18\x01 \x01(\r*\x90\x01\n\rEnabledSensor\x12\x0b\n\x07Voltage\x10\x00\x12\x0b\n\x07\x43urrent\x10\x01\x12\x0b\n\x07Teros12\x10\x02\x12\x0b\n\x07Teros21\x10\x03\x12\n\n\x06\x42ME280\x10\x04\x12\x0c\n\x08Phytos31\x10\x05\x12\x0b\n\x07SEN0308\x10\x06\x12\x0b\n\x07SEN0257\x10\x07\x12\x0b\n\x07YFS210C\x10\x08\x12\n\n\x06PCAP02\x10\t*\"\n\x0cUploadmethod\x12\x08\n\x04LoRa\x10\x00\x12\x08\n\x04WiFi\x10\x01\x62\x06proto3')
28
28
 
29
29
  _globals = globals()
30
30
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
31
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'soil_power_sensor_pb2', _globals)
32
32
  if not _descriptor._USE_C_DESCRIPTORS:
33
33
  DESCRIPTOR._loaded_options = None
34
- _globals['_ENABLEDSENSOR']._serialized_start=2759
35
- _globals['_ENABLEDSENSOR']._serialized_end=2838
36
- _globals['_UPLOADMETHOD']._serialized_start=2840
37
- _globals['_UPLOADMETHOD']._serialized_end=2874
34
+ _globals['_ENABLEDSENSOR']._serialized_start=4041
35
+ _globals['_ENABLEDSENSOR']._serialized_end=4185
36
+ _globals['_UPLOADMETHOD']._serialized_start=4187
37
+ _globals['_UPLOADMETHOD']._serialized_end=4221
38
38
  _globals['_MEASUREMENTMETADATA']._serialized_start=27
39
39
  _globals['_MEASUREMENTMETADATA']._serialized_end=96
40
40
  _globals['_POWERMEASUREMENT']._serialized_start=98
41
41
  _globals['_POWERMEASUREMENT']._serialized_end=150
42
- _globals['_TEROS12MEASUREMENT']._serialized_start=152
43
- _globals['_TEROS12MEASUREMENT']._serialized_end=232
44
- _globals['_TEROS21MEASUREMENT']._serialized_start=234
45
- _globals['_TEROS21MEASUREMENT']._serialized_end=288
46
- _globals['_PHYTOS31MEASUREMENT']._serialized_start=290
47
- _globals['_PHYTOS31MEASUREMENT']._serialized_end=350
48
- _globals['_BME280MEASUREMENT']._serialized_start=352
49
- _globals['_BME280MEASUREMENT']._serialized_end=428
50
- _globals['_SEN0308MEASUREMENT']._serialized_start=430
51
- _globals['_SEN0308MEASUREMENT']._serialized_end=485
52
- _globals['_SEN0257MEASUREMENT']._serialized_start=487
53
- _globals['_SEN0257MEASUREMENT']._serialized_end=542
54
- _globals['_YFS210CMEASUREMENT']._serialized_start=544
55
- _globals['_YFS210CMEASUREMENT']._serialized_end=578
56
- _globals['_MEASUREMENT']._serialized_start=581
57
- _globals['_MEASUREMENT']._serialized_end=961
58
- _globals['_RESPONSE']._serialized_start=963
59
- _globals['_RESPONSE']._serialized_end=1051
60
- _globals['_RESPONSE_RESPONSETYPE']._serialized_start=1013
61
- _globals['_RESPONSE_RESPONSETYPE']._serialized_end=1051
62
- _globals['_ESP32COMMAND']._serialized_start=1054
63
- _globals['_ESP32COMMAND']._serialized_end=1287
64
- _globals['_PAGECOMMAND']._serialized_start=1290
65
- _globals['_PAGECOMMAND']._serialized_end=1472
66
- _globals['_PAGECOMMAND_REQUESTTYPE']._serialized_start=1417
67
- _globals['_PAGECOMMAND_REQUESTTYPE']._serialized_end=1472
68
- _globals['_TESTCOMMAND']._serialized_start=1475
69
- _globals['_TESTCOMMAND']._serialized_end=1605
70
- _globals['_TESTCOMMAND_CHANGESTATE']._serialized_start=1545
71
- _globals['_TESTCOMMAND_CHANGESTATE']._serialized_end=1605
72
- _globals['_WIFICOMMAND']._serialized_start=1608
73
- _globals['_WIFICOMMAND']._serialized_end=1862
74
- _globals['_WIFICOMMAND_TYPE']._serialized_start=1751
75
- _globals['_WIFICOMMAND_TYPE']._serialized_end=1862
76
- _globals['_MICROSDCOMMAND']._serialized_start=1865
77
- _globals['_MICROSDCOMMAND']._serialized_end=2255
78
- _globals['_MICROSDCOMMAND_TYPE']._serialized_start=2041
79
- _globals['_MICROSDCOMMAND_TYPE']._serialized_end=2073
80
- _globals['_MICROSDCOMMAND_RETURNCODE']._serialized_start=2076
81
- _globals['_MICROSDCOMMAND_RETURNCODE']._serialized_end=2247
82
- _globals['_IRRIGATIONCOMMAND']._serialized_start=2258
83
- _globals['_IRRIGATIONCOMMAND']._serialized_end=2406
84
- _globals['_IRRIGATIONCOMMAND_TYPE']._serialized_start=2359
85
- _globals['_IRRIGATIONCOMMAND_TYPE']._serialized_end=2376
86
- _globals['_IRRIGATIONCOMMAND_STATE']._serialized_start=2378
87
- _globals['_IRRIGATIONCOMMAND_STATE']._serialized_end=2406
88
- _globals['_USERCONFIGURATION']._serialized_start=2409
89
- _globals['_USERCONFIGURATION']._serialized_end=2757
42
+ _globals['_VOLTAGEDELTAMEASUREMENT']._serialized_start=152
43
+ _globals['_VOLTAGEDELTAMEASUREMENT']._serialized_end=194
44
+ _globals['_CURRENTDELTAMEASUREMENT']._serialized_start=196
45
+ _globals['_CURRENTDELTAMEASUREMENT']._serialized_end=238
46
+ _globals['_VOLTAGEMEASUREMENT']._serialized_start=240
47
+ _globals['_VOLTAGEMEASUREMENT']._serialized_end=277
48
+ _globals['_CURRENTMEASUREMENT']._serialized_start=279
49
+ _globals['_CURRENTMEASUREMENT']._serialized_end=316
50
+ _globals['_POWERDELTAENTRY']._serialized_start=318
51
+ _globals['_POWERDELTAENTRY']._serialized_end=393
52
+ _globals['_POWERMEASUREMENTDELTA']._serialized_start=395
53
+ _globals['_POWERMEASUREMENTDELTA']._serialized_end=464
54
+ _globals['_REPEATEDPOWERDELTAS']._serialized_start=466
55
+ _globals['_REPEATEDPOWERDELTAS']._serialized_end=558
56
+ _globals['_TEROS12MEASUREMENT']._serialized_start=560
57
+ _globals['_TEROS12MEASUREMENT']._serialized_end=640
58
+ _globals['_TEROS21MEASUREMENT']._serialized_start=642
59
+ _globals['_TEROS21MEASUREMENT']._serialized_end=696
60
+ _globals['_PHYTOS31MEASUREMENT']._serialized_start=698
61
+ _globals['_PHYTOS31MEASUREMENT']._serialized_end=758
62
+ _globals['_BME280MEASUREMENT']._serialized_start=760
63
+ _globals['_BME280MEASUREMENT']._serialized_end=836
64
+ _globals['_SEN0308MEASUREMENT']._serialized_start=838
65
+ _globals['_SEN0308MEASUREMENT']._serialized_end=893
66
+ _globals['_SEN0257MEASUREMENT']._serialized_start=895
67
+ _globals['_SEN0257MEASUREMENT']._serialized_end=950
68
+ _globals['_YFS210CMEASUREMENT']._serialized_start=952
69
+ _globals['_YFS210CMEASUREMENT']._serialized_end=986
70
+ _globals['_PCAP02MEASUREMENT']._serialized_start=988
71
+ _globals['_PCAP02MEASUREMENT']._serialized_end=1028
72
+ _globals['_MEASUREMENT']._serialized_start=1031
73
+ _globals['_MEASUREMENT']._serialized_end=1449
74
+ _globals['_RESPONSE']._serialized_start=1451
75
+ _globals['_RESPONSE']._serialized_end=1539
76
+ _globals['_RESPONSE_RESPONSETYPE']._serialized_start=1501
77
+ _globals['_RESPONSE_RESPONSETYPE']._serialized_end=1539
78
+ _globals['_ESP32COMMAND']._serialized_start=1542
79
+ _globals['_ESP32COMMAND']._serialized_end=1866
80
+ _globals['_PAGECOMMAND']._serialized_start=1869
81
+ _globals['_PAGECOMMAND']._serialized_end=2051
82
+ _globals['_PAGECOMMAND_REQUESTTYPE']._serialized_start=1996
83
+ _globals['_PAGECOMMAND_REQUESTTYPE']._serialized_end=2051
84
+ _globals['_TESTCOMMAND']._serialized_start=2054
85
+ _globals['_TESTCOMMAND']._serialized_end=2184
86
+ _globals['_TESTCOMMAND_CHANGESTATE']._serialized_start=2124
87
+ _globals['_TESTCOMMAND_CHANGESTATE']._serialized_end=2184
88
+ _globals['_WIFICOMMAND']._serialized_start=2187
89
+ _globals['_WIFICOMMAND']._serialized_end=2512
90
+ _globals['_WIFICOMMAND_TYPE']._serialized_start=2361
91
+ _globals['_WIFICOMMAND_TYPE']._serialized_end=2512
92
+ _globals['_USERCONFIGCOMMAND']._serialized_start=2515
93
+ _globals['_USERCONFIGCOMMAND']._serialized_end=2688
94
+ _globals['_USERCONFIGCOMMAND_REQUESTTYPE']._serialized_start=2623
95
+ _globals['_USERCONFIGCOMMAND_REQUESTTYPE']._serialized_end=2688
96
+ _globals['_MICROSDCOMMAND']._serialized_start=2691
97
+ _globals['_MICROSDCOMMAND']._serialized_end=3081
98
+ _globals['_MICROSDCOMMAND_TYPE']._serialized_start=2867
99
+ _globals['_MICROSDCOMMAND_TYPE']._serialized_end=2899
100
+ _globals['_MICROSDCOMMAND_RETURNCODE']._serialized_start=2902
101
+ _globals['_MICROSDCOMMAND_RETURNCODE']._serialized_end=3073
102
+ _globals['_IRRIGATIONCOMMAND']._serialized_start=3084
103
+ _globals['_IRRIGATIONCOMMAND']._serialized_end=3232
104
+ _globals['_IRRIGATIONCOMMAND_TYPE']._serialized_start=3185
105
+ _globals['_IRRIGATIONCOMMAND_TYPE']._serialized_end=3202
106
+ _globals['_IRRIGATIONCOMMAND_STATE']._serialized_start=3204
107
+ _globals['_IRRIGATIONCOMMAND_STATE']._serialized_end=3232
108
+ _globals['_POWERCOMMAND']._serialized_start=3235
109
+ _globals['_POWERCOMMAND']._serialized_end=3662
110
+ _globals['_POWERCOMMAND_TYPE']._serialized_start=3349
111
+ _globals['_POWERCOMMAND_TYPE']._serialized_end=3378
112
+ _globals['_POWERCOMMAND_WAKEUPREASON']._serialized_start=3381
113
+ _globals['_POWERCOMMAND_WAKEUPREASON']._serialized_end=3662
114
+ _globals['_USERCONFIGURATION']._serialized_start=3665
115
+ _globals['_USERCONFIGURATION']._serialized_end=4013
116
+ _globals['_ADCVALUE']._serialized_start=4015
117
+ _globals['_ADCVALUE']._serialized_end=4038
90
118
  # @@protoc_insertion_point(module_scope)
ents/simulator/node.py CHANGED
@@ -10,6 +10,8 @@ from ..proto.encode import (
10
10
  encode_bme280_measurement,
11
11
  )
12
12
 
13
+ from ..proto.sensor import encode_repeated_sensor_measurements
14
+
13
15
 
14
16
  class NodeSimulator:
15
17
  """Simulation class to simulate measurements for different sensors"""
@@ -159,3 +161,122 @@ class NodeSimulator:
159
161
  )
160
162
  self.measurements.append(meas)
161
163
  self.measurement_buffer.append(meas)
164
+
165
+
166
+ class NodeSimulatorGeneric:
167
+ """Simulation class to simulate measurements for different sensors"""
168
+
169
+ # temporary storage for measurements to be uploaded
170
+ measurement_buffer: list[bytes] = []
171
+ # all measurements uploaded
172
+ measurements: list[bytes] = []
173
+ # all responses
174
+ responses: list[str] = []
175
+
176
+ # metrics for uploads
177
+ metrics: dict[str, int] = {
178
+ "total_requests": 0,
179
+ "failed_requests": 0,
180
+ "successful_requests": 0,
181
+ }
182
+
183
+ latency: list[float] = []
184
+
185
+ def __init__(
186
+ self, cell: int, logger: int, sensors: list[str], _min=-1, _max=1, fn=sin
187
+ ):
188
+ """Initializes the simulation class.
189
+
190
+ Args:
191
+ cell: Cell ID of the node.
192
+ logger: Logger ID of the node.
193
+ sensors: List of sensors to simulate.
194
+ _min: Minimum value for the simulated sensor data.
195
+ _max: Maximum value for the simulated sensor data.
196
+ fn: Function to generate the simulated sensor data.
197
+ """
198
+
199
+ self.cell = cell
200
+ self.logger = logger
201
+ self.sensors = sensors
202
+ self.fn = fn
203
+ self._min = _min
204
+ self._max = _max
205
+
206
+ def __str__(self):
207
+ """String representation of the simulation class
208
+
209
+ Shows the current upload metrics
210
+ """
211
+ avg = np.array(self.latency).mean()
212
+
213
+ last = 0
214
+ if len(self.latency) > 0:
215
+ last = self.latency[-1]
216
+
217
+ return "total: {}, failed: {}, avg (ms): {}, last (ms): {}".format(
218
+ self.metrics["total_requests"],
219
+ self.metrics["failed_requests"],
220
+ avg * 100,
221
+ last * 100,
222
+ )
223
+
224
+ def send_next(self, url: str) -> bool:
225
+ """Sends measurements to a dirtviz instance
226
+
227
+ Args:
228
+ url: URL of the dirtviz instance
229
+
230
+ Returns:
231
+ True if there are measurements to send, False otherwise
232
+ """
233
+
234
+ # get next measurement
235
+ try:
236
+ meas = self.measurements.pop()
237
+ except IndexError as _:
238
+ return False
239
+
240
+ headers = {"Content-Type": "application/octet-stream"}
241
+ result = requests.post(url, data=meas, headers=headers)
242
+
243
+ # store result
244
+ self.responses.append(result.text)
245
+ self.metrics["total_requests"] += 1
246
+ if result.status_code == 200:
247
+ self.metrics["successful_requests"] += 1
248
+ else:
249
+ self.metrics["failed_requests"] += 1
250
+ self.latency.append(result.elapsed.total_seconds())
251
+
252
+ return True
253
+
254
+ def measure(self, ts: int):
255
+ """Simulate measurements
256
+
257
+ Args:
258
+ ts: Timestamp of the measurement
259
+ """
260
+
261
+ meas = {
262
+ "meta": {
263
+ "ts": ts,
264
+ "loggerId": self.logger,
265
+ "cellId": self.cell,
266
+ },
267
+ "measurements": [],
268
+ }
269
+
270
+ scale = (self._max - self._min) / 2
271
+ offset = (self._max + self._min) / 2
272
+
273
+ for s in self.sensors:
274
+ meas["measurements"].append(
275
+ {
276
+ "type": s,
277
+ "decimal": self.fn(ts) * scale + offset,
278
+ }
279
+ )
280
+
281
+ serialized = encode_repeated_sensor_measurements(meas)
282
+ self.measurement_buffer.append(serialized)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ents
3
- Version: 2.3.4
3
+ Version: 2.3.5
4
4
  Summary: Python package for Environmental NeTworked Sensor (ENTS)
5
5
  Project-URL: Homepage, https://github.com/jlab-sensing/soil-power-sensor-firmware
6
6
  Project-URL: Issues, https://github.com/jlab-sensing/soil-power-sensor-firmware/issues
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.11
13
13
  Requires-Dist: matplotlib
14
14
  Requires-Dist: pandas
15
- Requires-Dist: protobuf==6.31.1
15
+ Requires-Dist: protobuf==6.33.2
16
16
  Requires-Dist: pyserial
17
17
  Requires-Dist: requests
18
18
  Requires-Dist: scikit-learn
@@ -1,5 +1,5 @@
1
- ents/__init__.py,sha256=KyqH3dz_BdFHWxD9n4DFItgsrxO7rDtt2IObWkdLsns,582
2
- ents/cli.py,sha256=O071Ot2u7yeMFZyoOY--hp4UepXOHEX2nNiiQ5TxpI4,16573
1
+ ents/__init__.py,sha256=IVe193OL25_F5AMMx272iGabJ1e4jPVNLFAJDktA0oU,706
2
+ ents/cli.py,sha256=rMZoyJ_FlA8OiYKpIoRK3vvCtFAgl5VoVGcLWcENtZE,24412
3
3
  ents/calibrate/PingSMU.py,sha256=1iXozKaPE0ucgB3qsTI5mVk__n6pqC8Z2nV_GRfU2gA,1253
4
4
  ents/calibrate/PingSPS.py,sha256=pNQN1ngWQ2Z7Q1DoWCIe4DN02hZfNOrKpLH7I0bAd8U,1876
5
5
  ents/calibrate/README.md,sha256=ctdpfS5tN-PnDBn8sCTAn4gi0E-ZLUDXYnLZuqleDmM,109
@@ -10,17 +10,18 @@ ents/calibrate/recorder.py,sha256=fce5cW2DiCSOMQ-CSRL7raghbR2Yeg8Nx9obyY-0yOg,18
10
10
  ents/config/README.md,sha256=SRtr5YuM64MSZQdy60F8Ib_AI2MR-MbbAdjS3jcjVD4,4447
11
11
  ents/config/__init__.py,sha256=3eyHUKg-ZPx82h2CGiNyzaaI7Y7koEOUX9pzrlnVcJw,51
12
12
  ents/config/adv_trace.py,sha256=hEDBNbVslJ2lJ-8tfJhPXxQMZN9Nylqv8RK42waRhsM,1290
13
- ents/config/user_config.py,sha256=SAudV12wyE-5Z0weZJQzBELRXR3-oevIgbrimUF2TmI,39198
14
- ents/demo/demoPullRequests.py,sha256=YSTVa59puMtER8sjOppiMshUCDjdsIikXLNOM0U6zmU,3864
13
+ ents/config/user_config.py,sha256=evaM3Lb0IU_qFugEeRiXUCMiCUyEbtnRNTXayqE6Qig,39182
15
14
  ents/proto/__init__.py,sha256=5THafGlxirjEUATIXB2EVpdOY5APEjztzOAHlRGNG2c,720
16
15
  ents/proto/decode.py,sha256=_dn9Agv41YgUtMVHZ7l5-Y13ci3hnjyXrRPGKDIHzvo,2964
17
16
  ents/proto/encode.py,sha256=kPAD5-bL6zNEjh6z1n1FusdM9z5UretypxHHAiuGGA4,7753
18
17
  ents/proto/esp32.py,sha256=4QOHZNH1SqkJg4TLvJgrAbhdJg88ZNtqoMNLBcWUX2U,4657
19
- ents/proto/soil_power_sensor_pb2.py,sha256=sNf-97udroXqmimooH0x1IWOTSm-4IoRsFzbyb9aLRg,9491
18
+ ents/proto/sensor.py,sha256=zdZXG-TtX5kpSc6aETOywHApM8xLMY_J2OO8oBlEqU4,7148
19
+ ents/proto/sensor_pb2.py,sha256=Kxe7ZMeaJwQbqv4MHWUK5_4LxTY8Ou1n1bXMDq4KfQ0,3673
20
+ ents/proto/soil_power_sensor_pb2.py,sha256=r7lcuo8A3YW-vsiR7gT0dvG2UMdolpMe3r8kGfKx54U,13442
20
21
  ents/simulator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- ents/simulator/node.py,sha256=vDdt_Q2BiEo1Z-aMZnm9_Y-aAtPU_lhcWW-xSDYR54c,4444
22
- ents-2.3.4.dist-info/METADATA,sha256=FMxd6PnezpUeq3ZBVty08iRL-CzgVo5YTugULlzxHZ4,5258
23
- ents-2.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
- ents-2.3.4.dist-info/entry_points.txt,sha256=1U6ViZDTy4vv1jFp5RisBPC0NFqmtV3f18eUnWKX0Nk,95
25
- ents-2.3.4.dist-info/licenses/LICENSE,sha256=2WLObzfS99jXXcPS5INqnmDVZ1nlO8Rj8mzQn2xkn14,1086
26
- ents-2.3.4.dist-info/RECORD,,
22
+ ents/simulator/node.py,sha256=RRPsKKA8_7u0Ka-1hXzO_3gNj91heXIZaDxRaG0Nw_o,7797
23
+ ents-2.3.5.dist-info/METADATA,sha256=x8PN37a25YxVbtL2hZIF6CwaxJ1NVXGQ0xiGWLXQeQA,5258
24
+ ents-2.3.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
25
+ ents-2.3.5.dist-info/entry_points.txt,sha256=1U6ViZDTy4vv1jFp5RisBPC0NFqmtV3f18eUnWKX0Nk,95
26
+ ents-2.3.5.dist-info/licenses/LICENSE,sha256=2WLObzfS99jXXcPS5INqnmDVZ1nlO8Rj8mzQn2xkn14,1086
27
+ ents-2.3.5.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,119 +0,0 @@
1
- import requests
2
- from datetime import datetime, timezone
3
- import pandas as pd
4
- from tabulate import tabulate
5
-
6
-
7
- class DirtVizClient:
8
- BASE_URL = "https://dirtviz.jlab.ucsc.edu/api/"
9
-
10
- def __init__(self):
11
- self.session = requests.Session()
12
-
13
- def cell_from_name(self, name, start=None, end=None):
14
- """Get power data for a specific cell"""
15
-
16
- def get_power_data(self, cell_id, start=None, end=None):
17
- """Get power data for a specific cell"""
18
- endpoint = f"power/{cell_id}"
19
- params = {}
20
-
21
- if start and end:
22
- params = {
23
- "startTime": start.strftime("%a, %d %b %Y %H:%M:%S GMT"),
24
- "endTime": end.strftime("%a, %d %b %Y %H:%M:%S GMT"),
25
- }
26
-
27
- response = self.session.get(f"{self.BASE_URL}{endpoint}", params=params)
28
- response.raise_for_status()
29
- return response.json()
30
-
31
-
32
- def format_data_display(df, cell_id):
33
- """Format the data output with timestamp as first column"""
34
-
35
- # Ensure timestamp exists and is first column
36
- if "timestamp" in df.columns:
37
- cols = ["timestamp"] + [col for col in df.columns if col != "timestamp"]
38
- df = df[cols]
39
-
40
- # Format timestamp nicely
41
- df["timestamp"] = pd.to_datetime(df["timestamp"])
42
- df["timestamp"] = df["timestamp"].dt.strftime("%m-%d-%Y %H:%M:%S")
43
-
44
- # Calculate statistics
45
- stats = {
46
- "Cell ID": cell_id,
47
- "Time Range": (
48
- f"{df['timestamp'].iloc[0]} to {df['timestamp'].iloc[-1]}"
49
- if len(df) > 0
50
- else "N/A"
51
- ),
52
- "Data Points": len(df),
53
- "Avg Voltage (mV)": f"{df['v'].mean():.2f}" if "v" in df.columns else "N/A",
54
- "Max Voltage (mV)": f"{df['v'].max():.2f}" if "v" in df.columns else "N/A",
55
- "Avg Current (µA)": f"{df['i'].mean():.2f}" if "i" in df.columns else "N/A",
56
- "Avg Power (µW)": f"{df['p'].mean():.2f}" if "p" in df.columns else "N/A",
57
- }
58
-
59
- column_rename = {
60
- "timestamp": "Measurement Times",
61
- "v": "Voltage (mV)",
62
- "i": "Current (µA)",
63
- "p": "Power (µW)",
64
- }
65
- # Apply renaming
66
- df = df.rename(columns=column_rename)
67
-
68
- # Display header
69
- print("\n" + "=" * 60)
70
- print(f"CELL {cell_id} POWER DATA SUMMARY".center(60))
71
- for key, value in stats.items():
72
- print(f"• {key:<20}: {value}") # Display the summary information
73
- print("=" * 60 + "\n")
74
-
75
- # Display sample data with timestamp first
76
- if len(df) > 0:
77
- print("DATA BY TIMESTAMPS:")
78
- print(
79
- tabulate(
80
- df,
81
- headers="keys",
82
- tablefmt="grid", # Changed to grid for better column alignment
83
- stralign="center", # Right-align numbers
84
- showindex=False,
85
- numalign="center",
86
- )
87
- )
88
- else:
89
- print("No data available to display")
90
-
91
- print("\n" + "=" * 80)
92
-
93
-
94
- if __name__ == "__main__":
95
- client = DirtVizClient()
96
-
97
- try:
98
- cell_id = 893 # Figure out how to do by name on DirtViz
99
- start = datetime(2025, 8, 12, tzinfo=timezone.utc)
100
- end = datetime.now(timezone.utc)
101
-
102
- print(f"\nFetching power data for cell {cell_id}...")
103
- data = client.get_power_data(cell_id, start, end)
104
-
105
- if data:
106
- df = pd.DataFrame(data)
107
- format_data_display(df, cell_id)
108
-
109
- # Save to CSV with timestamp first
110
- # df.to_csv(f"cell_{cell_id}_power_data.csv", index=False)
111
- # print(f"Data saved to cell_{cell_id}_power_data.csv")
112
- else:
113
- print("No data received for the specified time range.")
114
-
115
- except requests.exceptions.HTTPError as e:
116
- print(f"\nHTTP Error: {e}")
117
- print(f"Response: {e.response.text[:500]}...")
118
- except Exception as e:
119
- print(f"\n⚠️ Unexpected error: {str(e)}")