simo 2.0.34__py3-none-any.whl → 2.0.37__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 simo might be problematic. Click here for more details.

Binary file
Binary file
simo/core/forms.py CHANGED
@@ -291,7 +291,7 @@ class ComponentAdminForm(forms.ModelForm):
291
291
 
292
292
  class Meta:
293
293
  model = Component
294
- fields = 'name', 'icon', 'zone', 'category', 'show_in_app', 'notes'
294
+ fields = 'name', 'icon', 'zone', 'category', 'show_in_app', 'notes',
295
295
  widgets = {
296
296
  'icon': autocomplete.ModelSelect2(
297
297
  url='autocomplete-icon', attrs={'data-html': True}
@@ -466,6 +466,13 @@ class NumericSensorForm(BaseComponentForm):
466
466
  ValueLimitForm, can_delete=True, can_order=True, extra=0, max_num=3
467
467
  ), label="Graph Limits"
468
468
  )
469
+ value_units = forms.CharField(required=False)
470
+
471
+
472
+ def __init__(self, *args, **kwargs):
473
+ super().__init__(*args, **kwargs)
474
+ self.fields['value_units'].initial = self.controller.default_value_units
475
+
469
476
 
470
477
 
471
478
  class MultiSensorConfigForm(BaseComponentForm):
@@ -660,6 +667,7 @@ class DimmerConfigForm(BaseComponentForm):
660
667
  max = forms.FloatField(
661
668
  initial=1.0, help_text="Maximum component value."
662
669
  )
670
+ value_units = forms.CharField(required=False)
663
671
  inverse = forms.BooleanField(
664
672
  label=_("Inverse dimmer signal"), required=False
665
673
  )
@@ -676,6 +684,7 @@ class DimmerConfigForm(BaseComponentForm):
676
684
 
677
685
  def __init__(self, *args, **kwargs):
678
686
  super().__init__(*args, **kwargs)
687
+ self.fields['value_units'].initial = self.controller.default_value_units
679
688
  if self.instance.pk:
680
689
  self.fields['slaves'].initial = self.instance.slaves.all()
681
690
 
@@ -704,6 +713,11 @@ class DimmerPlusConfigForm(BaseComponentForm):
704
713
  secondary_max = forms.FloatField(
705
714
  initial=1.0, help_text="Maximum secondary value."
706
715
  )
716
+ value_units = forms.CharField(required=False)
717
+
718
+ def __init__(self, *args, **kwargs):
719
+ super().__init__(*args, **kwargs)
720
+ self.fields['value_units'].initial = self.controller.default_value_units
707
721
 
708
722
 
709
723
  class RGBWConfigForm(BaseComponentForm):
simo/core/serializers.py CHANGED
@@ -375,7 +375,6 @@ class ComponentSerializer(FormSerializer):
375
375
  user_role = self.context['request'].user.get_role(
376
376
  self.context['instance']
377
377
  )
378
- print("FORM BASIC FIELDS: ", form.basic_fields)
379
378
  if not user_role.is_superuser and user_role.is_owner:
380
379
  for field_name in list(form.fields.keys()):
381
380
  if field_name not in form.basic_fields:
@@ -164,7 +164,10 @@ class FormsetField(forms.Field):
164
164
  elif isinstance(field, forms.fields.BooleanField):
165
165
  form_data[field_name] = form_data[field_name] == 'on'
166
166
  elif isinstance(field, forms.fields.IntegerField):
167
- form_data[field_name] = int(form_data[field_name])
167
+ try:
168
+ form_data[field_name] = int(form_data[field_name])
169
+ except:
170
+ form_data[field_name] = None
168
171
  if self.widget.formset.can_order:
