cfclient 2024.3__py3-none-any.whl → 2024.7__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.

Potentially problematic release.


This version of cfclient might be problematic. Click here for more details.

@@ -210,7 +210,7 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
210
210
  self._combined_button = QtWidgets.QPushButton('Combined Axis ' +
211
211
  'Detection')
212
212
  self.cancelButton = QtWidgets.QPushButton('Cancel')
213
- self._popup.addButton(self.cancelButton, QMessageBox.DestructiveRole)
213
+ self._popup.addButton(self.cancelButton, QMessageBox.ButtonRole.DestructiveRole)
214
214
  self._popup.setWindowTitle(caption)
215
215
  self._popup.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.MSWindowsFixedSizeDialogHint)
216
216
  if len(directions) > 1:
@@ -219,7 +219,7 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
219
219
  self._combined_button.setCheckable(True)
220
220
  self._combined_button.blockSignals(True)
221
221
  self._popup.addButton(self._combined_button,
222
- QMessageBox.ActionRole)
222
+ QMessageBox.ButtonRole.ActionRole)
223
223
  self._popup.setText(message)
224
224
  self._popup.show()
225
225
 
@@ -715,7 +715,7 @@ class FlightTab(TabToolbox, flight_tab_class):
715
715
  self.targetHeight.setEnabled(enabled)
716
716
  print('Chaning enable for target height: %s' % enabled)
717
717
  else:
718
- self._helper.cf.param.set_value("flightmode.althold", str(enabled))
718
+ self._helper.cf.param.set_value("flightmode.althold", int(enabled))
719
719
 
720
720
  def alt1_updated(self, state):
721
721
  if state:
