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

Files changed (183) hide show
  1. simo/__pycache__/settings.cpython-38.pyc +0 -0
  2. simo/__pycache__/urls.cpython-38.pyc +0 -0
  3. simo/core/__pycache__/admin.cpython-38.pyc +0 -0
  4. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  5. simo/core/__pycache__/api_auth.cpython-38.pyc +0 -0
  6. simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
  7. simo/core/__pycache__/auto_urls.cpython-38.pyc +0 -0
  8. simo/core/__pycache__/autocomplete_views.cpython-38.pyc +0 -0
  9. simo/core/__pycache__/base_types.cpython-38.pyc +0 -0
  10. simo/core/__pycache__/context.cpython-38.pyc +0 -0
  11. simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
  12. simo/core/__pycache__/events.cpython-38.pyc +0 -0
  13. simo/core/__pycache__/forms.cpython-38.pyc +0 -0
  14. simo/core/__pycache__/gateways.cpython-38.pyc +0 -0
  15. simo/core/__pycache__/managers.cpython-38.pyc +0 -0
  16. simo/core/__pycache__/middleware.cpython-38.pyc +0 -0
  17. simo/core/__pycache__/models.cpython-38.pyc +0 -0
  18. simo/core/__pycache__/permissions.cpython-38.pyc +0 -0
  19. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  20. simo/core/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  21. simo/core/__pycache__/tasks.cpython-38.pyc +0 -0
  22. simo/core/__pycache__/views.cpython-38.pyc +0 -0
  23. simo/core/admin.py +10 -10
  24. simo/core/api.py +7 -6
  25. simo/core/controllers.py +1 -0
  26. simo/core/db_backend/__pycache__/__init__.cpython-38.pyc +0 -0
  27. simo/core/db_backend/__pycache__/base.cpython-38.pyc +0 -0
  28. simo/core/drf_braces/__pycache__/__init__.cpython-38.pyc +0 -0
  29. simo/core/drf_braces/__pycache__/utils.cpython-38.pyc +0 -0
  30. simo/core/drf_braces/fields/__pycache__/__init__.cpython-38.pyc +0 -0
  31. simo/core/drf_braces/fields/__pycache__/_fields.cpython-38.pyc +0 -0
  32. simo/core/drf_braces/fields/__pycache__/custom.cpython-38.pyc +0 -0
  33. simo/core/drf_braces/fields/__pycache__/mixins.cpython-38.pyc +0 -0
  34. simo/core/drf_braces/fields/__pycache__/modified.cpython-38.pyc +0 -0
  35. simo/core/drf_braces/serializers/__pycache__/__init__.cpython-38.pyc +0 -0
  36. simo/core/drf_braces/serializers/__pycache__/form_serializer.cpython-38.pyc +0 -0
  37. simo/core/forms.py +8 -6
  38. simo/core/migrations/0030_alter_instance_timezone.py +18 -0
  39. simo/core/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
  40. simo/core/migrations/__pycache__/0002_load_icons.cpython-38.pyc +0 -0
  41. simo/core/migrations/__pycache__/0003_create_default_zones_and_categories.cpython-38.pyc +0 -0
  42. simo/core/migrations/__pycache__/0004_create_generic.cpython-38.pyc +0 -0
  43. simo/core/migrations/__pycache__/0005_component_subcomponents.cpython-38.pyc +0 -0
  44. simo/core/migrations/__pycache__/0006_alter_component_subcomponents.cpython-38.pyc +0 -0
  45. simo/core/migrations/__pycache__/0007_component_change_init_to.cpython-38.pyc +0 -0
  46. simo/core/migrations/__pycache__/0008_alter_component_change_init_to.cpython-38.pyc +0 -0
  47. simo/core/migrations/__pycache__/0009_auto_20220707_1404.cpython-38.pyc +0 -0
  48. simo/core/migrations/__pycache__/0010_historyaggregate.cpython-38.pyc +0 -0
  49. simo/core/migrations/__pycache__/0011_component_last_change.cpython-38.pyc +0 -0
  50. simo/core/migrations/__pycache__/0012_instance.cpython-38.pyc +0 -0
  51. simo/core/migrations/__pycache__/0013_auto_20231003_0754.cpython-38.pyc +0 -0
  52. simo/core/migrations/__pycache__/0014_zone_instance.cpython-38.pyc +0 -0
  53. simo/core/migrations/__pycache__/0015_auto_20231004_1113.cpython-38.pyc +0 -0
  54. simo/core/migrations/__pycache__/0016_auto_20231004_1113.cpython-38.pyc +0 -0
  55. simo/core/migrations/__pycache__/0017_auto_20231004_1313.cpython-38.pyc +0 -0
  56. simo/core/migrations/__pycache__/0018_auto_20231005_0622.cpython-38.pyc +0 -0
  57. simo/core/migrations/__pycache__/0019_alter_gateway_type.cpython-38.pyc +0 -0
  58. simo/core/migrations/__pycache__/0020_component_meta.cpython-38.pyc +0 -0
  59. simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-38.pyc +0 -0
  60. simo/core/migrations/__pycache__/0026_category_instance.cpython-38.pyc +0 -0
  61. simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-38.pyc +0 -0
  62. simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-38.pyc +0 -0
  63. simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-38.pyc +0 -0
  64. simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-38.pyc +0 -0
  65. simo/core/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
  66. simo/core/models.py +31 -46
  67. simo/core/serializers.py +3 -4
  68. simo/core/templatetags/__pycache__/__init__.cpython-38.pyc +0 -0
  69. simo/core/templatetags/__pycache__/components_list.cpython-38.pyc +0 -0
  70. simo/core/utils/__pycache__/__init__.cpython-38.pyc +0 -0
  71. simo/core/utils/__pycache__/admin.cpython-38.pyc +0 -0
  72. simo/core/utils/__pycache__/config_values.cpython-38.pyc +0 -0
  73. simo/core/utils/__pycache__/easing.cpython-38.pyc +0 -0
  74. simo/core/utils/__pycache__/form_fields.cpython-38.pyc +0 -0
  75. simo/core/utils/__pycache__/form_widgets.cpython-38.pyc +0 -0
  76. simo/core/utils/__pycache__/formsets.cpython-38.pyc +0 -0
  77. simo/core/utils/__pycache__/helpers.cpython-38.pyc +0 -0
  78. simo/core/utils/__pycache__/logs.cpython-38.pyc +0 -0
  79. simo/core/utils/__pycache__/mixins.cpython-38.pyc +0 -0
  80. simo/core/utils/__pycache__/model_helpers.cpython-38.pyc +0 -0
  81. simo/core/utils/__pycache__/relay.cpython-38.pyc +0 -0
  82. simo/core/utils/__pycache__/serialization.cpython-38.pyc +0 -0
  83. simo/core/utils/__pycache__/type_constants.cpython-38.pyc +0 -0
  84. simo/core/utils/__pycache__/validators.cpython-38.pyc +0 -0
  85. simo/core/utils/serialization.py +4 -2
  86. simo/core/utils/type_constants.py +32 -11
  87. simo/fleet/__pycache__/admin.cpython-38.pyc +0 -0
  88. simo/fleet/__pycache__/api.cpython-38.pyc +0 -0
  89. simo/fleet/__pycache__/auto_urls.cpython-38.pyc +0 -0
  90. simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
  91. simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
  92. simo/fleet/__pycache__/gateways.cpython-38.pyc +0 -0
  93. simo/fleet/__pycache__/managers.cpython-38.pyc +0 -0
  94. simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
  95. simo/fleet/__pycache__/serializers.cpython-38.pyc +0 -0
  96. simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  97. simo/fleet/__pycache__/utils.cpython-38.pyc +0 -0
  98. simo/fleet/__pycache__/views.cpython-38.pyc +0 -0
  99. simo/fleet/admin.py +6 -6
  100. simo/fleet/auto_urls.py +4 -4
  101. simo/fleet/controllers.py +75 -2
  102. simo/fleet/forms.py +68 -33
  103. simo/fleet/gateways.py +7 -3
  104. simo/fleet/managers.py +4 -2
  105. simo/fleet/migrations/0032_auto_20240415_0736.py +33 -0
  106. simo/fleet/migrations/0033_auto_20240415_0736.py +28 -0
  107. simo/fleet/migrations/__pycache__/0025_auto_20240130_1334.cpython-38.pyc +0 -0
  108. simo/fleet/migrations/__pycache__/0026_rename_i2cinterface_scl_pin_and_more.cpython-38.pyc +0 -0
  109. simo/fleet/migrations/__pycache__/0027_auto_20240306_0802.cpython-38.pyc +0 -0
  110. simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-38.pyc +0 -0
  111. simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-38.pyc +0 -0
  112. simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-38.pyc +0 -0
  113. simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-38.pyc +0 -0
  114. simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-38.pyc +0 -0
  115. simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-38.pyc +0 -0
  116. simo/fleet/models.py +82 -14
  117. simo/fleet/socket_consumers.py +19 -12
  118. simo/fleet/utils.py +6 -1
  119. simo/fleet/views.py +10 -9
  120. simo/generic/__pycache__/__init__.cpython-38.pyc +0 -0
  121. simo/generic/__pycache__/app_widgets.cpython-38.pyc +0 -0
  122. simo/generic/__pycache__/base_types.cpython-38.pyc +0 -0
  123. simo/generic/__pycache__/controllers.cpython-38.pyc +0 -0
  124. simo/generic/__pycache__/forms.cpython-38.pyc +0 -0
  125. simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
  126. simo/generic/__pycache__/models.cpython-38.pyc +0 -0
  127. simo/generic/__pycache__/routing.cpython-38.pyc +0 -0
  128. simo/generic/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  129. simo/generic/controllers.py +0 -7
  130. simo/generic/forms.py +0 -3
  131. simo/generic/gateways.py +0 -8
  132. simo/multimedia/__pycache__/__init__.cpython-38.pyc +0 -0
  133. simo/multimedia/__pycache__/admin.cpython-38.pyc +0 -0
  134. simo/multimedia/__pycache__/api.cpython-38.pyc +0 -0
  135. simo/multimedia/__pycache__/app_widgets.cpython-38.pyc +0 -0
  136. simo/multimedia/__pycache__/base_types.cpython-38.pyc +0 -0
  137. simo/multimedia/__pycache__/controllers.cpython-38.pyc +0 -0
  138. simo/multimedia/__pycache__/forms.cpython-38.pyc +0 -0
  139. simo/multimedia/__pycache__/models.cpython-38.pyc +0 -0
  140. simo/multimedia/__pycache__/serializers.cpython-38.pyc +0 -0
  141. simo/multimedia/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
  142. simo/multimedia/migrations/__pycache__/0002_sound_length.cpython-38.pyc +0 -0
  143. simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-38.pyc +0 -0
  144. simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-38.pyc +0 -0
  145. simo/multimedia/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
  146. simo/notifications/__pycache__/__init__.cpython-38.pyc +0 -0
  147. simo/notifications/__pycache__/admin.cpython-38.pyc +0 -0
  148. simo/notifications/__pycache__/api.cpython-38.pyc +0 -0
  149. simo/notifications/__pycache__/models.cpython-38.pyc +0 -0
  150. simo/notifications/__pycache__/serializers.cpython-38.pyc +0 -0
  151. simo/notifications/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
  152. simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.pyc +0 -0
  153. simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
  154. simo/users/__pycache__/admin.cpython-38.pyc +0 -0
  155. simo/users/__pycache__/api.cpython-38.pyc +0 -0
  156. simo/users/__pycache__/auto_urls.cpython-38.pyc +0 -0
  157. simo/users/__pycache__/middleware.cpython-38.pyc +0 -0
  158. simo/users/__pycache__/models.cpython-38.pyc +0 -0
  159. simo/users/__pycache__/serializers.cpython-38.pyc +0 -0
  160. simo/users/__pycache__/sso_urls.cpython-38.pyc +0 -0
  161. simo/users/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
  162. simo/users/migrations/__pycache__/0002_componentpermission.cpython-38.pyc +0 -0
  163. simo/users/migrations/__pycache__/0003_create_roles_and_system_user.cpython-38.pyc +0 -0
  164. simo/users/migrations/__pycache__/0004_user_secret_key.cpython-38.pyc +0 -0
  165. simo/users/migrations/__pycache__/0005_permissionsrole_instance.cpython-38.pyc +0 -0
  166. simo/users/migrations/__pycache__/0006_auto_20231003_0850.cpython-38.pyc +0 -0
  167. simo/users/migrations/__pycache__/0007_auto_20231003_1228.cpython-38.pyc +0 -0
  168. simo/users/migrations/__pycache__/0008_auto_20231003_1229.cpython-38.pyc +0 -0
  169. simo/users/migrations/__pycache__/0009_remove_user_role.cpython-38.pyc +0 -0
  170. simo/users/migrations/__pycache__/0010_auto_20231004_1313.cpython-38.pyc +0 -0
  171. simo/users/migrations/__pycache__/0011_auto_20231004_1313.cpython-38.pyc +0 -0
  172. simo/users/migrations/__pycache__/0012_alter_userinstancerole_unique_together.cpython-38.pyc +0 -0
  173. simo/users/migrations/__pycache__/0013_remove_user_roles.cpython-38.pyc +0 -0
  174. simo/users/migrations/__pycache__/0014_user_roles.cpython-38.pyc +0 -0
  175. simo/users/migrations/__pycache__/0015_remove_user_at_home.cpython-38.pyc +0 -0
  176. simo/users/migrations/__pycache__/0016_auto_20231005_1050.cpython-38.pyc +0 -0
  177. simo/users/migrations/__pycache__/0025_rename_name_fingerprint_type_and_more.cpython-38.pyc +0 -0
  178. simo/users/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
  179. {simo-2.0.5.dist-info → simo-2.0.7.dist-info}/METADATA +1 -1
  180. {simo-2.0.5.dist-info → simo-2.0.7.dist-info}/RECORD +183 -89
  181. {simo-2.0.5.dist-info → simo-2.0.7.dist-info}/LICENSE.md +0 -0
  182. {simo-2.0.5.dist-info → simo-2.0.7.dist-info}/WHEEL +0 -0
  183. {simo-2.0.5.dist-info → simo-2.0.7.dist-info}/top_level.txt +0 -0