169
172
  form_data['order'] = int(formset_data.get(
170
173
  '%s-%d-ORDER' % (prefix, i), 0
Binary file
simo/fleet/controllers.py CHANGED
@@ -223,12 +223,12 @@ class PWMOutput(FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
223
223
  elif value < conf.get('min', 0):
224
224
  value = conf.get('min', 0)
225
225
 
226
- if value == conf.get('max', 100):
226
+ if value >= conf.get('max', 100):
227
227
  if conf.get('inverse'):
228
228
  pwm_value = 0
229
229
  else:
230
230
  pwm_value = 1023
231
- elif value == conf.get('min', 100):
231
+ elif value <= conf.get('min', 100):
232
232
  if conf.get('inverse'):
233
233
  pwm_value = 1023
234
234
  else:
simo/fleet/forms.py CHANGED
@@ -84,8 +84,7 @@ class InterfaceAdminForm(forms.ModelForm):
84
84
 
85
85
  class ColonelComponentForm(BaseComponentForm):
86
86
  colonel = forms.ModelChoiceField(
87
- label="Colonel", queryset=Colonel.objects.all(),
88
- help_text="ATENTION! Changing Colonel after component creation is not recommended!"
87
+ label="Colonel", queryset=Colonel.objects.all()
89
88
  )
90
89
 
91
90
  def clean_colonel(self):
@@ -133,6 +132,7 @@ class ColonelComponentForm(BaseComponentForm):
133
132
  updated_vals[key] = int(val)
134
133
  self.cleaned_data['controls'][i] = updated_vals
135
134
 
135
+ pins_in_use = []
136
136
  formset_errors = {}
137
137
  for i, control in enumerate(self.cleaned_data['controls']):
138
138
  if pin_instances[i].colonel != self.cleaned_data['colonel']:
@@ -144,6 +144,11 @@ class ColonelComponentForm(BaseComponentForm):
144
144
  formset_errors[i] = {
145
145
  'pin': f"{pin_instances[i]} is already occupied by {pin_instances[i].occupied_by}!"
146
146
  }
147
+ elif pin_instances[i].no in pins_in_use:
148
+ formset_errors[i] = {
149
+ 'pin': f"{pin_instances[i].no} is already in use!"
150
+ }
151
+ pins_in_use.append(pin_instances[i].no)
147
152
 
148
153
  errors_list = []
149
154
  if formset_errors:
@@ -184,6 +189,9 @@ class ControlPinForm(forms.Form):
184
189
  ('momentary', "Momentary"), ('toggle', "Toggle"),
185
190
  ),
186
191
  )
192
+ debounce = forms.IntegerField(
193
+ required=False, help_text="Add debounce value in ms (10 - 200ms)"
194
+ )
187
195
  prefix = 'controls'
188
196
 
189
197
 
@@ -205,11 +213,11 @@ class ColonelBinarySensorConfigForm(ColonelComponentForm):
205
213
  "you deliver GND to the input and OFF when you cut it out."
206
214
  )
207
215
  debounce = forms.IntegerField(
208
- min_value=0, max_value=1000 * 60 * 60, required=False, initial=0,
216
+ min_value=0, max_value=1000 * 60 * 60, required=False, initial=50,
209
217
  help_text="Some sensors are unstable and quickly transition "
210
218
  "between ON/OFF states when engaged. <br>"
211
219
  "Set debounce value in milliseconds, to remediate this. "
212
- "100ms offers a good starting point!"
220
+ "50ms offers a good starting point!"
213
221
  )
214
222
 
215
223
  def clean(self):
@@ -421,6 +429,17 @@ class BME680SensorConfigForm(ColonelComponentForm):
421
429
 
422
430
  )
423
431
 
432
+ def clean(self):
433
+ if not self.cleaned_data.get('colonel'):
434
+ return self.cleaned_data
435
+ if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
436
+ self.add_error(
437
+ 'interface',
438
+ f"This interface is on {self.cleaned_data['interface'].colonel}, "
439
+ f"however we need an interface from {self.cleaned_data['colonel']}."
440
+ )
441
+ return self.cleaned_data
442
+
424
443
  def save(self, commit=True):
425
444
  if 'interface' in self.cleaned_data:
426
445
  self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
@@ -452,6 +471,17 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
452
471
 
453
472
  )
454
473
 
474
+ def clean(self):
475
+ if not self.cleaned_data.get('colonel'):
476
+ return self.cleaned_data
477
+ if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
478
+ self.add_error(
479
+ 'interface',
480
+ f"This interface is on {self.cleaned_data['interface'].colonel}, "
481
+ f"however we need an interface from {self.cleaned_data['colonel']}."
482
+ )
483
+ return self.cleaned_data
484
+
455
485
  def save(self, commit=True):