@@ -31,17 +31,20 @@ to edit them.
31
31
  """
32
32
 
33
33
  import logging
34
+ from threading import Event
34
35
 
35
36
  from PyQt6 import uic, QtCore
36
37
  from PyQt6.QtCore import QSortFilterProxyModel, Qt, pyqtSignal
37
38
  from PyQt6.QtCore import QAbstractItemModel, QModelIndex, QVariant
38
39
  from PyQt6.QtGui import QBrush, QColor
39
- from PyQt6.QtWidgets import QHeaderView
40
+ from PyQt6.QtWidgets import QHeaderView, QFileDialog, QMessageBox
40
41
 
41
42
  from cflib.crazyflie.param import PersistentParamState
43
+ from cflib.localization import ParamFileManager
42
44
 
43
45
  import cfclient
44
46
  from cfclient.ui.tab_toolbox import TabToolbox
47
+ from cfclient.utils.logconfigreader import FILE_REGEX_YAML
45
48
 
46
49
  __author__ = 'Bitcraze AB'
47
50
  __all__ = ['ParamTab']
@@ -316,6 +319,13 @@ class ParamTab(TabToolbox, param_tab_class):
316
319
  self.paramTree.header().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
317
320
  self.paramTree.selectionModel().selectionChanged.connect(self._paramChanged)
318
321
 
322
+ self._load_param_button.clicked.connect(self._load_param_button_clicked)
323
+ self._dump_param_button.clicked.connect(self._dump_param_button_clicked)
324
+ self._clear_param_button.clicked.connect(self._clear_stored_persistent_params_button_clicked)
325
+
326
+ self._is_connected = False
327
+ self._update_param_io_buttons()
328
+
319
329
  def _param_default_cb(self, default_value):
320
330
  if default_value is not None:
321
331
  self.defaultValue.setText(str(default_value))
@@ -408,14 +418,144 @@ class ParamTab(TabToolbox, param_tab_class):
408
418
  if elem.is_persistent():
409
419
  self.cf.param.persistent_get_state(complete, lambda _, state: self._persistent_state_signal.emit(state))
410
420
 
421
+ def _update_param_io_buttons(self):
422
+ enabled = self._is_connected
423
+ self._load_param_button.setEnabled(enabled)
424
+ self._dump_param_button.setEnabled(enabled)
425
+ self._clear_param_button.setEnabled(enabled)
426
+
427
+ def _load_param_button_clicked(self):
428
+ names = QFileDialog.getOpenFileName(self, 'Open file', cfclient.config_path, FILE_REGEX_YAML)
429
+
430
+ if names[0] == '':
431
+ return
432
+ filename = names[0]
433
+ parameters = ParamFileManager.read(filename)
434
+
435
+ def _is_persistent_stored_callback(complete_name, success):
436
+ if not success:
437
+ print(f'Persistent params: failed to store {complete_name}!')
438
+ QMessageBox.about(self, 'Warning', f'Failed to persistently store {complete_name}!')
439
+ else:
440
+ print(f'Persistent params: stored {complete_name}!')
441
+
442
+ _set_param_names = []
443
+ for param, state in parameters.items():
444
+ if state.is_stored:
445
+ try:
446
+ self.cf.param.set_value(param, state.stored_value)
447
+ _set_param_names.append(param)
448
+ except Exception:
449
+ print(f'Failed to set {param}!')
450
+ QMessageBox.about(self, 'Warning', f'Failed to set {param}!')
451
+ print(f'Set {param}!')
452
+ self.cf.param.persistent_store(param, _is_persistent_stored_callback)
453
+
454
+ self._update_param_io_buttons()
455
+ dlg = QMessageBox(self)
456
+ dlg.setWindowTitle("Info")
457
+ _parameters_and_values = [f"{_param_name}:{parameters[_param_name].stored_value}"
458
+ for _param_name in _set_param_names]
459
+ dlg.setText('Loaded persistent parameters from file:\n' + "\n".join(_parameters_and_values))
460
+ dlg.setIcon(QMessageBox.Icon.NoIcon)
461
+ dlg.exec()
462
+
463
+ def _get_persistent_state(self, complete_param_name):
464
+ wait_for_callback_event = Event()
465
+ state_value = None
466
+
467
+ def state_callback(complete_name, value):
468
+ nonlocal state_value
469
+ state_value = value
470
+ wait_for_callback_event.set()
471
+
472
+ self.cf.param.persistent_get_state(complete_param_name, state_callback)
473
+ wait_for_callback_event.wait()
474
+ return state_value
475
+
476
+ def _get_all_persistent_param_names(self):
477
+ persistent_params = []
478
+ for group_name, params in self.cf.param.toc.toc.items():
479
+ for param_name, element in params.items():
480
+ if element.is_persistent():
481
+ complete_name = group_name + '.' + param_name
482
+ persistent_params.append(complete_name)
483
+
484
+ return persistent_params
485
+
486
+ def _get_all_stored_persistent_param_names(self):
487
+ persistent_params = self._get_all_persistent_param_names()
488
+ stored_params = []
489
+ for complete_name in persistent_params:
490
+ state = self._get_persistent_state(complete_name)
491
+ if state.is_stored:
492
+ stored_params.append(complete_name)
493
+ return stored_params
494
+
495
+ def _get_all_stored_persistent_params(self):
496
+ persistent_params = self._get_all_persistent_param_names()
497
+ stored_params = {}
498
+ for complete_name in persistent_params:
499
+ state = self._get_persistent_state(complete_name)
500
+ if state.is_stored:
501
+ stored_params[complete_name] = state
502
+ return stored_params
503
+
504
+ def _dump_param_button_clicked(self):
505
+ stored_persistent_params = self._get_all_stored_persistent_params()
506
+ names = QFileDialog.getSaveFileName(self, 'Save file', cfclient.config_path, FILE_REGEX_YAML)
507
+ if names[0] == '':
508
+ return
509
+ if not names[0].endswith(".yaml"):
510
+ filename = names[0] + ".yaml"
511
+ else:
512
+ filename = names[0]
513
+
514
+ ParamFileManager.write(filename, stored_persistent_params)
515
+ dlg = QMessageBox(self)
516
+ dlg.setWindowTitle('Info')
517
+ _parameters_and_values = [f"{_param_name}: {stored_persistent_params[_param_name].stored_value}"
518
+ for _param_name in stored_persistent_params.keys()]
519
+ dlg.setText('Dumped persistent parameters to file:\n' + "\n".join(_parameters_and_values))
520
+ dlg.setIcon(QMessageBox.Icon.NoIcon)
521
+ dlg.exec()
522
+
523
+ def _clear_persistent_parameter(self, complete_param_name):
524
+ wait_for_callback_event = Event()
525
+
526
+ def is_stored_cleared(complete_name, success):
527
+ if success:
528
+ print(f'Persistent params: cleared {complete_name}!')
529
+ else:
530
+ print(f'Persistent params: failed to clear {complete_name}!')
531
+ wait_for_callback_event.set()
532
+
533
+ self.cf.param.persistent_clear(complete_param_name, callback=is_stored_cleared)
534
+ wait_for_callback_event.wait()
535
+
536
+ def _clear_stored_persistent_params_button_clicked(self):
537
+ dlg = QMessageBox(self)
538
+ dlg.setWindowTitle("Clear Stored Parameters Confirmation")
539
+ dlg.setText("Are you sure you want to clear your stored persistent parameter?")
540
+ dlg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
541
+ button = dlg.exec()
542
+
543
+ if button == QMessageBox.StandardButton.Yes:
544
+ stored_persistent_params = self._get_all_stored_persistent_param_names()
545
+ for complete_name in stored_persistent_params:
546
+ self._clear_persistent_parameter(complete_name)
547
+
411
548
  def _connected(self, link_uri):
412
549
  self._model.reset()
413
550
  self._model.set_toc(self.cf.param.toc.toc, self._helper.cf)
414
551
  self._model.set_enabled(True)
415
552
  self._helper.cf.param.request_update_of_all_params()
553
+ self._is_connected = True
554
+ self._update_param_io_buttons()
416
555
 
417
556
  def _disconnected(self, link_uri):
418
-
557
+ self._is_connected = False
558
+ self._update_param_io_buttons()
419
559
  self._model.reset()
420
560
  self._paramChanged()
421
561
  self._model.set_enabled(False)
@@ -22,8 +22,8 @@
22
22
  </item>
23
23
  <item row="1" column="0">
24
24
  <widget class="QTreeView" name="paramTree"/>
25
- </item>
26
- <item row="0" column="1" rowspan="2">
25
+ </item>
26
+ <item row="1" column="1" rowspan="2">
27
27
  <widget class="QFrame" name="paramDetails">
28
28
  <property name="frameShape">
29
29
  <enum>QFrame::Box</enum>
@@ -182,6 +182,42 @@
182
182
  </layout>
183
183
  </widget>
184
184
  </item>
185
+ <item row="0" column="1">
186
+ <layout class="QVBoxLayout" name="verticalLayout">
187
+ <item>
188
+ <widget class="QLabel" name="label">
189
+ <property name="text">
190
+ <string>Persistent Parameter Management</string>
191
+ </property>
192
+ </widget>
193
+ </item>
194
+ <item>
195
+ <layout class="QHBoxLayout" name="horizontalLayout">
196
+ <item>
197
+ <widget class="QPushButton" name="_dump_param_button">
198
+ <property name="text">
199
+ <string>Dump</string>
200
+ </property>
201
+ </widget>
202
+ </item>
203
+ <item>
204
+ <widget class="QPushButton" name="_load_param_button">
205
+ <property name="text">
206
+ <string>Load</string>
207
+ </property>
208
+ </widget>
209
+ </item>
210
+ <item>
211
+ <widget class="QPushButton" name="_clear_param_button">
212
+ <property name="text">
213
+ <string>Clear</string>
214
+ </property>
215
+ </widget>
216
+ </item>
217
+ </layout>
218
+ </item>
219
+ </layout>
220
+ </item>
185
221
  </layout>
186
222
  </widget>
187
223
  <resources/>
@@ -31,20 +31,51 @@
31
31
  <layout class="QGridLayout" name="gridLayout">
32
32
  <item row="1" column="0">
33
33
  <layout class="QGridLayout" name="gridLayout_5">
34
+ <item row="0" column="0">
35
+ <widget class="QRadioButton" name="_enable_range_x">
36
+ <property name="text">
37
+ <string>Range (s)</string>
38
+ </property>
39
+ <property name="autoExclusive">
40
+ <bool>false</bool>
41
+ </property>
42
+ </widget>
43
+ </item>
34
44
  <item row="0" column="1">
35
- <widget class="QLineEdit" name="_range_x_min">
45
+ <widget class="QDoubleSpinBox" name="_range_x_min">
36
46
  <property name="enabled">
37
47
  <bool>false</bool>
38
48
  </property>
39
- <property name="text">
40
- <string>0</string>
49
+ <property name="minimum">
50
+ <double>0</double>
51
+ </property>
52
+ <property name="maximum">
53
+ <double>86400</double>
54
+ </property>
55
+ <property name="singleStep">
56
+ <double>1</double>
57
+ </property>
58
+ <property name="value">
59
+ <double>0</double>
41
60
  </property>
42
61
  </widget>
43
62
  </item>
44
- <item row="0" column="2">
45
- <widget class="QLabel" name="label_2">
46
- <property name="text">
47
- <string>-</string>
63
+ <item row="0" column="4">
64
+ <widget class="QDoubleSpinBox" name="_range_x_max">
65
+ <property name="enabled">
66
+ <bool>false</bool>
67
+ </property>
68
+ <property name="minimum">
69
+ <double>0</double>
70
+ </property>
71
+ <property name="maximum">
72
+ <double>86400</double>
73
+ </property>
74
+ <property name="singleStep">
75
+ <double>1</double>
76
+ </property>
77
+ <property name="value">
78
+ <double>60</double>
48
79
  </property>
49
80
  </widget>
50
81
  </item>
@@ -70,7 +101,7 @@
70
101
  <string/>
71
102
  </property>
72
103
  <property name="maximum">
73
- <number>2000</number>
104
+ <number>3000</number>
74
105
  </property>
75
106
  <property name="singleStep">
76
107
  <number>100</number>
@@ -80,47 +111,8 @@
80
111
  </property>
81
112
  </widget>
82
113
  </item>
83
- <item row="0" column="3">
84
- <widget class="QLineEdit" name="_range_x_max">
85
- <property name="enabled">
86
- <bool>false</bool>
87
- </property>
88
- <property name="text">
89
- <string>1000</string>
90
- </property>
91
- </widget>
92
- </item>
93
- <item row="0" column="0">
94
- <widget class="QRadioButton" name="_enable_range_x">
95
- <property name="enabled">
96
- <bool>false</bool>
97
- </property>
98
- <property name="text">
99
- <string>Range</string>
100
- </property>
101
- <property name="autoExclusive">
102
- <bool>false</bool>
103
- </property>
104
- </widget>
105
- </item>
106
- <item row="3" column="0">
107
- <widget class="QRadioButton" name="_enable_manual_x">
108
- <property name="enabled">
109
- <bool>false</bool>
110
- </property>
111
- <property name="text">
112
- <string>Manual</string>
113
- </property>
114
- <property name="autoExclusive">
115
- <bool>false</bool>
116
- </property>
117
- </widget>
118
- </item>
119
114
  <item row="2" column="0">
120
115
  <widget class="QRadioButton" name="_enable_seconds_x">
121
- <property name="enabled">
122
- <bool>false</bool>
123
- </property>
124
116
  <property name="text">
125
117
  <string>Seconds</string>
126
118
  </property>
@@ -156,12 +156,17 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
156
156
  self._enable_samples_x.setChecked(True)
157
157
  self._last_ts = None
158
158
  self._dtime = None
159
+ self._first_ts = None
159
160
 
160
161
  self._x_range = (
161
162
  float(self._range_x_min.text()), float(self._range_x_max.text()))
162
163
  self._nbr_samples = int(self._nbr_of_samples_x.text())
163
-
164
164
  self._nbr_of_samples_x.valueChanged.connect(self._nbr_samples_changed)
165
+ self._nbr_seconds = int(self._nbr_of_seconds_x.text())
166
+ self._nbr_of_seconds_x.valueChanged.connect(self._nbr_of_seconds_changed)
167
+ self._range_x_min.valueChanged.connect(self._x_range_changed)
168
+ self._range_x_max.valueChanged.connect(self._x_range_changed)
169
+
165
170
  self._range_y_min.valueChanged.connect(self._y_range_changed)
166
171
  self._range_y_max.valueChanged.connect(self._y_range_changed)
167
172
 
@@ -175,8 +180,8 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
175
180
  self._x_btn_group.addButton(self._enable_range_x)
176
181
  self._x_btn_group.addButton(self._enable_samples_x)
177
182
  self._x_btn_group.addButton(self._enable_seconds_x)
178
- self._x_btn_group.addButton(self._enable_manual_x)
179
183
  self._x_btn_group.setExclusive(True)
184
+ self._x_btn_group.buttonClicked.connect(self._x_mode_change)
180
185
 
181
186
  self._draw_graph = True
182
187
  self._auto_redraw.stateChanged.connect(self._auto_redraw_change)
@@ -188,6 +193,20 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
188
193
  else:
189
194
  self._draw_graph = True
190
195
 
196
+ def _x_mode_change(self, box):
197
+ """Callback when user changes the X-axis mode"""
198
+ self._nbr_of_samples_x.setEnabled(False)
199
+ self._nbr_of_seconds_x.setEnabled(False)
200
+ self._range_x_min.setEnabled(False)
201
+ self._range_x_max.setEnabled(False)
202
+ if box == self._enable_range_x:
203
+ self._range_x_min.setEnabled(True)
204
+ self._range_x_max.setEnabled(True)
205
+ elif box == self._enable_samples_x:
206
+ self._nbr_of_samples_x.setEnabled(True)
207
+ elif box == self._enable_seconds_x:
208
+ self._nbr_of_seconds_x.setEnabled(True)
209
+
191
210
  def _y_mode_change(self, box):
192
211
  """Callback when user changes the Y-axis mode"""
193
212
  if box == self._enable_range_y:
@@ -228,6 +247,14 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
228
247
  """Callback when user changes the number of samples to be shown"""
229
248
  self._nbr_samples = val
230
249
 
250
+ def _nbr_of_seconds_changed(self, val):
251
+ """Callback when user changes the number of seconds to be shown"""
252
+ self._nbr_seconds = val
253
+
254
+ def _x_range_changed(self, val):
255
+ self._range_x_min.setMaximum(self._range_x_max.value()-1)
256
+ self._range_x_max.setMinimum(self._range_x_min.value()+1)
257
+
231
258
  def set_title(self, title):
232
259
  """