simo/fleet/models.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import requests
2
2
  import time
3
+ from django.core.exceptions import ValidationError
3
4
  from django.db import transaction
4
5
  from django.db import models
5
6
  from django.db.models.signals import post_save, pre_delete, post_delete
@@ -11,8 +12,8 @@ from simo.core.models import Instance, Gateway, Component
11
12
  from simo.core.utils.helpers import get_random_string
12
13
  from simo.core.events import GatewayObjectCommand
13
14
  from .gateways import FleetGatewayHandler
14
- from .managers import ColonelsManager, ColonelPinsManager, I2CInterfacesManager
15
- from .utils import GPIO_PINS
15
+ from .managers import ColonelsManager, ColonelPinsManager, InterfacesManager
16
+ from .utils import GPIO_PINS, INTERFACES_PINS_MAP
16
17
 
17
18
 
18
19
 
@@ -181,10 +182,12 @@ class Colonel(DirtyFieldsMixin, models.Model):
181
182
  pin.save()
182
183
 
183
184
  for interface in self.i2c_interfaces.all():
184
- interface.sda_pin.occupied_by = interface
185
- interface.sda_pin.save()
186
- interface.scl_pin.occupied_by = interface
187
- interface.scl_pin.save()
185
+ if interface.sda_pin:
186
+ interface.sda_pin.occupied_by = interface
187
+ interface.sda_pin.save()
188
+ if interface.scl_pin:
189
+ interface.scl_pin.occupied_by = interface
190
+ interface.scl_pin.save()
188
191
 