456
486
  if 'interface' in self.cleaned_data:
457
487
  self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
@@ -557,6 +587,14 @@ class ColonelSwitchConfigForm(ColonelComponentForm):
557
587
  if self.cleaned_data.get('controls'):
558
588
  self._clean_controls()
559
589
 
590
+ if self.cleaned_data.get('output_pin') and self.cleaned_data.get('controls'):
591
+ for ctrl in self.cleaned_data['controls']:
592
+ if ctrl['pin'] == self.cleaned_data['output_pin']:
593
+ self.add_error(
594
+ "output_pin",
595
+ "Can't be used as control pin at the same time!"
596
+ )
597
+
560
598
  return self.cleaned_data
561
599
 
562
600
 
@@ -589,6 +627,7 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
589
627
  required=True, initial=100,
590
628
  help_text="Maximum component value"
591
629
  )
630
+ value_units = forms.CharField(required=False)
592
631
  duty_min = forms.IntegerField(
593
632
  min_value=0, max_value=1023, required=True, initial=0,
594
633
  help_text="Minumum PWM signal output duty (0 - 1023)"
@@ -618,6 +657,7 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
618
657
  required=True, initial=100,
619
658
  help_text="Component ON value when used with toggle switch"
620
659
  )
660
+
621
661
  slaves = forms.ModelMultipleChoiceField(
622
662
  required=False,
623
663
  queryset=Component.objects.filter(
@@ -636,7 +676,10 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
636
676
 
637
677
  def __init__(self, *args, **kwargs):
638
678
  super().__init__(*args, **kwargs)
639
- self.basic_fields.extend(['turn_on_time', 'turn_off_time', 'skew'])
679
+ self.fields['value_units'].initial = self.controller.default_value_units
680
+ self.basic_fields.extend(
681
+ ['value_units', 'turn_on_time', 'turn_off_time', 'skew']
682
+ )
640
683
  if self.instance.pk and 'slaves' in self.fields:
641
684
  self.fields['slaves'].initial = self.instance.slaves.all()
642
685
 
@@ -651,6 +694,13 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
651
694
  self._clean_pin('output_pin')
652
695
  if 'controls' in self.cleaned_data:
653
696
  self._clean_controls()
697
+ if self.cleaned_data.get('output_pin') and self.cleaned_data.get('controls'):
698
+ for ctrl in self.cleaned_data['controls']:
699
+ if ctrl['pin'] == self.cleaned_data['output_pin']:
700
+ self.add_error(
701
+ "output_pin",
702
+ "Can't be used as control pin at the same time!"
703
+ )
654
704
  return self.cleaned_data
655
705
 
656
706
 
@@ -751,6 +801,14 @@ class ColonelRGBLightConfigForm(ColonelComponentForm):
751
801
  if self.cleaned_data.get('controls'):
752
802
  self._clean_controls()
753
803
 
804
+ if self.cleaned_data.get('output_pin') and self.cleaned_data.get('controls'):
805
+ for ctrl in self.cleaned_data['controls']:
806
+ if ctrl['pin'] == self.cleaned_data['output_pin']:
807
+ self.add_error(
808
+ "output_pin",
809
+ "Can't be used as control pin at the same time!"
810
+ )
811
+
754
812
  if 'color_order' in self.cleaned_data:
755
813
  if self.cleaned_data.get('color_order'):
756
814
  if self.cleaned_data['has_white']:
@@ -815,6 +873,12 @@ class DualMotorValveForm(ColonelComponentForm):
815
873
  self._clean_pin('open_pin')
816
874
  if self.cleaned_data.get('close_pin'):
817
875
  self._clean_pin('close_pin')
876
+ if self.cleaned_data.get('open_pin') \
877
+ and self.cleaned_data.get('close_pin') \
878
+ and self.cleaned_data['open_pin'] == self.cleaned_data['close_pin']:
879
+ self.add_error(
880
+ 'close_pin', "Can't be the same as open pin!"
881
+ )
818
882
  return self.cleaned_data
819
883
 
820
884
  def save(self, commit=True):
@@ -902,6 +966,13 @@ class BlindsConfigForm(ColonelComponentForm):
902
966
  def clean(self):
903
967
  super().clean()
904
968
 
969
+ if self.cleaned_data.get('open_pin') \
970
+ and self.cleaned_data.get('close_pin') \
971
+ and self.cleaned_data['open_pin'] == self.cleaned_data['close_pin']:
972
+ self.add_error(
973
+ 'close_pin', "Can't be the same as open pin!"
974
+ )
975
+
905
976
  if self.cleaned_data.get('open_pin'):
906
977
  self._clean_pin('open_pin')
907
978
  if self.cleaned_data.get('close_pin'):
@@ -923,6 +994,23 @@ class BlindsConfigForm(ColonelComponentForm):
923
994
  return self.cleaned_data
924
995
 
925
996
  self._clean_controls()
997
+
998
+ if self.cleaned_data.get('open_pin'):
999
+ for ctrl in self.cleaned_data['controls']:
1000
+ if ctrl['pin'] == self.cleaned_data['output_pin']:
1001
+ self.add_error(
1002
+ "open_pin",
1003
+ "Can't be used as control pin at the same time!"
1004
+ )
1005
+
1006
+ if self.cleaned_data.get('close_pin'):
1007
+ for ctrl in self.cleaned_data['controls']:
1008
+ if ctrl['pin'] == self.cleaned_data['close_pin']:
1009
+ self.add_error(
1010
+ "close_pin",
1011
+ "Can't be used as control pin at the same time!"
1012
+ )
1013
+
926
1014
  return self.cleaned_data
927
1015
 
928
1016
  def save(self, commit=True):
@@ -971,6 +1059,13 @@ class BurglarSmokeDetectorConfigForm(ColonelComponentForm):
971
1059
  if 'power_pin' in self.cleaned_data:
972
1060
  self._clean_pin('power_pin')
973
1061
 
1062
+ if self.cleaned_data.get('sensor_pin') \
1063
+ and self.cleaned_data.get('power_pin') \
1064
+ and self.cleaned_data['sensor_pin'] == self.cleaned_data['power_pin']:
1065
+ self.add_error(
1066
+ 'power_pin', "Can't be the same as sensor pin!"
1067
+ )
1068
+
974
1069
  return self.cleaned_data
975
1070
 
976
1071
  def save(self, commit=True):
@@ -1046,6 +1141,17 @@ class DALIDeviceConfigForm(ColonelComponentForm):
1046
1141
  )
1047
1142
  return self.cleaned_data['interface']
1048
1143
 
1144
+ def clean(self):
1145
+ if not self.cleaned_data.get('colonel'):
1146
+ return self.cleaned_data
1147
+ if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
1148
+ self.add_error(
1149
+ 'interface',
1150
+ f"This interface is on {self.cleaned_data['interface'].colonel}, "
1151
+ f"however we need an interface from {self.cleaned_data['colonel']}."
1152
+ )
1153
+ return self.cleaned_data
1154
+
1049
1155
  def save(self, commit=True, update_colonel_config=True):
1050
1156
  if 'interface' in self.cleaned_data:
1051
1157
  self.instance.config['dali_interface'] = \
simo/generic/forms.py CHANGED
@@ -270,7 +270,6 @@ class AlarmGroupConfigForm(BaseComponentForm):
270
270
  )