233
260
  Set the title of the plot.
@@ -254,11 +281,15 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
254
281
  pairs
255
282
  ts - timestamp of the data in ms
256
283
  """
257
- if not self._last_ts:
258
- self._last_ts = ts
259
- elif not self._last_ts:
284
+
285
+ if self._first_ts is None:
286
+ self._first_ts = ts
287
+
288
+ if self._last_ts is None:
289
+ self._dtime = 1e12
290
+ else:
260
291
  self._dtime = ts - self._last_ts
261
- self._last_ts = ts
292
+ self._last_ts = ts
262
293
 
263
294
  x_min_limit = 0
264
295
  x_max_limit = 0
@@ -266,6 +297,17 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
266
297
  if self._enable_samples_x.isChecked():
267
298
  x_min_limit = max(0, self._last_item - self._nbr_samples)
268
299
  x_max_limit = max(self._last_item, self._nbr_samples)
300
+ self._range_x_min.setValue(int(self._first_ts + x_min_limit * self._dtime)/1000.)
301
+ self._range_x_max.setValue(int(self._first_ts + x_max_limit * self._dtime)/1000.)
302
+ elif self._enable_seconds_x.isChecked():
303
+ x_min_limit = max(0, int(((self._last_ts - self._first_ts) - self._nbr_seconds * 1000.) / self._dtime))
304
+ x_max_limit = max(0, self._last_item)
305
+ print(self._first_ts, x_min_limit, x_max_limit, self._dtime, self._nbr_seconds)
306
+ self._range_x_min.setValue((self._first_ts + x_min_limit * self._dtime)/1000.)
307
+ self._range_x_max.setValue((self._first_ts + x_min_limit * self._dtime)/1000. + self._nbr_seconds)
308
+ elif self._enable_range_x.isChecked():
309
+ x_min_limit = max(0, int((self._range_x_min.value() * 1000. - self._first_ts) / self._dtime))
310
+ x_max_limit = max(0, int((self._range_x_max.value() * 1000. - self._first_ts) / self._dtime))
269
311
 
270
312
  for name in self._items:
271
313
  self._items[name].add_point(data[name], ts)
@@ -277,6 +319,11 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
277
319
  if (self._enable_samples_x.isChecked() and self._dtime and
278
320
  self._last_item < self._nbr_samples):
279
321
  self._x_max = self._x_min + self._nbr_samples * self._dtime
322
+ elif (self._enable_seconds_x.isChecked() and self._dtime and
323
+ self._last_item < int(self._nbr_seconds * 1000. / self._dtime)):
324
+ self._x_max = self._x_min + self._nbr_seconds * 1000.
325
+ elif (self._enable_range_x.isChecked() and self._dtime) and self._last_item < x_max_limit:
326
+ self._x_max = self._x_min + (x_max_limit - x_min_limit) * self._dtime
280
327
 
281
328
  self._last_item = self._last_item + 1
282
329
  self._plot_widget.getViewBox().setRange(
@@ -292,6 +339,7 @@ class PlotWidget(QtWidgets.QWidget, plot_widget_class):
292
339
  self._items = {}
293
340
  self._last_item = 0
294
341
  self._last_ts = None
342
+ self._first_ts = None
295
343
  self._dtime = None
296
344
  self._plot_widget.clear()
297
345
 
@@ -7,7 +7,7 @@
7
7
  # +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
8
8
  # || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
9
9
  #
10
- # Copyright (C) 2011-2023 Bitcraze AB
10
+ # Copyright (C) 2011-2024 Bitcraze AB
11
11
  #
12
12
  # Crazyflie Nano Quadcopter Client
13
13
  #
@@ -27,15 +27,11 @@
27
27
  # MA 02110-1301, USA.
28
28
 
29
29
  """