189
192
 
190
193
  def move_to(self, other_colonel):
@@ -256,12 +259,6 @@ def after_colonel_save(sender, instance, created, *args, **kwargs):
256
259
  capacitive=data.get('capacitive'), adc=data.get('adc'),
257
260
  native=data.get('native'), note=data.get('note')
258
261
  )
259
- if instance.type in ('ample-wall', 'game-changer'):
260
- I2CInterface.objects.create(
261
- colonel=instance, name='Main', no=0,
262
- scl_pin=ColonelPin.objects.get(colonel=instance, no=4),
263
- sda_pin=ColonelPin.objects.get(colonel=instance, no=15),
264
- )
265
262
 
266
263
 
267
264
  @receiver(pre_delete, sender=Component)
@@ -310,7 +307,7 @@ class I2CInterface(models.Model):
310
307
  default=100000, help_text="100000 - is a good middle point!"
311
308
  )
312
309
 
313
- objects = I2CInterfacesManager()
310
+ objects = InterfacesManager()
314
311
 
315
312
  class Meta:
316
313
  unique_together = 'colonel', 'no'
@@ -319,7 +316,7 @@ class I2CInterface(models.Model):
319
316
  return self.name
320
317
 
321
318
 
322
- @receiver(post_save, sender=I2CInterface)
319
+ @receiver(post_delete, sender=I2CInterface)
323
320
  def post_i2c_interface_delete(sender, instance, *args, **kwargs):