271
271
  has_alarm = False
272
272
 
273
-
274
273
  def __init__(self, *args, **kwargs):
275
274
  super().__init__(*args, **kwargs)
276
275
  from .controllers import AlarmGroup
@@ -281,9 +280,10 @@ class AlarmGroupConfigForm(BaseComponentForm):
281
280
  config__is_main=True
282
281
  ).count()
283
282
  )
284
- self.fields['is_main'].initial = first_alarm_group
285
- if first_alarm_group:
286
- self.fields['is_main'].widget.attrs['disabled'] = 'disabled'
283
+ if 'is_main' in self.fields:
284
+ self.fields['is_main'].initial = first_alarm_group
285
+ if first_alarm_group:
286
+ self.fields['is_main'].widget.attrs['disabled'] = 'disabled'
287
287
  else:
288
288
  if self.instance.config.get('is_main'):
289
289
  self.fields['is_main'].widget.attrs['disabled'] = 'disabled'
simo/users/api.py CHANGED
@@ -35,7 +35,9 @@ class UsersViewSet(mixins.RetrieveModelMixin,
35
35
  email__in=('system@simo.io', 'device@simo.io')
36
36
  ) # Exclude system user
37
37
 
38
- return queryset.filter(roles__instance=self.instance)
38
+ return queryset.filter(
39
+ Q(roles__instance=self.instance) | Q(id=self.request.user.id)
40
+ )
39
41
 