30
- The input module that will read joysticks/input devices and send control set-
31
- points to the Crazyflie. It will also accept settings from the UI.
32
-
33
- This module can use different drivers for reading the input device data.
34
- Currently it can just use the PySdl2 driver but in the future there will be a
35
- Linux and Windows driver that can bypass PySdl2.
30
+ The logconfigreader module is responsible for reading and parsing log
31
+ configuration data. This data is used to control what information is logged
32
+ in the client.
36
33
  """
37
34
 
38
- import glob
39
35
  import json
40
36
  import logging
41
37
  import os
@@ -68,10 +64,7 @@ class LogConfigReader():
68
64
  # Check if user config exists, otherwise copy files
69
65
  if (not os.path.exists(cfclient.config_path + "/log")):
70
66
  logger.info("No user config found, copying dist files")
71
- os.makedirs(cfclient.config_path + "/log")
72
- for f in glob.glob(
73
- cfclient.module_path + "/configs/log/[A-Za-z]*.json"):
74
- shutil.copy2(f, cfclient.config_path + "/log")
67
+ shutil.copytree(cfclient.module_path + "/configs/log", cfclient.config_path + "/log")
75
68
  self._cf = crazyflie
76
69
  self._cf.connected.add_callback(self._connected)
77
70
 
@@ -206,27 +199,27 @@ class LogConfigReader():
206
199
  self._log_configs = {'Default': []}
207
200
  log_path = os.path.join(cfclient.config_path, 'log')
208
201
 
209
- for cathegory in os.listdir(log_path):
202
+ for category in os.listdir(log_path):
210
203
 
211
- cathegory_path = os.path.join(log_path, cathegory)
204
+ category_path = os.path.join(log_path, category)
212
205
 
213
206
  try:
214
- if (os.path.isdir(cathegory_path)):
207
+ if (os.path.isdir(category_path)):
215
208
  # create a new cathegory
216
- self._log_configs[cathegory] = []
217
- for conf in os.listdir(cathegory_path):
209
+ self._log_configs[category] = []
210
+ for conf in os.listdir(category_path):
218
211
  if conf.endswith('.json'):
219
- conf_path = os.path.join(cathegory_path, conf)
212
+ conf_path = os.path.join(category_path, conf)
220
213
  log_conf = self._get_conf(conf_path)
221
214
 
222
215
  # add the log configuration to the cathegory
223
- self._log_configs[cathegory].append(log_conf)
216
+ self._log_configs[category].append(log_conf)
224
217
 
225
218
  else:
226
219
  # if it's not a directory, the log config is placed
227
220
  # in the 'Default' cathegory
228
- if cathegory_path.endswith('.json'):
229
- log_conf = self._get_conf(cathegory_path)
221
+ if category_path.endswith('.json'):
222
+ log_conf = self._get_conf(category_path)
230
223
  self._log_configs['Default'].append(log_conf)
231
224
 
232
225
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cfclient
3
- Version: 2024.3
3
+ Version: 2024.7
4
4
  Summary: Bitcraze Cazyflie quadcopter client
5
5
  Home-page: http://www.bitcraze.io
6
6
  Author: Bitcraze team
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.4
11
11
  Classifier: Programming Language :: Python :: 3.5
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.txt
14
- Requires-Dist: cflib >=0.1.25.1
14
+ Requires-Dist: cflib >=0.1.26
15
15
  Requires-Dist: setuptools
16
16
  Requires-Dist: appdirs ~=1.4.0
17
17
  Requires-Dist: pyzmq ~=25.0