simo 2.2.2__py3-none-any.whl → 2.2.4__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
Binary file
simo/core/admin.py CHANGED
@@ -264,6 +264,11 @@ class ComponentAdmin(EasyObjectsDeleteMixin, admin.ModelAdmin):
264
264
  # for displaying component controller info.
265
265
  #change_form_template = 'admin/core/component_change_form.html'
266
266
 
267
+ def has_change_permission(self, request, obj=None):
268
+ if not obj or not obj.controller or not obj.controller.masters_only:
269
+ return True
270
+ return request.user.is_master
271
+
267
272
  def get_fieldsets(self, request, obj=None):
268
273
  form = self._get_form_for_get_fields(request, obj)
269
274
  fieldsets = form.get_admin_fieldsets(request, obj)
@@ -380,14 +385,14 @@ class ComponentAdmin(EasyObjectsDeleteMixin, admin.ModelAdmin):
380
385
 
381
386
  else:
382
387
  if request.method == 'POST':
383
- ctx['form'] = CompTypeSelectForm(gateway, data=request.POST)
388
+ ctx['form'] = CompTypeSelectForm(gateway, request, data=request.POST)
384
389
  if ctx['form'].is_valid():
385
390
  request.session['add_comp_type'] = \
386
391
  ctx['form'].cleaned_data['controller_type']
387
392
  return redirect(request.path)
388
393
 
389
394
  else:
390
- ctx['form'] = CompTypeSelectForm(gateway)
395
+ ctx['form'] = CompTypeSelectForm(gateway, request)
391
396
  else:
392
397
  if request.method == 'POST':
393
398
  ctx['form'] = GatewaySelectForm(data=request.POST)
simo/core/api.py CHANGED
@@ -690,10 +690,10 @@ class ControllerTypes(InstanceMixin, viewsets.GenericViewSet):
690
690
  return permissions
691
691
 
692
692
  def list(self, request, *args, **kwargs):
693
- from .utils.type_constants import CONTROLLER_TYPES_MAP
693
+ from .utils.type_constants import get_controller_types_map
694
694
  data = {}
695
695
 
696
- for uid, cls in CONTROLLER_TYPES_MAP.items():
696
+ for uid, cls in get_controller_types_map(user=request.user).items():
697
697
  if cls.gateway_class.name not in data:
698
698
  data[cls.gateway_class.name] = []