40
42
 
41
43
  def check_permission_to_change(self, request, target_user):
simo/users/serializers.py CHANGED
@@ -24,11 +24,12 @@ class UserSerializer(serializers.ModelSerializer):
24
24
  class Meta:
25
25
  model = User
26
26
  fields = (
27
- 'id', 'email', 'name', 'avatar', 'role', 'is_active',
27
+ 'id', 'email', 'name', 'avatar', 'role', 'is_master', 'is_active',
28
28
  'at_home', 'last_action'
29
29
  )
30
30
  read_only_fields = (
31
- 'id', 'email', 'name', 'avatar', 'at_home', 'last_action', 'ssh_key'
31
+ 'id', 'email', 'name', 'avatar', 'at_home', 'last_action', 'ssh_key',
32
+ 'is_master'
32
33
  )
33
34
 
34
35
  def get_is_active(self, obj):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.0.34
3
+ Version: 2.0.37
4
4
  Summary: Smart Home on Steroids!
5
5
  Author-email: Simanas Venčkauskas <simanas@simo.io>
6
6
  Project-URL: Homepage, https://simo.io
@@ -38,7 +38,7 @@ simo/core/controllers.py,sha256=Z_sXPaehJcOS8Zz1UZZ2n7-1cjx3_B9dVjHBQHgjtTc,2728
38
38
  simo/core/dynamic_settings.py,sha256=U2WNL96JzVXdZh0EqMPWrxqO6BaRR2Eo5KTDqz7MC4o,1943
39
39
  simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
40
40
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
41
- simo/core/forms.py,sha256=VoNKoLDR7AAJWHiEUTT8tYcNoVwZh4XxX1-lZEoRzpI,23688
41
+ simo/core/forms.py,sha256=f0_qnyrIem9yj5BKDAenzG5XK_tW7PGKWLuLKb3wPgg,24252
42
42
  simo/core/gateways.py,sha256=s_c2W0v2_te89i6LS4Nj7F2wn9UwjZXPT7pfy6SToVo,3714
43
43
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
44
44
  simo/core/managers.py,sha256=Qdg2-Qh4dLbW0A5Dmtnpct6CUhEuuvdbIskBijQxopU,2360
@@ -46,7 +46,7 @@ simo/core/middleware.py,sha256=pO52hQOJV_JRmNyUe7zfufSnJFlRITOWX6jwkoPWJhk,2052
46
46
  simo/core/models.py,sha256=W5rShDy8l6GQzTRFiBZFAuibe_fg_LRwSNk973mv_m8,20134
47
47
  simo/core/permissions.py,sha256=yqVXq6SNZccSKcOoGdb0oh-WHsyTTtI9ovJdJyhjv28,2707
48
48
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
49
- simo/core/serializers.py,sha256=dbQ78K9ePBChFPjJHXGj8BkqXQfIFcfFpOtcupGUuz8,18337
49
+ simo/core/serializers.py,sha256=7iE5_ke56GpcQ_cV6LgQIsfG3pAQXPc3t4e60HwogUs,18277
50
50
  simo/core/signal_receivers.py,sha256=C6Jk7wVEtyo4hwcrU7L0ijtpK0wce2MNwpyBgSfSJ-U,5467
51
51
  simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
52
52
  simo/core/storage.py,sha256=YlxmdRs-zhShWtFKgpJ0qp2NDBuIkJGYC1OJzqkbttQ,572
@@ -57,7 +57,7 @@ simo/core/views.py,sha256=hlAKpAbCbqI3a-uL5tDp532T2oLFiF0MBzKUJ_SNzo0,5833
57
57
  simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