324
321
  with transaction.atomic():
325
322
  ct = ContentType.objects.get_for_model(instance)
@@ -334,3 +331,74 @@ def post_i2c_interface_delete(sender, instance, *args, **kwargs):
334
331
  instance.scl_pin.save()
335
332
  instance.sda_pin.occupied_by = instance
336
333
  instance.sda_pin.save()
334
+
335
+
336
+ class Interface(models.Model):
337
+ colonel = models.ForeignKey(
338
+ Colonel, on_delete=models.CASCADE, related_name='interfaces'
339
+ )
340
+ no = models.PositiveIntegerField(choices=((1, "1"), (2, "2")))
341
+ type = models.CharField(
342
+ max_length=20, choices=(('i2c', "I2C"), ('dali', "DALI"))
343
+ )
344
+ pin_a = models.ForeignKey(
345
+ ColonelPin, on_delete=models.CASCADE, limit_choices_to={
346
+ 'native': True, 'output': True,
347
+ }, verbose_name="Pin A (scl)", null=True, related_name='interface_a',
348
+ editable=False
349
+ )
350
+ pin_b = models.ForeignKey(
351
+ ColonelPin, on_delete=models.CASCADE, limit_choices_to={
352
+ 'native': True, 'output': True,
353
+ }, verbose_name="Pin B (sda)", null=True, related_name='interface_b',
354
+ editable=False
355
+ )
356
+
357
+ objects = InterfacesManager()
358
+
359
+ class Meta:
360
+ unique_together = 'colonel', 'no'
361
+
362
+ def __str__(self):
363
+ return f"{self.no} - {self.get_type_display()}"
364
+
365
+ def save(self, *args, **kwargs):
366
+ if not self.pk:
367
+ for pin_no in INTERFACES_PINS_MAP[self.no]:
368
+ cpin = ColonelPin.objects.get(colonel=self.colonel, no=pin_no)
369
+ if cpin.occupied_by:
370
+ raise ValidationError(
371
+ f"Interface can not be created, because "
372
+ f"GPIO{cpin} is already occupied by {cpin.occupied_by}."
373
+ )
374
+ return super().save(*args, **kwargs)
375
+
376
+
377
+ @receiver(post_save, sender=Interface)
378
+ def post_interface_save(sender, instance, created, *args, **kwargs):
379
+ if created:
380
+ instance.pin_a = ColonelPin.objects.get(
381
+ colonel=instance.colonel, no=INTERFACES_PINS_MAP[instance.no][0]
382
+ )
383
+ instance.pin_a.occupied_by = instance
384
+ instance.pin_a.save()
385
+ instance.pin_b = ColonelPin.objects.get(
386
+ colonel=instance.colonel, no=INTERFACES_PINS_MAP[instance.no][1]
387
+ )
388
+ instance.pin_b.occupied_by = instance
389
+ instance.pin_b.save()
390
+
391
+
392
+ @receiver(post_delete, sender=Interface)
393
+ def post_interface_delete(sender, instance, *args, **kwargs):
394
+ with transaction.atomic():
395
+ ct = ContentType.objects.get_for_model(instance)
396
+ for pin in ColonelPin.objects.filter(
397
+ occupied_by_content_type=ct,
398
+ occupied_by_id=instance.id
399
+ ):
400
+ pin.occupied_by_content_type = None
401
+ pin.occupied_by_content_id = None
402
+ pin.save()
403
+
404
+
@@ -218,15 +218,14 @@ class FleetConsumer(AsyncWebsocketConsumer):
218
218
  }