699
699
  data[cls.gateway_class.name].append({
simo/core/controllers.py CHANGED
@@ -39,6 +39,7 @@ class ControllerBase(ABC):
39
39
  discovery_msg = None
40
40
  manual_add = True # Can be added manually
41
41
  family = None
42
+ masters_only = False # component can be created/modified by hub masters only
42
43
 
43
44
  @property
44
45
  @abstractmethod
simo/core/forms.py CHANGED
@@ -23,7 +23,7 @@ class HiddenField(forms.CharField):
23
23
  Hidden field used in API
24
24
  '''
25
25
  def __init__(self, *args, **kwargs):
26
- super().__init__(widget=forms.HiddenInput())
26
+ super().__init__(widget=forms.HiddenInput(), *args, **kwargs)
27
27
 
28
28
 
29
29
  class AdminAuthenticationForm(OrgAdminAuthenticationForm):
@@ -185,10 +185,21 @@ class GatewaySelectForm(forms.Form):
185
185
  class CompTypeSelectForm(forms.Form):
186
186
  controller_type = forms.ChoiceField(choices=())
187
187
 
188
- def __init__(self, gateway, *args, **kwargs):
188
+ def __init__(self, gateway, request, *args, **kwargs):
189
189
  super().__init__(*args, **kwargs)
190
190
  if gateway:
191
- from .utils.type_constants import CONTROLLERS_BY_GATEWAY
191
+ from .utils.type_constants import (
192
+ GATEWAYS_MAP, get_controller_types_map
193
+ )
194
+
195
+ CONTROLLERS_BY_GATEWAY = {}
196
+ for gateway_slug, gateway_cls in GATEWAYS_MAP.items():
197
+ CONTROLLERS_BY_GATEWAY[gateway_slug] = {}
198
+ for ctrl_uid, ctrl_cls in get_controller_types_map(
199
+ gateway_cls, user=request.user
200
+ ).items():
201
+ CONTROLLERS_BY_GATEWAY[gateway_slug][ctrl_uid] = ctrl_cls
202
+
192
203
  self.fields['controller_type'].choices = [
193
204
  (cls.uid, cls.name) for cls in CONTROLLERS_BY_GATEWAY.get(
194
205
  gateway.handler.uid, {}
simo/core/middleware.py CHANGED
@@ -65,9 +65,8 @@ def instance_middleware(get_response):
65
65
 
66
66
  if not instance:
67
67
  if request.user.is_authenticated:
68
- if len(request.user.instances) == 1:
69
- for inst in request.user.instances:
70
- instance = inst
68
+ if request.user.instances:
69
+ instance = list(request.user.instances)[0]
71
70
 
72
71
  if instance:
73
72
  introduce_instance(instance, request)
simo/core/permissions.py CHANGED
@@ -80,6 +80,8 @@ class ComponentPermission(BasePermission):
80
80
  return True
81
81
  if request.user.is_master:
82
82
  return True
83
+ if obj.controller.masters_only:
84
+ return False
83
85
  user_role = request.user.get_role(view.instance)
84
86
  if user_role.is_superuser:
85
87
  return True
simo/core/serializers.py CHANGED
@@ -257,6 +257,7 @@ class ComponentSerializer(FormSerializer):
257
257
  battery_level = ObjectSerializerMethodField()
258
258
  controller_methods = serializers.SerializerMethodField()
259
259
  info = serializers.SerializerMethodField()
260
+ masters_only = serializers.SerializerMethodField()
260
261
 
261
262
  class Meta:
262
263
  form = ComponentAdminForm
@@ -522,6 +523,9 @@ class ComponentSerializer(FormSerializer):
522
523
  def get_slaves(self, obj):
523
524
  return [c['id'] for c in obj.slaves.all().values('id')]
524
525
 
526
+ def get_masters_only(self, obj):
527
+ return obj.controller.masters_only
528
+
525
529
 
526
530
  class ZoneSerializer(serializers.ModelSerializer):
527
531
  components = serializers.SerializerMethodField()
@@ -5,7 +5,7 @@ from ..gateways import BaseGatewayHandler
5
5
  from ..app_widgets import BaseAppWidget
6
6
 
7
7
 
8
- def get_controller_types_map(gateway=None):
8
+ def get_controller_types_map(gateway=None, user=None):
9
9
  from ..controllers import ControllerBase
10
10
  controllers_map = {}
11
11
  for name, app in apps.app_configs.items():
@@ -38,6 +38,9 @@ def get_controller_types_map(gateway=None):
38
38
  else:
39
39
  if not same:
40
40
  continue
41
+ if user and not user.is_master and cls.masters_only:
42
+ continue
43
+
41
44
  controllers_map[cls.uid] = cls
42
45
  return controllers_map
43
46
 
@@ -46,6 +46,7 @@ from .forms import (
46
46
  # ----------- Generic controllers -----------------------------
47
47
 
48
48
  class Script(ControllerBase, TimerMixin):
49
+ masters_only = True
49
50
  name = _("Script")
50
51
  base_type = 'script'
51
52
  gateway_class = GenericGatewayHandler
@@ -102,6 +103,7 @@ class Script(ControllerBase, TimerMixin):
102
103
 
103
104
 
104
105
  class PresenceLighting(Script):
106
+ masters_only = False
105
107
  name = _("Presence lighting")
106
108
  config_form = PresenceLightingConfigForm
107
109
 
@@ -793,8 +795,6 @@ class Watering(ControllerBase):
793
795
  'ai_assist': True, 'soil_type': 'loamy', 'ai_assist_level': 50,
794
796
  'schedule': config_to_dict(self._get_default_schedule()),
795
797
  'estimated_moisture': 50,
796
- 'last_run': None,
797
- 'next_run': None,
798
798
  }
799
799
 
800
800
 
@@ -836,7 +836,7 @@ class Watering(ControllerBase):
836
836
  def start(self):
837
837
  self.component.refresh_from_db()
838
838
  if not self.component.value.get('program_progress', 0):
839
- self.component.config['last_run'] = timezone.now().timestamp()
839
+ self.component.meta['last_run'] = timezone.now().timestamp()
840
840
  self.component.save()
841
841
  self.set(
842
842
  {'status': 'running_program',
simo/generic/forms.py CHANGED
@@ -333,18 +333,20 @@ class AlarmBreachEventForm(forms.Form):
333
333
  if not self.cleaned_data.get('breach_action'):
334
334
  return self.cleaned_data
335
335
  component = self.cleaned_data.get('component')
336
- if not hasattr(component, self.cleaned_data['breach_action']):
336
+ if not getattr(component, self.cleaned_data['breach_action'], None):
337
337
  self.add_error(
338
338
  'breach_action',
339
339
  f"{component} has no {self.cleaned_data['breach_action']} action!"
340
340
  )
341
341
  if self.cleaned_data.get('disarm_action'):
342
- if not hasattr(component, self.cleaned_data['disarm_action']):
342
+ if not getattr(component, self.cleaned_data['disarm_action'], None):
343
343
  self.add_error(
344
344
  'disarm_action',
345
345
  f"{component} has no "
346
346
  f"{self.cleaned_data['disarm_action']} action!"
347
347
  )
348
+ if not self.cleaned_data.get('uid'):
349
+ self.cleaned_data['uid'] = get_random_string(6)
348
350
  return self.cleaned_data
349
351
 
350
352
 
@@ -434,14 +436,6 @@ class AlarmGroupConfigForm(BaseComponentForm):
434
436
  self.fields['is_main'].widget.attrs['disabled'] = 'disabled'
435
437
 
436
438
 
437
- def clean_breach_events(self):
438
- events = self.cleaned_data['breach_events']
439
- for i, cont in enumerate(events):
440
- if not cont.get('uid'):
441
- cont['uid'] = get_random_string(6)
442
- return events
443
-
444
-
445
439
  def recurse_check_alarm_groups(self, components, start_comp=None):
446
440
  for comp in components:
447
441
  check_cmp = start_comp if start_comp else comp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.2.2
3
+ Version: 2.2.4
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
@@ -13,8 +13,8 @@ simo/__pycache__/settings.cpython-38.pyc,sha256=ZdhdXOZPZOAljVIHlClO3YFQLpRlqi4L
13
13
  simo/__pycache__/urls.cpython-38.pyc,sha256=u0x6EqT8S1YfDOSPgbI8Kf-RDlveY9OV-EDXMYKAQ7w,2125
14
14
  simo/__pycache__/wsgi.cpython-38.pyc,sha256=TpRxO7VM_ql31hbKphVdanydC5RI1nHB4l0QA2pdWxo,322
15
15
  simo/core/__init__.py,sha256=_s2TjJfQImsMrTIxqLAx9AZie1Ojmm6sCHASdl3WLGU,50
16
- simo/core/admin.py,sha256=Gb1lSyvFtYj2oC5lA7j3VqU6zlqlncx5R-_XJbb8Wdk,17927
17
- simo/core/api.py,sha256=SNBhrN60ig64VNZS-gOhHr7bT9uq9dba3ozKrgsbaEs,27899
16
+ simo/core/admin.py,sha256=hoJ0OhfWL9T0d6JCY6_Gm3GR-nrgtDR2UQM67rMsjiE,18141
17
+ simo/core/api.py,sha256=ZS8e1bd2jjA8a_l7fDpXYBQC4IOYYxe4JoMSAIhRa0Y,27926
18
18
  simo/core/api_auth.py,sha256=vCxvczA8aWNcW0VyKs5WlC_ytlqeGP_H_hkKUNVkCwM,1247
19
19
  simo/core/api_meta.py,sha256=EaiY-dCADP__9MvLpoHvhjytFT92IrxPZDv95xgqasU,4955
20
20
  simo/core/app_widgets.py,sha256=4Lh9FDzdkfh_mccJMe09dyRTT3Uqf9VXwbkurJ9E9oQ,2115
@@ -23,20 +23,20 @@ simo/core/auto_urls.py,sha256=nNXEgLAAAQAhRWQDA9AbDtw-zcPKmu_pufJaSa8g818,1102
23
23
  simo/core/autocomplete_views.py,sha256=JT5LA2_Wtr60XYSAIqaXFKFYPjrmkEf6yunXD9y2zco,4022
24
24
  simo/core/base_types.py,sha256=qVh6MrXZEfN7bFOyFftC7u0yyz0PkvpsjllLBc6SCp4,616
25
25
  simo/core/context.py,sha256=98PXAMie43faRVBFkOG22uNpvGRNprcGhzjBFkrxaRY,1367
26
- simo/core/controllers.py,sha256=y6nB_iv1KxsyNutGRYZIBAHua2BHuV7OMRBD9nJXFbg,29521
26
+ simo/core/controllers.py,sha256=rLgJqnEMzRC0GpZnQb0m_Cz43Gp2zaYbODU7UUxE5oA,29602
27
27
  simo/core/dynamic_settings.py,sha256=U9pY7p_hoeD1LxobIvxZqQ7Zn_4MhYMqZvsr4O0PAYs,1871
28
28
  simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
29
29
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
30
30
  simo/core/form_fields.py,sha256=9tIjiEN3IE55GPyB4tOlfkd51JDne3-h8pKhpL3tLFE,2220
31
- simo/core/forms.py,sha256=QTPEe7nxzhg8NNCQFsVJpoO1LQW6MNNTHkEhBs7keYw,21386
31
+ simo/core/forms.py,sha256=AE-WWLOCH1O2TkhGzmYX2yr3QZJEB4mVh111SLVBuys,21851
32
32
  simo/core/gateways.py,sha256=m0eS3XjVe34Dge6xtoCq16kFWCKJcdQrT0JW0REqoq8,3715
33
33
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
34
34
  simo/core/managers.py,sha256=n-b3I4uXzfHKTeB1VMjSaMsDUxp8FegFJwnbV1IsWQ4,3019
35
- simo/core/middleware.py,sha256=Go4DAdnXWd7i0ZEbftwfcZI5YGjZ31aQqDzWE4s676c,1970
35
+ simo/core/middleware.py,sha256=LIMpHJDQ4zx9dfmy5z0-rEW2EPO9d-iG1ZJbJ_6t6hc,1927
36
36
  simo/core/models.py,sha256=Mg6UjGQjA5WtxO2kq9fO-iW2f9UzDh58etcZ9-X5RSU,21570
37
- simo/core/permissions.py,sha256=D8JA3gdsbSfA1Lz6-AIP5ILsYYZ59_Rw4csLqVpuKuE,2928
37
+ simo/core/permissions.py,sha256=v0iJM4LOeYoEfMiw3OLPYio272G1aUEAg_z9Wd1q5m0,2993
38
38
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
39
- simo/core/serializers.py,sha256=K13SDW-FIcNiRYmJufSDS2EkRAW3cuoiHRByof2DYXQ,20629
39
+ simo/core/serializers.py,sha256=Dwm03pPpN0yDpr6W2dLw9MtUCjaPC-f93SYxYAkYfww,20765
40
40
  simo/core/signal_receivers.py,sha256=9-qFCCeSLcMFEMg6QUtKOVgUsoNoqhzGoI98nuNSTEo,6228
41
41
  simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
42
42
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
@@ -46,8 +46,8 @@ simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
46
46
  simo/core/views.py,sha256=VVqfEPzK0EdbVMMarkG8rd7cODG5QHpXnr3e8UdrTQE,2600
47
47
  simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
48
48
  simo/core/__pycache__/__init__.cpython-38.pyc,sha256=ZJFM_XN0RmJMULQulgA_wFiOnEtsMoedcOWnXjH-Y8o,208
49
- simo/core/__pycache__/admin.cpython-38.pyc,sha256=Lqs-wHz-vxGEo7ApOk6nkpNwfxselcFHqAUozotdZU4,13231
50
- simo/core/__pycache__/api.cpython-38.pyc,sha256=tECqcoyjHT9f2o0qt9aQlamf6a-i2CMNn-IWWuToocQ,21736
49
+ simo/core/__pycache__/admin.cpython-38.pyc,sha256=c5Q8YfIiLk25yVCxQvNsH-lwuOwfQa88X6xDYjOBogU,13428
50
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=c1QJHr84hrxuOF4hI1dc3N-yBy-UJuhmHpTbUocwrr4,21760
51
51
  simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=6M9Cl_ha4y_Vf8Rv4GMYL8dcBCmp0KzYi6jn3SQTgys,1712
52
52
  simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=VYx5ZeDyNBI4B_CBEIhV5B3GnLsMOx9s3rNZTSMODco,3703
53
53
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=vUCEAYqppjgRZYMs6pTuSxWWuZxreLygPuPBGw044dQ,3643
@@ -56,20 +56,20 @@ simo/core/__pycache__/auto_urls.cpython-38.pyc,sha256=Tyf8PYHq5YqSwTp25Joy-eura_
56
56
  simo/core/__pycache__/autocomplete_views.cpython-38.pyc,sha256=hJ6JILI1LqrAtpQMvxnLvljGdW1v1gpvBsD79vFkZ58,3972
57
57
  simo/core/__pycache__/base_types.cpython-38.pyc,sha256=hmq22vvGyCmhbYyuV6bFAOOSIupspgW5yq_VzqWd-vY,759
58
58
  simo/core/__pycache__/context.cpython-38.pyc,sha256=MSZPDhqMhCpUuBJl3HCIBHZA3BntYeP8RAnQcdqAH9k,1278
59
- simo/core/__pycache__/controllers.cpython-38.pyc,sha256=hqSv7xLR6qhK-d7Ymu17aVeHfVqPkLR9IiTs646vV5E,26574
59
+ simo/core/__pycache__/controllers.cpython-38.pyc,sha256=LA5Bnzev4kS3S8Ta0nfaVHQMIPfUDPYDL1GvfgHtIWg,26584
60
60
  simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=9ge2uV4QBKdA4f2pIZp4EIGB9vY2z4IUb-UMc4ZY0I4,2384
61
61
  simo/core/__pycache__/events.cpython-38.pyc,sha256=A1Axx-qftd1r7st7wkO3DkvTdt9-RkcJe5KJhpzJVk8,5109
62
62
  simo/core/__pycache__/filters.cpython-38.pyc,sha256=VIMADCBiYhziIyRmxAyUDJluZvuZmiC4bNYWTRsGSao,721
63
63
  simo/core/__pycache__/form_fields.cpython-38.pyc,sha256=u0voKXkA64xbH6LY_-jMBHQS4mOJZZeuB9WTvtv9JWE,3433
64
- simo/core/__pycache__/forms.cpython-38.pyc,sha256=gDYKULuBTMLxrKfzWXaLDbxuCJvhi2rwR5rIMC_IIVI,17672
64
+ simo/core/__pycache__/forms.cpython-38.pyc,sha256=_metULCNOh96IxCiiEVbA9rUM2C0gHUX1RC6WeBDV7k,17887
65
65
  simo/core/__pycache__/gateways.cpython-38.pyc,sha256=D1ooHL-iSpQrxnD8uAl4xWFJmm-QWZfbkLiLlFOMtdU,4553
66
66
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
67
67
  simo/core/__pycache__/managers.cpython-38.pyc,sha256=6RTIxyjOgpQGtAqcUyE2vFPS09w1V5Wmd_vOV7rHRRI,3370
68
- simo/core/__pycache__/middleware.cpython-38.pyc,sha256=94jRByEYOhsIuiMgPq_oHrRKrvD8rgQw8plS0n1Mrz8,1933
68
+ simo/core/__pycache__/middleware.cpython-38.pyc,sha256=UZTX3tUUHkigr_3GiSLbUX3RbJBg1_JBPiXy6saJ9GA,1911
69
69
  simo/core/__pycache__/models.cpython-38.pyc,sha256=rKg-_vQ-3L3_NKbCd0HIij7Nyev1t7SOz32-6PS4Rds,17907
70
- simo/core/__pycache__/permissions.cpython-38.pyc,sha256=pg11ulzmKh4IeWGPIDJ-KYG-S0dKyY5lHh-S3iljb0E,2930
70
+ simo/core/__pycache__/permissions.cpython-38.pyc,sha256=fH4iyqd9DdzRLEu2b621-FeM-napR0M7hzBUTHo9Q3g,2972
71
71
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
72
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=DhfGacxAy35un3edthOzgOWeVFbD93bvBWCJ4cAMPN4,19280
72
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=DSt_yCuB2aP-pBvu1g-mTzDOonFPkWsr77mqpw3To-8,19461
73
73
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=3Bt9S47DR_ZFS3O-crElFgLLXPIYyDgPIc2ibwEkaic,4904
74
74
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=NJUr7nRyHFvmAumxxWpsod5wzVVZM99rCEuJs1utHA4,8432
75
75
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
@@ -10164,7 +10164,7 @@ simo/core/utils/model_helpers.py,sha256=3IzJeOvBoYdUJVXCJkY20npOZXPjNPAiEFvuT0OP
10164
10164
  simo/core/utils/operations.py,sha256=W234NEetDnMWP7_tvxJq5CWo_rT6Xhe4Cw7n9-VOpyU,176
10165
10165
  simo/core/utils/relay.py,sha256=i1xy_nPTgY5Xn0l2W4lNI3xeVUpDQTUUfV3M8h2DeBg,457
10166
10166
  simo/core/utils/serialization.py,sha256=v0HLQ98r3zOlsf6dv6S4WxOEt6BzmFz2eTXa_iuKjSM,2057
10167
- simo/core/utils/type_constants.py,sha256=xR2HXZOw9GZhC47iO1Py5B8mpaQMPbzvqX5nHWakhsY,4116
10167
+ simo/core/utils/type_constants.py,sha256=PYBcG1EhlbSCgctL4nC1etHfN-oNi7H7K9W8vTSZbCw,4218
10168
10168
  simo/core/utils/validators.py,sha256=FRO6_K5HAO1OaC-LosApZjh-W3EA-IJZ53HnwEJgqiI,1297
10169
10169
  simo/core/utils/__pycache__/__init__.cpython-38.pyc,sha256=NJHPMizDKYRDEyMdQIh-ZRwT-BntwrvYfF450N2RYdI,164
10170
10170
  simo/core/utils/__pycache__/admin.cpython-38.pyc,sha256=ER2IoAHAfOO3q0PfKBtS7647fM-gkEptJ_DpC8LlUeY,2473
@@ -10174,7 +10174,7 @@ simo/core/utils/__pycache__/config_values.cpython-38.pyc,sha256=fqTVDhkjaWFv14Pr
10174
10174
  simo/core/utils/__pycache__/easing.cpython-38.pyc,sha256=LupxHv19OiBqL0VXmTbMCtAOpgvBpq_b0XwLU8El-Jk,2137
10175
10175
  simo/core/utils/__pycache__/form_fields.cpython-38.pyc,sha256=nBk6k9aj6BpWwdkpceIXdl5NU0fB6NPFhSBPaA-VtPs,1252
10176
10176
  simo/core/utils/__pycache__/form_widgets.cpython-38.pyc,sha256=MYAYEq0I4P0WErG9FamTJYWue7-cPartAWbFAiSSg5w,908
10177
- simo/core/utils/__pycache__/formsets.cpython-38.pyc,sha256=S0ekEmo_ar_g9Jx8U1xYpYj8a133lM3jNdTcVFjf1_U,4946
10177
+ simo/core/utils/__pycache__/formsets.cpython-38.pyc,sha256=b0BuoiXFQwNgok0OWuMma8pwTC6s9c-s9yuet_YLlZk,4946
10178
10178
  simo/core/utils/__pycache__/helpers.cpython-38.pyc,sha256=jTGaN7kSJRwouP0EuYSaiJeMylo_RzJwSm-DKRwceHA,4291
10179
10179
  simo/core/utils/__pycache__/json.cpython-38.pyc,sha256=TKc88VpPKgimeaozhgx34WWJ1mwTWFWN6B9-VAH8qT0,532
10180
10180
  simo/core/utils/__pycache__/logs.cpython-38.pyc,sha256=BVVeQoOhfRHm3SHnCoE1d5G84kTpJZFmr_btc3jDYTU,2156
@@ -10183,7 +10183,7 @@ simo/core/utils/__pycache__/model_helpers.cpython-38.pyc,sha256=QzO0rh1NuQePHDCS
10183
10183
  simo/core/utils/__pycache__/operations.cpython-38.pyc,sha256=1BUP7gbpBgX7mwWLpkmRH0eXgisbjn-6TIa8VDPj6v8,381
10184
10184
  simo/core/utils/__pycache__/relay.cpython-38.pyc,sha256=gs4iN9TWBo_JIW07emIggIcv6gHKuOY_4jfmAFhuL3k,697
10185
10185
  simo/core/utils/__pycache__/serialization.cpython-38.pyc,sha256=9nTbzozDi8Avl6krHvAo67CLdiTrYW0ij3hQtucHty0,1338
10186
- simo/core/utils/__pycache__/type_constants.cpython-38.pyc,sha256=bEMvzkBxzc6MKq6gn9A6wszXzMjLTbX-V-IK4NMht8E,3363
10186
+ simo/core/utils/__pycache__/type_constants.cpython-38.pyc,sha256=DEgtIL7cPWeIsjGaPf-qIHXzfOTJUJIBxDCbKDTs64s,3417
10187
10187
  simo/core/utils/__pycache__/validators.cpython-38.pyc,sha256=gjeBOjL_keMoRDjdn8v-3F3wcjPIT3Xx5KpTalo0e-Y,1247
10188
10188
  simo/fleet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10189
10189
  simo/fleet/admin.py,sha256=3iQLbpJnPku4MSp4sOL3Wj01lZQBBPyGV-bzTrRxKA4,6295
@@ -10300,8 +10300,8 @@ simo/fleet/templates/fleet/controllers_info/ENS160AirQualitySensor.md,sha256=3LS
10300
10300
  simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10301
10301
  simo/generic/app_widgets.py,sha256=E_pnpA1hxMIhenRCrHoQ5cik06jm2BAHCkl_eo-OudU,1264
10302
10302
  simo/generic/base_types.py,sha256=djymox_boXTHX1BTTCLXrCH7ED-uAsV_idhaDOc3OLI,409
10303
- simo/generic/controllers.py,sha256=lnojSqDQ-1FArF2wH_c11y0qd906Wog-qrSG1DoqeXc,58284
10304
- simo/generic/forms.py,sha256=IAfDtmEk1-CP0JBoetOD_ahLm64nK41GOUXjmbUzNtY,29550
10303
+ simo/generic/controllers.py,sha256=dA8LaQSAyukXI6Sy8MvcQG1nugR9HlNKlstcXR_dW2s,58271
10304
+ simo/generic/forms.py,sha256=VzJJjZEuvpDEa2uObw9SkPmzQ4J_LkJ6UCNCoQImm0g,29427
10305
10305
  simo/generic/gateways.py,sha256=cc_q_g2HsI2_rWmr8yZ3spnMPwsgoYS5ApWRimc11wU,18831
10306
10306
  simo/generic/models.py,sha256=flpK2jsBFghrvRHzl6IKT-t3WZ-hNOj4ZP2vmBzx0K8,7657
10307
10307
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
@@ -10309,8 +10309,8 @@ simo/generic/socket_consumers.py,sha256=NfTQGYtVAc864IoogZRxf_0xpDPM0eMCWn0SlKA5
10309
10309
  simo/generic/__pycache__/__init__.cpython-38.pyc,sha256=mLu54WS9KIl-pHwVCBKpsDFIlOqml--JsOVzAUHg6cU,161
10310
10310
  simo/generic/__pycache__/app_widgets.cpython-38.pyc,sha256=0IoKRG9n1tkNRRkrqAeOQwWBPd_33u98JBcVtMVVCio,2374
10311
10311
  simo/generic/__pycache__/base_types.cpython-38.pyc,sha256=ptw6axyAqemZA35oa6vzr7EihzvbhW9w7Y-G6kfDedU,555
10312
- simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=9ZnI6Z084og6Q-9fmhT-PZEM5w_yOC1rwMAHHA6af_Q,36460
10313
- simo/generic/__pycache__/forms.cpython-38.pyc,sha256=v85YEQR9l0QyUgYW_uTKr5qFCjp8TYOAAnfYQvYActI,21227
10312
+ simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=DSGkVxjPz4g8BAFNFjM4YULJJOQsuaIapNw1JklEwDM,36478
10313
+ simo/generic/__pycache__/forms.cpython-38.pyc,sha256=g-KKlxmRVWVN_mVOoXsuIGTNaVgs76BisphknIyD8vI,21071
10314
10314
  simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=8NbsLVDww3Ov5DKF--LKgyrgnrn8yVcKrY21cdvV5aA,13979
10315
10315
  simo/generic/__pycache__/models.cpython-38.pyc,sha256=n3FeTMJYh4B6nCPiPKeXiWsUOOWkLHca7qTvfTK6Iik,5844
10316
10316
  simo/generic/__pycache__/routing.cpython-38.pyc,sha256=xtxTUTBTdivzFyA5Wh7k-hUj1WDO_FiRq6HYXdbr9Ks,382
@@ -10505,9 +10505,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10505
10505
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10506
10506
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10507
10507
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10508
- simo-2.2.2.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10509
- simo-2.2.2.dist-info/METADATA,sha256=Ru0FCahOkylESH_ERFdMhvY_J5YwYXMmIBsjAZvsdKY,1847
10510
- simo-2.2.2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
10511
- simo-2.2.2.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10512
- simo-2.2.2.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10513
- simo-2.2.2.dist-info/RECORD,,
10508
+ simo-2.2.4.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10509
+ simo-2.2.4.dist-info/METADATA,sha256=ieqenkGo1tCWUDV_593yvZYaYWTkVFwczsZI-7EgqMg,1847
10510
+ simo-2.2.4.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
10511
+ simo-2.2.4.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10512
+ simo-2.2.4.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10513
+ simo-2.2.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5