58
58
  simo/core/__pycache__/__init__.cpython-38.pyc,sha256=y0IW37wBUIGa3Eh_ZG28pRqHKoLiPyTgUX2OnbkEPlc,158
59
59
  simo/core/__pycache__/admin.cpython-38.pyc,sha256=1OisxqtyWMbzpgeeu5vtBW3gp3Nts4Ei4ff1P-SPpq4,13545
60
- simo/core/__pycache__/api.cpython-38.pyc,sha256=RsMxUiiMEEXsSh2fBbrkjsIUOKUy81dmN9_20SB7CR8,19942
60
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=YBk4BVAMxAkShEyWgeTkHtTpr4P-tMwrTQI5TTP7vFE,19968
61
61
  simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=5UTBr3rDMERAfc0OuOVDwGeQkt6Q7GLBtZJAMBse1sg,1712
62
62
  simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=94T3_rybn2T1_bkaDQnQRyjy21LBaGOnz-mmkJ6T0N8,2840
63
63
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=9Es2wZNduzUJv-jZ_HX0-L3vqwpXWBbseEwoC5K6b-w,3465
@@ -77,11 +77,11 @@ simo/core/__pycache__/middleware.cpython-38.pyc,sha256=ESR5JPtITo9flczO0672sfzYU
77
77
  simo/core/__pycache__/models.cpython-38.pyc,sha256=UNX6Btm5ZnpLzSCWgevQnSYzAyDWttA2Ivy7CGPu8DU,17288
78
78
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=flJOCh94U8mFhE0XWzUD0sGR6Xe1HlfG4hQtNSnAGZ4,2788
79
79
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
80
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=ltj2lqyqt2ctV6svTQ_VkTmq_aOx8iPhTdu5QQhScdk,17213
80
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=8QlBSWOtgmhTpFbMMgGoXtMoTMETSnpA37z2LBgRzNQ,17178
81
81
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=UcKT8RK_14CI-JEWfplnIxskmWec_w5-gqKUXITLDA4,4323
82
82
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=NJUr7nRyHFvmAumxxWpsod5wzVVZM99rCEuJs1utHA4,8432
83
83
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=BTkYH8QQyjqI0WOtJC8fHNtgu0YA1vjqZclXjC2vCVI,1116
84
- simo/core/__pycache__/tasks.cpython-38.pyc,sha256=7qQsnj1VkWTrYQNwfXH8SKkiaXBQteibciubKWPClXU,9139
84
+ simo/core/__pycache__/tasks.cpython-38.pyc,sha256=yt2G8HPIkx1Djz4oVBfhUW9WOR9GOdxLhHFXViQJc6A,9139
85
85
  simo/core/__pycache__/todos.cpython-38.pyc,sha256=lOqGZ58siHM3isoJV4r7sg8igrfE9fFd-jSfeBa0AQI,253
86
86
  simo/core/__pycache__/views.cpython-38.pyc,sha256=YrKRZPaV_JM4VGpdhVhsK-90UwUTOqp-V-Yj0SRGZgs,4212
87
87
  simo/core/__pycache__/widgets.cpython-38.pyc,sha256=sR0ZeHCHrhnNDBJuRrxp3zUsfBp0xrtF0xrK2TkQv1o,3520
@@ -10149,7 +10149,7 @@ simo/core/utils/config_values.py,sha256=4HCQmv5wQdupd16WOp80oJSyU7EDccjUO6blX--d
10149
10149
  simo/core/utils/easing.py,sha256=N2NwD0CjLh82RGaYJKjyt-VVpVeS9z0mba8fqr8A1t0,1499
10150
10150
  simo/core/utils/form_fields.py,sha256=UOzYdPd71qgCw1H3qH01u85YjrOlETPJAHOJrZKhyD0,627
10151
10151
  simo/core/utils/form_widgets.py,sha256=Zxn9jJqPle9Q_BKNJnyTDn7MosYwNp1TFu5LoKs0bfc,408