219
219
  }
220
220
  config_data['settings'].update(instance_options)
221
- i2c_interfaces = await sync_to_async(list, thread_sensitive=True)(
222
- self.colonel.i2c_interfaces.all().select_related(
223
- 'scl_pin', 'sda_pin'
221
+ interfaces = await sync_to_async(list, thread_sensitive=True)(
222
+ self.colonel.interfaces.all().select_related(
223
+ 'pin_a', 'pin_b'
224
224
  )
225
225
  )
226
- for i2c_interface in i2c_interfaces:
227
- config_data['interfaces']['i2c-%d' % i2c_interface.no] = {
228
- 'scl': i2c_interface.scl_pin.no, 'sda': i2c_interface.sda_pin.no,
229
- 'freq': i2c_interface.freq
226
+ for interface in interfaces:
227
+ config_data['interfaces'][f'{interface.type}-{interface.no}'] = {
228
+ 'pin_a': interface.pin_a.no, 'pin_b': interface.pin_b.no,
230
229
  }
231
230
  components = await sync_to_async(
232
231
  list, thread_sensitive=True
@@ -319,6 +318,11 @@ class FleetConsumer(AsyncWebsocketConsumer):
319
318
  asyncio.run(self.send_data({
320
319
  'command': 'discover-ttlock'
321
320
  }))
321
+ elif payload.get('command') == 'discover-dali':
322
+ print("SEND discover-dali command!")
323
+ asyncio.run(self.send_data({
324
+ 'command': 'discover-dali', 'i': payload['interface']
325
+ }))
322
326
  elif payload.get('command') == 'finalize':
323
327
  asyncio.run(self.send_data({
324
328
  'command': 'finalize',
@@ -420,18 +424,21 @@ class FleetConsumer(AsyncWebsocketConsumer):
420
424
  except Exception as e:
421
425
  print(traceback.format_exc(), file=sys.stderr)
422
426
 
423
- elif 'discover-ttlock' in data:
427
+ elif 'discovery-result' in data:
424
428
  def process_discovery_result():
425
- self.gateway.refresh_from_db()
426
- if self.gateway.discovery.get('finished'):
427
- return Component.objects.filter(
429
+ # check if component is already created
430
+ if data['discovery-result'] == 'success':
431
+ comp = Component.objects.filter(
428
432
  meta__finalization_data__temp_id=data['result']['id']
429
433
  ).first()
434
+ if comp:
435
+ return comp
436
+
437
+ self.gateway.refresh_from_db()
430
438
  try:
431
439
  self.gateway.process_discovery(data)
432
440
  except Exception as e:
433
441
  print(traceback.format_exc(), file=sys.stderr)
434
- self.gateway.finish_discovery()
435
442
 
436
443
  finished_comp = await sync_to_async(
437
444
  process_discovery_result, thread_sensitive=True
simo/fleet/utils.py CHANGED
@@ -58,7 +58,7 @@ for no, data in BASE_ESP32_GPIO_PINS.items():
58
58
 
59
59
  # ample-wall
60
60
  for no, data in BASE_ESP32_GPIO_PINS.items():
61
- if no in (4, 12, 13, 14, 15, 23, 32, 33, 34, 36, 39):
61
+ if no in (12, 13, 14, 23, 32, 33, 34, 36, 39):
62
62
  GPIO_PINS['ample-wall'][no] = GPIO_PIN_DEFAULTS.copy()
63
63
  GPIO_PINS['ample-wall'][no].update(data)
64
64
 
@@ -114,3 +114,8 @@ for no, data in BASE_ESP32_GPIO_PINS.items():
114
114
  GPIO_PINS['4-relays'][no]['note'] = 'Relay4'
115
115
  else:
116
116
  GPIO_PINS['4-relays'][no].update(data)
117
+
118
+
119
+ INTERFACES_PINS_MAP = {
120
+ 1: [13, 23], 2: [32, 33]
121
+ }
simo/fleet/views.py CHANGED
@@ -1,9 +1,8 @@
1
- from django.contrib.contenttypes.models import ContentType
2
1
  from django.http import HttpResponse, Http404
3
2
  from django.db.models import Q
4
3
  from dal import autocomplete
5
4
  from simo.core.utils.helpers import search_queryset
6
- from .models import Colonel, ColonelPin, I2CInterface
5
+ from .models import Colonel, ColonelPin, Interface
7
6
 
8
7
 
9
8
  def colonels_ping(request):
@@ -43,20 +42,22 @@ class PinsSelectAutocomplete(autocomplete.Select2QuerySetView):
43
42
  return qs
44
43
 
45
44
 
46
- class I2CInterfaceSelectAutocomplete(autocomplete.Select2ListView):
45
+ class InterfaceSelectAutocomplete(autocomplete.Select2ListView):
47
46
 
48
47
  def get_list(self):
49
48
  if not self.request.user.is_staff:
50
- return []
49
+ return Interface.objects.none()
51
50
 
52
51
  try:
53
52
  colonel = Colonel.objects.get(
54
53
  pk=self.forwarded.get("colonel")
55
54
  )
56
55
  except:
57
- return []
56
+ return Interface.objects.none()
58
57
 
59
- return [
60
- (i.no, i.get_no_display()) for i in
61
- I2CInterface.objects.filter(colonel=colonel)
62
- ]
58
+ qs = Interface.objects.filter(colonel=colonel)
59
+
60
+ if self.forwarded.get('filters'):
61
+ qs = qs.filter(**self.forwarded.get('filters'))
62
+
63
+ return qs
@@ -208,13 +208,9 @@ class Thermostat(ControllerBase):
208
208
  heater = Component.objects.filter(
209
209
  pk=self.component.config.get('heater')
210
210
  ).first()
211
- if heater:
212
- heater.prepare_controller()
213
211
  cooler = Component.objects.filter(
214
212
  pk=self.component.config.get('cooler')
215
213
  ).first()
216
- if cooler:
217
- cooler.prepare_controller()
218
214
 
219
215
  if not temperature_sensor or not temperature_sensor.alive:
220
216
  print(f"No temperature sensor on {self.component}!")
@@ -720,7 +716,6 @@ class Watering(ControllerBase):
720
716
  switch = Component.objects.get(pk=contour_data['switch'])
721
717
  except Component.DoesNotExist:
722
718
  continue
723
- switch.prepare_controller()
724
719
  if run:
725
720
  if switch.timer_engaged():
726
721
  switch.stop_timer()
@@ -845,7 +840,6 @@ class Watering(ControllerBase):
845
840
  switch = Component.objects.get(pk=contour_data['switch'])
846
841
  except Component.DoesNotExist:
847
842
  continue
848
- switch.prepare_controller()
849
843
  if switch.timer_engaged():
850
844
  switch.stop_timer()
851
845
  switch.turn_off()
@@ -1077,7 +1071,6 @@ class AlarmClock(ControllerBase):
1077
1071
  print(f"Reverse event {event['uid']}!")
1078
1072
  comp = Component.objects.filter(id=event['component']).first()
1079
1073
  if comp:
1080
- comp.prepare_controller()
1081
1074
  if forward:
1082
1075
  action_name = 'play_action'
1083
1076
  else:
simo/generic/forms.py CHANGED
@@ -202,7 +202,6 @@ class AlarmGroupConfigForm(BaseComponentForm):
202
202
  "Can not cover self. Please remove - [%s]" % str(check_cmp)
203
203
  )
204
204
  if comp.base_type == 'alarm-group':
205
- comp.prepare_controller()
206
205
  self.recurse_check_alarm_groups(
207
206
  comp.get_children(), check_cmp
208
207
  )
@@ -227,7 +226,6 @@ class AlarmGroupConfigForm(BaseComponentForm):
227
226
  c.save(update_fields=('config',))
228
227
  if obj.id:
229
228
  comp = Component.objects.get(id=obj.id)
230
- comp.prepare_controller()
231
229
  comp.refresh_status()
232
230
  return obj
233
231
 
@@ -512,7 +510,6 @@ class AlarmClockEventForm(forms.Form):
512
510
  if not self.cleaned_data.get('play_action'):
513
511
  return self.cleaned_data
514
512
  component = self.cleaned_data.get('component')
515
- component.prepare_controller()
516
513
  if not hasattr(component, self.cleaned_data['play_action']):
517
514
  self.add_error(
518
515
  'play_action',
simo/generic/gateways.py CHANGED
@@ -175,7 +175,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
175
175
  ):
176
176
  tz = pytz.timezone(thermostat.zone.instance.timezone)
177
177
  timezone.activate(tz)
178
- thermostat.prepare_controller()
179
178
  thermostat.evaluate()
180
179
 
181
180
  def watch_alarm_clocks(self):
@@ -185,7 +184,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
185
184
  ):
186
185
  tz = pytz.timezone(alarm_clock.zone.instance.timezone)
187
186
  timezone.activate(tz)
188
- alarm_clock.prepare_controller()
189
187
  alarm_clock.tick()
190
188
 
191
189
  def watch_scripts(self):
@@ -194,7 +192,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
194
192
  controller_uid=Script.uid,
195
193
  config__autostart=True
196
194
  ).exclude(value='running'):
197
- script.prepare_controller()
198
195
  self.start_script(script)
199
196
 
200
197
  def watch_watering(self):
@@ -202,7 +199,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
202
199
  for watering in Component.objects.filter(controller_uid=Watering.uid):
203
200
  tz = pytz.timezone(watering.zone.instance.timezone)
204
201
  timezone.activate(tz)
205
- watering.prepare_controller()
206
202
  if watering.value['status'] == 'running_program':
207
203
  watering.set_program_progress(
208
204
  watering.value['program_progress'] + 1
@@ -333,11 +329,9 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
333
329
  open_switch = Component.objects.get(
334
330
  pk=blinds.config['open_switch']
335
331
  )
336
- open_switch.prepare_controller()
337
332
  close_switch = Component.objects.get(
338
333
  pk=blinds.config['close_switch']
339
334
  )
340
- close_switch.prepare_controller()
341
335
  except:
342
336
  return
343
337
 
@@ -406,7 +400,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
406
400
  alarm_group.save()
407
401
 
408
402
  for pk, other_group in other_alarm_groups.items():
409
- other_group.prepare_controller()
410
403
  other_group.refresh_status()
411
404
 
412
405
 
@@ -416,7 +409,6 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
416
409
  ).first()
417
410
  if not switch:
418
411
  return
419
- switch.prepare_controller()
420
412
 
421
413
  if gate.config.get('action_method') == 'click':
422
414
  switch.click()
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.0.5
3
+ Version: 2.0.7
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