10152
- simo/core/utils/formsets.py,sha256=1u34QGZ2P67cxZD2uUJS3lAf--E8XsiiqFmZ4P41Vw4,6463
10152
+ simo/core/utils/formsets.py,sha256=1v2folVgoOd915LMQjyb0OMBuQ535HPq6uymm5m35ZU,6573
10153
10153
  simo/core/utils/helpers.py,sha256=TOWy3slspaEYEhe9zDcb0RgzHUYslF6LZDlrWPGSqUI,3791
10154
10154
  simo/core/utils/json.py,sha256=x3kMiiK30vuyWSYfghLVsDKo0N2JlCxZ5n8cwel85Vk,464
10155
10155
  simo/core/utils/logs.py,sha256=Zn9JQxqCH9Odx2J1BWT84nFCfkJ4Z4p5X8psdll7hNc,2366
@@ -10182,8 +10182,8 @@ simo/fleet/api.py,sha256=Hxn84xI-Q77HxjINgRbjSJQOv9jii4OL20LxK0VSrS8,2499
10182
10182
  simo/fleet/auto_urls.py,sha256=X04oKJWA48wFW5iXg3PPROY2KDdHn_a99orQSE28QC4,518
10183
10183
  simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
10184
10184
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10185
- simo/fleet/controllers.py,sha256=ROQWoCWLOiXX4Xh2E9ZPor1ypOibGfd7m8GItP1Si28,23172
10186
- simo/fleet/forms.py,sha256=d3j_nv8uW1e3ptmaMlJZ6buOdFVKOfs6J7WyCbcKoYA,43582
10185
+ simo/fleet/controllers.py,sha256=WCqOA5Qrn9RavdfcB8X06WwaTE-9TGUprTQHZ8V8-nA,23172
10186
+ simo/fleet/forms.py,sha256=7MuKBfOUgXuLDsSYo0jQHYxWJxQiTB95K7ogwULmp84,48121
10187
10187
  simo/fleet/gateways.py,sha256=KV5i5fxXIrlK-k6zyEkk83x11GJt-ELQ0npb4Ac83cM,3693
10188
10188
  simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
10189
10189
  simo/fleet/models.py,sha256=bD5AebGFCAYGXPYhTA2nK1X9KpMG4WK4zFk9OzBDoHI,15301
@@ -10199,11 +10199,11 @@ simo/fleet/__pycache__/api.cpython-38.pyc,sha256=rL9fb7cCQatyFvXyKmlNOKmxVo8vHYe
10199
10199
  simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=SqyTuaz_kEBvx-bL46SclsZEEP5RFh6U6TGKyXDdiOE,565
10200
10200
  simo/fleet/__pycache__/base_types.cpython-38.pyc,sha256=deyPwjpT6xZiFxBGFnj5b7R-lbdOTh2krgpJhrcGVhc,274
10201
10201
  simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
10202
- simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=IInB1lBX4uFj1ZDyzCJEDABPXWTMwUpKBczkoJyj4SI,19842
10203
- simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=aW_L2Q8y7YACrV6wlO3_JL-Id_16biEkXT_BAPnqzHg,31617
10202
+ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=TN3yvfZJgS7FwzgP4S1aDoaOqxbKj2oXfXOxqbkIXJU,19856
10203
+ simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=spAw3w0y42aF0driUhxT6QrDDOom3KkOrgoFYwAwqak,31698
10204
10204
  simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=YAcgTOqJbtjGI03lvEcU6keFfrwAHkObVmErYzfRvjk,3569
10205
10205
  simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
10206
- simo/fleet/__pycache__/models.cpython-38.pyc,sha256=dQ5Fj9nXg7vgFfACzxWurhqGw8EnYa9Px7SwmGiAih4,12904
10206
+ simo/fleet/__pycache__/models.cpython-38.pyc,sha256=LjcLsSytCQd17xhH-5RrzvnZ6JYI1ilvNdCY2iUCsGc,12935
10207
10207
  simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
10208
10208
  simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=9ljhwoHkolcVrJwOVbYCbGPAUKgALRwor_M3W_K0adE,3173
10209
10209
  simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=0-WhvzVsVJ5A_AgoKnWKOJjoJioLDNsYX4C6bGJANwQ,13551
@@ -10286,7 +10286,7 @@ simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10286
10286
  simo/generic/app_widgets.py,sha256=E_pnpA1hxMIhenRCrHoQ5cik06jm2BAHCkl_eo-OudU,1264
10287
10287
  simo/generic/base_types.py,sha256=djymox_boXTHX1BTTCLXrCH7ED-uAsV_idhaDOc3OLI,409
10288
10288
  simo/generic/controllers.py,sha256=WYuOUzDWvkYRaTvlbdGy_qmwp1o_ohqKDfV7OrOq2QU,52218
10289
- simo/generic/forms.py,sha256=NPHNg_8BPTIJt-DR0-GkNWgVo9bE0_50PUWSnpIE4Dg,24262
10289
+ simo/generic/forms.py,sha256=ZKK7uqSHTff_sAX7ZWZZpf5l1uvyosdXa_BCX9tLuf0,24314
10290
10290
  simo/generic/gateways.py,sha256=RcHubz3oyY_ysPLNPLRoyh8C6r-WfPzpD98OVkDvPPI,17731
10291
10291
  simo/generic/models.py,sha256=92TACMhJHadAg0TT9GnARO_R3_Sl6i-GGjhG_x7YdFI,7391
10292
10292
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
@@ -10372,14 +10372,14 @@ simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.
10372
10372
  simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=YMBRHVon2nWDtIUbghckjnC12sIg_ykPWhV5aM0tto4,178
10373
10373
  simo/users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10374
10374
  simo/users/admin.py,sha256=6RKGnwcrmewJFPzpqnxYn8rxjHO4tJPVFJvA3eMum2s,6746
10375
- simo/users/api.py,sha256=FVo2bHkGA9VKavyjQm8_wfvI5rQ5KcMZliRiTJjixmI,9462
10375
+ simo/users/api.py,sha256=vf11fV8ZCao3Q2TdUO8mDTF3n0N3JYad7CUhz7_ZrZQ,9516
10376
10376
  simo/users/auth_backends.py,sha256=I5pnaTa20-Lxfw_dFG8471xDITb0_fQl1PVhJalp5vU,3992
10377
10377
  simo/users/auto_urls.py,sha256=lcJvteBsbHQMJieZpDz-63tDYejLApqsW3CUnDakd7k,272
10378
10378
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
10379
10379
  simo/users/middleware.py,sha256=GMCrnWSc_2qCleyQIkfQGdL-pU-UTEcSg1wPvIKZ9uk,1210
10380
10380
  simo/users/models.py,sha256=I_iAa-6CLORshmGszSl021zl97oaXNIEOZYMSq5Wn5M,18902
10381
10381
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
10382
- simo/users/serializers.py,sha256=e6yIUsO7BfvrZ4IQHBn-FdpAUMgic5clmGQdTtRlGRY,2515
10382
+ simo/users/serializers.py,sha256=DwbFGi4WeTYXOSnfrBfd5rC5OGtevYurn27EaTVa1EU,2553
10383
10383
  simo/users/sso_urls.py,sha256=gQOaPvGMYFD0NCVSwyoWO-mTEHe5j9sbzV_RK7kdvp0,251
10384
10384
  simo/users/sso_views.py,sha256=-XI67TvQ7SN3goU4OuAHyn84u_1vtusvpn7Pu0K97zo,4648
10385
10385
  simo/users/tasks.py,sha256=v9J7t4diB0VnqUDVZAQ8H-rlr4ZR14bgEUuEGpODyOI,854
@@ -10466,8 +10466,8 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10466
10466
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10467
10467
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10468
10468
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10469
- simo-2.0.34.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10470
- simo-2.0.34.dist-info/METADATA,sha256=aupHMz4VI42i2kPGzjG86agyXhh2e5V_Zc-FI9MLUcA,1730
10471
- simo-2.0.34.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
10472
- simo-2.0.34.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10473
- simo-2.0.34.dist-info/RECORD,,
10469
+ simo-2.0.37.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10470
+ simo-2.0.37.dist-info/METADATA,sha256=xKOE5qzOHNzbeyUNG_nM_qrb0pPynAJuc-Qshb9UjUs,1730
10471
+ simo-2.0.37.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
10472
+ simo-2.0.37.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10473
+ simo-2.0.37.dist-info/RECORD,,
File without changes