simo 1.7.20__py3-none-any.whl → 2.0.1__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.
- simo/__pycache__/asgi.cpython-38.pyc +0 -0
- simo/__pycache__/settings.cpython-38.pyc +0 -0
- simo/__pycache__/urls.cpython-38.pyc +0 -0
- simo/__pycache__/wsgi.cpython-38.pyc +0 -0
- simo/core/__pycache__/admin.cpython-38.pyc +0 -0
- simo/core/__pycache__/api.cpython-38.pyc +0 -0
- simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
- simo/core/__pycache__/auto_urls.cpython-38.pyc +0 -0
- simo/core/__pycache__/autocomplete_views.cpython-38.pyc +0 -0
- simo/core/__pycache__/base_types.cpython-38.pyc +0 -0
- simo/core/__pycache__/context.cpython-38.pyc +0 -0
- simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/core/__pycache__/events.cpython-38.pyc +0 -0
- simo/core/__pycache__/forms.cpython-38.pyc +0 -0
- simo/core/__pycache__/gateways.cpython-38.pyc +0 -0
- simo/core/__pycache__/managers.cpython-38.pyc +0 -0
- simo/core/__pycache__/middleware.cpython-38.pyc +0 -0
- simo/core/__pycache__/models.cpython-38.pyc +0 -0
- simo/core/__pycache__/permissions.cpython-38.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/core/__pycache__/signal_receivers.cpython-38.pyc +0 -0
- simo/core/__pycache__/socket_consumers.cpython-38.pyc +0 -0
- simo/core/__pycache__/tasks.cpython-38.pyc +0 -0
- simo/core/__pycache__/views.cpython-38.pyc +0 -0
- simo/core/admin.py +28 -18
- simo/core/api.py +157 -16
- simo/core/api_meta.py +87 -0
- simo/core/auto_urls.py +4 -1
- simo/core/autocomplete_views.py +8 -4
- simo/core/base_types.py +1 -0
- simo/core/context.py +3 -1
- simo/core/controllers.py +134 -36
- simo/core/db_backend/base.py +7 -22
- simo/core/drf_braces/README +3 -0
- simo/core/drf_braces/__init__.py +7 -0
- simo/core/drf_braces/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/drf_braces/__pycache__/utils.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/__init__.py +5 -0
- simo/core/drf_braces/fields/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/_fields.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/custom.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/mixins.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/modified.cpython-38.pyc +0 -0
- simo/core/drf_braces/fields/_fields.py +48 -0
- simo/core/drf_braces/fields/custom.py +107 -0
- simo/core/drf_braces/fields/mixins.py +58 -0
- simo/core/drf_braces/fields/modified.py +41 -0
- simo/core/drf_braces/forms/__init__.py +0 -0
- simo/core/drf_braces/forms/fields.py +20 -0
- simo/core/drf_braces/forms/serializer_form.py +156 -0
- simo/core/drf_braces/mixins.py +52 -0
- simo/core/drf_braces/models.py +0 -0
- simo/core/drf_braces/parsers.py +72 -0
- simo/core/drf_braces/renderers.py +37 -0
- simo/core/drf_braces/serializers/__init__.py +0 -0
- simo/core/drf_braces/serializers/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/form_serializer.cpython-38.pyc +0 -0
- simo/core/drf_braces/serializers/enforce_validation_serializer.py +214 -0
- simo/core/drf_braces/serializers/form_serializer.py +391 -0
- simo/core/drf_braces/serializers/swapping.py +48 -0
- simo/core/drf_braces/tests/__init__.py +0 -0
- simo/core/drf_braces/tests/fields/__init__.py +0 -0
- simo/core/drf_braces/tests/fields/test_custom.py +94 -0
- simo/core/drf_braces/tests/fields/test_fields.py +13 -0
- simo/core/drf_braces/tests/fields/test_mixins.py +96 -0
- simo/core/drf_braces/tests/fields/test_modified.py +40 -0
- simo/core/drf_braces/tests/forms/__init__.py +0 -0
- simo/core/drf_braces/tests/forms/test_fields.py +46 -0
- simo/core/drf_braces/tests/forms/test_serializer_form.py +256 -0
- simo/core/drf_braces/tests/serializers/__init__.py +0 -0
- simo/core/drf_braces/tests/serializers/test_enforce_validation_serializer.py +169 -0
- simo/core/drf_braces/tests/serializers/test_form_serializer.py +387 -0
- simo/core/drf_braces/tests/serializers/test_swapping.py +40 -0
- simo/core/drf_braces/tests/test_mixins.py +111 -0
- simo/core/drf_braces/tests/test_parsers.py +73 -0
- simo/core/drf_braces/tests/test_renderers.py +23 -0
- simo/core/drf_braces/tests/test_utils.py +73 -0
- simo/core/drf_braces/utils.py +209 -0
- simo/core/events.py +3 -3
- simo/core/forms.py +79 -37
- simo/core/gateways.py +31 -14
- simo/core/management/commands/gateways_manager.py +0 -1
- simo/core/managers.py +81 -0
- simo/core/middleware.py +25 -0
- simo/core/migrations/0026_category_instance.py +20 -0
- simo/core/migrations/0027_remove_component_tags.py +17 -0
- simo/core/migrations/0028_rename_subcomponents_component_slaves.py +18 -0
- simo/core/migrations/0029_auto_20240229_1331.py +33 -0
- simo/core/migrations/__pycache__/0026_category_instance.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-38.pyc +0 -0
- simo/core/models.py +103 -66
- simo/core/permissions.py +28 -2
- simo/core/serializers.py +330 -26
- simo/core/socket_consumers.py +5 -14
- simo/core/tasks.py +11 -1
- simo/core/templates/admin/base.html +37 -10
- simo/core/templates/admin/wizard/discovery.html +188 -0
- simo/core/templates/admin/wizard/wizard_add.html +5 -5
- simo/core/utils/__pycache__/serialization.cpython-38.pyc +0 -0
- simo/core/utils/admin.py +9 -2
- simo/core/utils/formsets.py +17 -16
- simo/core/utils/helpers.py +1 -0
- simo/core/utils/serialization.py +56 -0
- simo/core/utils/type_constants.py +1 -1
- simo/core/utils/validators.py +14 -1
- simo/core/views.py +13 -0
- simo/fleet/__pycache__/admin.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/api.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/auto_urls.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/gateways.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/managers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/utils.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/views.cpython-38.pyc +0 -0
- simo/fleet/admin.py +53 -29
- simo/fleet/api.py +59 -3
- simo/fleet/auto_urls.py +2 -3
- simo/fleet/controllers.py +199 -16
- simo/fleet/forms.py +325 -483
- simo/fleet/gateways.py +44 -2
- simo/fleet/managers.py +32 -0
- simo/fleet/migrations/0025_auto_20240130_1334.py +27 -0
- simo/fleet/migrations/0026_rename_i2cinterface_scl_pin_and_more.py +64 -0
- simo/fleet/migrations/0027_auto_20240306_0802.py +170 -0
- simo/fleet/migrations/0028_remove_i2cinterface_scl_pin_no_and_more.py +21 -0
- simo/fleet/migrations/0029_alter_i2cinterface_scl_pin_and_more.py +24 -0
- simo/fleet/migrations/0030_colonelpin_label_alter_colonel_type.py +24 -0
- simo/fleet/migrations/0031_alter_colonel_type.py +18 -0
- simo/fleet/migrations/__pycache__/0025_auto_20240130_1334.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0026_rename_i2cinterface_scl_pin_and_more.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0027_auto_20240306_0802.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-38.pyc +0 -0
- simo/fleet/models.py +140 -82
- simo/fleet/serializers.py +35 -1
- simo/fleet/socket_consumers.py +239 -76
- simo/fleet/utils.py +15 -53
- simo/fleet/views.py +28 -14
- simo/generic/controllers.py +13 -89
- simo/generic/forms.py +29 -18
- simo/generic/gateways.py +73 -2
- simo/generic/models.py +3 -3
- simo/multimedia/controllers.py +9 -8
- simo/settings.py +7 -4
- simo/urls.py +4 -8
- simo/users/__pycache__/admin.cpython-38.pyc +0 -0
- simo/users/__pycache__/api.cpython-38.pyc +0 -0
- simo/users/__pycache__/auto_urls.cpython-38.pyc +0 -0
- simo/users/__pycache__/models.cpython-38.pyc +0 -0
- simo/users/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/users/__pycache__/sso_urls.cpython-38.pyc +0 -0
- simo/users/admin.py +8 -1
- simo/users/api.py +38 -2
- simo/users/auto_urls.py +2 -2
- simo/users/migrations/0025_rename_name_fingerprint_type_and_more.py +22 -0
- simo/users/migrations/__pycache__/0025_rename_name_fingerprint_type_and_more.cpython-38.pyc +0 -0
- simo/users/models.py +2 -3
- simo/users/serializers.py +15 -1
- simo/users/sso_urls.py +3 -3
- simo/wsgi.py +7 -0
- {simo-1.7.20.dist-info → simo-2.0.1.dist-info}/METADATA +8 -9
- {simo-1.7.20.dist-info → simo-2.0.1.dist-info}/RECORD +173 -189
- {simo-1.7.20.dist-info → simo-2.0.1.dist-info}/WHEEL +1 -1
- simo/core/db_backend/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/db_backend/__pycache__/base.cpython-38.pyc +0 -0
- simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0002_load_icons.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0003_create_default_zones_and_categories.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0004_create_generic.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0005_component_subcomponents.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0006_alter_component_subcomponents.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0007_component_change_init_to.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0008_alter_component_change_init_to.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0009_auto_20220707_1404.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0010_historyaggregate.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0011_component_last_change.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0012_instance.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0013_auto_20231003_0754.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0014_zone_instance.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0015_auto_20231004_1113.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0016_auto_20231004_1113.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0017_auto_20231004_1313.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0018_auto_20231005_0622.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0019_alter_gateway_type.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0020_component_meta.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-38.pyc +0 -0
- simo/core/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/templatetags/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/templatetags/__pycache__/components_list.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/admin.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/config_values.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/easing.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/form_fields.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/form_widgets.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/formsets.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/helpers.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/logs.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/mixins.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/model_helpers.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/relay.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/type_constants.cpython-38.pyc +0 -0
- simo/core/utils/__pycache__/validators.cpython-38.pyc +0 -0
- simo/fleet/tasks.py +0 -25
- simo/generic/__pycache__/__init__.cpython-37.pyc +0 -0
- simo/generic/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/generic/__pycache__/app_widgets.cpython-38.pyc +0 -0
- simo/generic/__pycache__/base_types.cpython-38.pyc +0 -0
- simo/generic/__pycache__/controllers.cpython-37.pyc +0 -0
- simo/generic/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/generic/__pycache__/forms.cpython-38.pyc +0 -0
- simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
- simo/generic/__pycache__/models.cpython-38.pyc +0 -0
- simo/generic/__pycache__/routing.cpython-38.pyc +0 -0
- simo/generic/__pycache__/socket_consumers.cpython-38.pyc +0 -0
- simo/generic/__pycache__/widgets.cpython-37.pyc +0 -0
- simo/multimedia/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/admin.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/api.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/app_widgets.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/base_types.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/forms.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/models.cpython-38.pyc +0 -0
- simo/multimedia/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0002_sound_length.cpython-38.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-38.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-38.pyc +0 -0
- simo/multimedia/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/admin.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/api.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/models.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/utils.cpython-38.pyc +0 -0
- simo/notifications/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
- simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.pyc +0 -0
- simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0001_initial.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0002_componentpermission.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0003_create_roles_and_system_user.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0004_user_secret_key.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0005_permissionsrole_instance.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0006_auto_20231003_0850.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0007_auto_20231003_1228.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0008_auto_20231003_1229.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0009_remove_user_role.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0010_auto_20231004_1313.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0011_auto_20231004_1313.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0012_alter_userinstancerole_unique_together.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0013_remove_user_roles.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0014_user_roles.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0015_remove_user_at_home.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0016_auto_20231005_1050.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/__init__.cpython-38.pyc +0 -0
- {simo-1.7.20.dist-info → simo-2.0.1.dist-info}/LICENSE.md +0 -0
- {simo-1.7.20.dist-info → simo-2.0.1.dist-info}/top_level.txt +0 -0
simo/generic/controllers.py
CHANGED
|
@@ -63,7 +63,7 @@ class Script(ControllerBase, TimerMixin):
|
|
|
63
63
|
)
|
|
64
64
|
return value
|
|
65
65
|
|
|
66
|
-
def
|
|
66
|
+
def _prepare_for_send(self, value):
|
|
67
67
|
if value == 'start':
|
|
68
68
|
new_code = getattr(self.component, 'new_code', None)
|
|
69
69
|
if new_code:
|
|
@@ -71,7 +71,7 @@ class Script(ControllerBase, TimerMixin):
|
|
|
71
71
|
self.component.refresh_from_db()
|
|
72
72
|
self.component.config['code'] = new_code
|
|
73
73
|
self.component.save(update_fields=['config'])
|
|
74
|
-
return
|
|
74
|
+
return value
|
|
75
75
|
|
|
76
76
|
def _val_to_success(self, value):
|
|
77
77
|
if value == 'start':
|
|
@@ -208,9 +208,13 @@ 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()
|
|
211
213
|
cooler = Component.objects.filter(
|
|
212
214
|
pk=self.component.config.get('cooler')
|
|
213
215
|
).first()
|
|
216
|
+
if cooler:
|
|
217
|
+
cooler.prepare_controller()
|
|
214
218
|
|
|
215
219
|
if not temperature_sensor or not temperature_sensor.alive:
|
|
216
220
|
print(f"No temperature sensor on {self.component}!")
|
|
@@ -322,47 +326,6 @@ class AlarmGroup(ControllerBase):
|
|
|
322
326
|
)
|
|
323
327
|
return value
|
|
324
328
|
|
|
325
|
-
def _send_to_device(self, value):
|
|
326
|
-
assert value in ('armed', 'disarmed')
|
|
327
|
-
|
|
328
|
-
other_alarm_groups = {}
|
|
329
|
-
stats = {
|
|
330
|
-
'disarmed': 0, 'pending-arm': 0, 'armed': 0, 'breached': 0
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
for c_id in self.component.config['components']:
|
|
334
|
-
slave = Component.objects.filter(pk=c_id).first()
|
|
335
|
-
if not slave:
|
|
336
|
-
continue
|
|
337
|
-
if value == 'armed':
|
|
338
|
-
if not slave.is_in_alarm():
|
|
339
|
-
slave.arm_status = 'armed'
|
|
340
|
-
stats['armed'] += 1
|
|
341
|
-
else:
|
|
342
|
-
slave.arm_status = 'pending-arm'
|
|
343
|
-
stats['pending-arm'] += 1
|
|
344
|
-
elif value == 'disarmed':
|
|
345
|
-
stats['disarmed'] += 1
|
|
346
|
-
slave.arm_status = 'disarmed'
|
|
347
|
-
|
|
348
|
-
slave.do_not_update_alarm_group = True
|
|
349
|
-
slave.save(update_fields=['arm_status'])
|
|
350
|
-
|
|
351
|
-
for other_group in Component.objects.filter(
|
|
352
|
-
controller_uid=AlarmGroup.uid,
|
|
353
|
-
config__components__contains=slave.id
|
|
354
|
-
).exclude(pk=self.component.pk):
|
|
355
|
-
other_alarm_groups[other_group.pk] = other_group
|
|
356
|
-
|
|
357
|
-
self.component.value = value
|
|
358
|
-
if stats['pending-arm']:
|
|
359
|
-
self.component.value = 'pending-arm'
|
|
360
|
-
self.component.config['stats'] = stats
|
|
361
|
-
self.component.save()
|
|
362
|
-
|
|
363
|
-
for pk, other_group in other_alarm_groups.items():
|
|
364
|
-
other_group.refresh_status()
|
|
365
|
-
|
|
366
329
|
def arm(self):
|
|
367
330
|
self.send('armed')
|
|
368
331
|
|
|
@@ -375,7 +338,6 @@ class AlarmGroup(ControllerBase):
|
|
|
375
338
|
)
|
|
376
339
|
|
|
377
340
|
def refresh_status(self):
|
|
378
|
-
|
|
379
341
|
stats = {
|
|
380
342
|
'disarmed': 0, 'pending-arm': 0, 'armed': 0, 'breached': 0
|
|
381
343
|
}
|
|
@@ -515,21 +477,6 @@ class Gate(ControllerBase, TimerMixin):
|
|
|
515
477
|
self.component.set(self.component.value + '_moving')
|
|
516
478
|
threading.Thread(target=cancel_move, daemon=True).start()
|
|
517
479
|
|
|
518
|
-
def _send_to_device(self, value):
|
|
519
|
-
switch = Component.objects.filter(
|
|
520
|
-
pk=self.component.config.get('action_switch')
|
|
521
|
-
).first()
|
|
522
|
-
if not switch:
|
|
523
|
-
return
|
|
524
|
-
|
|
525
|
-
if self.component.config.get('action_method') == 'click':
|
|
526
|
-
switch.click()
|
|
527
|
-
else:
|
|
528
|
-
if value == 'open':
|
|
529
|
-
switch.turn_on()
|
|
530
|
-
else:
|
|
531
|
-
switch.turn_off()
|
|
532
|
-
|
|
533
480
|
def open(self):
|
|
534
481
|
self.send('open')
|
|
535
482
|
|
|
@@ -662,9 +609,6 @@ class Blinds(ControllerBase, TimerMixin):
|
|
|
662
609
|
|
|
663
610
|
return value
|
|
664
611
|
|
|
665
|
-
def _send_to_device(self, value):
|
|
666
|
-
GatewayObjectCommand(self.component, **{'set_val': value}).publish()
|
|
667
|
-
|
|
668
612
|
def open(self):
|
|
669
613
|
self.send(0)
|
|
670
614
|
|
|
@@ -776,6 +720,7 @@ class Watering(ControllerBase):
|
|
|
776
720
|
switch = Component.objects.get(pk=contour_data['switch'])
|
|
777
721
|
except Component.DoesNotExist:
|
|
778
722
|
continue
|
|
723
|
+
switch.prepare_controller()
|
|
779
724
|
if run:
|
|
780
725
|
if switch.timer_engaged():
|
|
781
726
|
switch.stop_timer()
|
|
@@ -900,6 +845,7 @@ class Watering(ControllerBase):
|
|
|
900
845
|
switch = Component.objects.get(pk=contour_data['switch'])
|
|
901
846
|
except Component.DoesNotExist:
|
|
902
847
|
continue
|
|
848
|
+
switch.prepare_controller()
|
|
903
849
|
if switch.timer_engaged():
|
|
904
850
|
switch.stop_timer()
|
|
905
851
|
switch.turn_off()
|
|
@@ -1131,6 +1077,7 @@ class AlarmClock(ControllerBase):
|
|
|
1131
1077
|
print(f"Reverse event {event['uid']}!")
|
|
1132
1078
|
comp = Component.objects.filter(id=event['component']).first()
|
|
1133
1079
|
if comp:
|
|
1080
|
+
comp.prepare_controller()
|
|
1134
1081
|
if forward:
|
|
1135
1082
|
action_name = 'play_action'
|
|
1136
1083
|
else:
|
|
@@ -1370,7 +1317,8 @@ class AlarmClock(ControllerBase):
|
|
|
1370
1317
|
return current_value
|
|
1371
1318
|
|
|
1372
1319
|
|
|
1373
|
-
|
|
1320
|
+
# ----------- Dummy controllers -----------------------------
|
|
1321
|
+
|
|
1374
1322
|
class StateSelect(ControllerBase):
|
|
1375
1323
|
gateway_class = DummyGatewayHandler
|
|
1376
1324
|
name = _("State select")
|
|
@@ -1387,9 +1335,6 @@ class StateSelect(ControllerBase):
|
|
|
1387
1335
|
raise ValidationError("Unsupported value!")
|
|
1388
1336
|
return value
|
|
1389
1337
|
|
|
1390
|
-
def _send_to_device(self, value):
|
|
1391
|
-
self.component.set(value)
|
|
1392
|
-
|
|
1393
1338
|
|
|
1394
1339
|
class DummyBinarySensor(BinarySensor):
|
|
1395
1340
|
gateway_class = DummyGatewayHandler
|
|
@@ -1406,56 +1351,35 @@ class DummyMultiSensor(MultiSensor):
|
|
|
1406
1351
|
class DummySwitch(Switch):
|
|
1407
1352
|
gateway_class = DummyGatewayHandler
|
|
1408
1353
|
|
|
1409
|
-
def _send_to_device(self, value):
|
|
1410
|
-
self.component.set(value)
|
|
1411
|
-
|
|
1412
1354
|
|
|
1413
1355
|
class DummyDoubleSwitch(DoubleSwitch):
|
|
1414
1356
|
gateway_class = DummyGatewayHandler
|
|
1415
1357
|
|
|
1416
|
-
def _send_to_device(self, value):
|
|
1417
|
-
self.component.set(value)
|
|
1418
|
-
|
|
1419
1358
|
|
|
1420
1359
|
class DummyTripleSwitch(TripleSwitch):
|
|
1421
1360
|
gateway_class = DummyGatewayHandler
|
|
1422
1361
|
|
|
1423
|
-
def _send_to_device(self, value):
|
|
1424
|
-
self.component.set(value)
|
|
1425
|
-
|
|
1426
1362
|
|
|
1427
1363
|
class DummyQuadrupleSwitch(QuadrupleSwitch):
|
|
1428
1364
|
gateway_class = DummyGatewayHandler
|
|
1429
1365
|
|
|
1430
|
-
def _send_to_device(self, value):
|
|
1431
|
-
self.component.set(value)
|
|
1432
|
-
|
|
1433
1366
|
|
|
1434
1367
|
class DummyQuintupleSwitch(QuintupleSwitch):
|
|
1435
1368
|
gateway_class = DummyGatewayHandler
|
|
1436
1369
|
|
|
1437
|
-
def _send_to_device(self, value):
|
|
1438
|
-
self.component.set(value)
|
|
1439
|
-
|
|
1440
1370
|
|
|
1441
1371
|
class DummyDimmer(Dimmer):
|
|
1442
1372
|
gateway_class = DummyGatewayHandler
|
|
1443
1373
|
|
|
1444
|
-
def
|
|
1374
|
+
def _prepare_for_send(self, value):
|
|
1445
1375
|
if self.component.config.get('inverse'):
|
|
1446
1376
|
value = self.component.config.get('max') - value
|
|
1447
|
-
|
|
1377
|
+
return value
|
|
1448
1378
|
|
|
1449
1379
|
|
|
1450
1380
|
class DummyDimmerPlus(DimmerPlus):
|
|
1451
1381
|
gateway_class = DummyGatewayHandler
|
|
1452
1382
|
|
|
1453
|
-
def _send_to_device(self, value):
|
|
1454
|
-
self.component.set(value)
|
|
1455
|
-
|
|
1456
1383
|
|
|
1457
1384
|
class DummyRGBWLight(RGBWLight):
|
|
1458
1385
|
gateway_class = DummyGatewayHandler
|
|
1459
|
-
|
|
1460
|
-
def _send_to_device(self, value):
|
|
1461
|
-
self.component.set(value)
|
simo/generic/forms.py
CHANGED
|
@@ -14,7 +14,7 @@ from dal import autocomplete, forward
|
|
|
14
14
|
from simo.core.utils.config_values import config_to_dict
|
|
15
15
|
from simo.core.utils.formsets import FormsetField
|
|
16
16
|
from simo.core.utils.helpers import get_random_string
|
|
17
|
-
from simo.core.utils.form_fields import
|
|
17
|
+
from simo.core.utils.form_fields import ListSelect2Widget
|
|
18
18
|
from simo.conf import dynamic_settings
|
|
19
19
|
|
|
20
20
|
|
|
@@ -45,7 +45,7 @@ class ScriptConfigForm(BaseComponentForm):
|
|
|
45
45
|
def get_admin_fieldsets(cls, request, obj=None):
|
|
46
46
|
base_fields = (
|
|
47
47
|
'id', 'gateway', 'base_type', 'name', 'icon', 'zone', 'category',
|
|
48
|
-
'
|
|
48
|
+
'show_in_app', 'autostart',
|
|
49
49
|
'code', 'control', 'log'
|
|
50
50
|
)
|
|
51
51
|
|
|
@@ -196,6 +196,7 @@ class AlarmGroupConfigForm(BaseComponentForm):
|
|
|
196
196
|
"Can not cover self. Please remove - [%s]" % str(check_cmp)
|
|
197
197
|
)
|
|
198
198
|
if comp.base_type == 'alarm-group':
|
|
199
|
+
comp.prepare_controller()
|
|
199
200
|
self.recurse_check_alarm_groups(
|
|
200
201
|
comp.get_children(), check_cmp
|
|
201
202
|
)
|
|
@@ -220,6 +221,7 @@ class AlarmGroupConfigForm(BaseComponentForm):
|
|
|
220
221
|
c.save(update_fields=('config',))
|
|
221
222
|
if obj.id:
|
|
222
223
|
comp = Component.objects.get(id=obj.id)
|
|
224
|
+
comp.prepare_controller()
|
|
223
225
|
comp.refresh_status()
|
|
224
226
|
return obj
|
|
225
227
|
|
|
@@ -440,21 +442,29 @@ class WateringConfigForm(BaseComponentForm):
|
|
|
440
442
|
)
|
|
441
443
|
obj = super().save(commit=commit)
|
|
442
444
|
if commit:
|
|
443
|
-
obj.
|
|
445
|
+
obj.slaves.clear()
|
|
444
446
|
for contour in self.cleaned_data['contours']:
|
|
445
|
-
obj.
|
|
447
|
+
obj.slaves.add(
|
|
446
448
|
Component.objects.get(pk=contour['switch'])
|
|
447
449
|
)
|
|
448
450
|
return obj
|
|
449
451
|
|
|
450
452
|
|
|
451
453
|
class StateForm(forms.Form):
|
|
452
|
-
icon =
|
|
454
|
+
icon = forms.CharField(
|
|
455
|
+
widget=ListSelect2Widget(
|
|
456
|
+
url='autocomplete-icon', attrs={'data-html': True}
|
|
457
|
+
)
|
|
458
|
+
)
|
|
453
459
|
slug = forms.SlugField(required=True)
|
|
454
460
|
name = forms.CharField(required=True)
|
|
455
461
|
help_text = forms.CharField(required=False, widget=forms.Textarea(attrs={'rows': 3}))
|
|
456
462
|
prefix = 'states'
|
|
457
463
|
|
|
464
|
+
def clean(self):
|
|
465
|
+
print("Let's clean the data! ", self.cleaned_data)
|
|
466
|
+
return self.cleaned_data
|
|
467
|
+
|
|
458
468
|
|
|
459
469
|
class StateSelectForm(BaseComponentForm):
|
|
460
470
|
states = FormsetField(
|
|
@@ -493,20 +503,21 @@ class AlarmClockEventForm(forms.Form):
|
|
|
493
503
|
def clean(self):
|
|
494
504
|
if not self.cleaned_data.get('component'):
|
|
495
505
|
return self.cleaned_data
|
|
496
|
-
if not self.cleaned_data.get('
|
|
506
|
+
if not self.cleaned_data.get('play_action'):
|
|
497
507
|
return self.cleaned_data
|
|
498
508
|
component = self.cleaned_data.get('component')
|
|
499
|
-
|
|
509
|
+
component.prepare_controller()
|
|
510
|
+
if not hasattr(component, self.cleaned_data['play_action']):
|
|
500
511
|
self.add_error(
|
|
501
|
-
'
|
|
502
|
-
f"{component} has no {self.cleaned_data['
|
|
512
|
+
'play_action',
|
|
513
|
+
f"{component} has no {self.cleaned_data['play_action']} action!"
|
|
503
514
|
)
|
|
504
|
-
if self.cleaned_data.get('
|
|
505
|
-
if not hasattr(component, self.cleaned_data['
|
|
515
|
+
if self.cleaned_data.get('reverse_action'):
|
|
516
|
+
if not hasattr(component, self.cleaned_data['reverse_action']):
|
|
506
517
|
self.add_error(
|
|
507
|
-
'
|
|
518
|
+
'reverse_action',
|
|
508
519
|
f"{component} has no "
|
|
509
|
-
f"{self.cleaned_data['
|
|
520
|
+
f"{self.cleaned_data['reverse_action']} action!"
|
|
510
521
|
)
|
|
511
522
|
return self.cleaned_data
|
|
512
523
|
|
|
@@ -521,16 +532,16 @@ class AlarmClockConfigForm(BaseComponentForm):
|
|
|
521
532
|
def clean_default_events(self):
|
|
522
533
|
events = self.cleaned_data['default_events']
|
|
523
534
|
for i, cont in enumerate(events):
|
|
524
|
-
if not cont
|
|
535
|
+
if not cont.get('uid'):
|
|
525
536
|
cont['uid'] = get_random_string(6)
|
|
526
537
|
return events
|
|
527
538
|
|
|
528
539
|
def save(self, commit=True):
|
|
529
540
|
obj = super().save(commit=commit)
|
|
530
541
|
if commit:
|
|
531
|
-
obj.
|
|
542
|
+
obj.slaves.clear()
|
|
532
543
|
for comp in self.cleaned_data['default_events']:
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
544
|
+
c = Component.objects.filter(pk=comp['component']).first()
|
|
545
|
+
if c:
|
|
546
|
+
obj.slaves.add(c)
|
|
536
547
|
return obj
|
simo/generic/gateways.py
CHANGED
|
@@ -175,6 +175,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
175
175
|
):
|
|
176
176
|
tz = pytz.timezone(thermostat.zone.instance.timezone)
|
|
177
177
|
timezone.activate(tz)
|
|
178
|
+
thermostat.prepare_controller()
|
|
178
179
|
thermostat.evaluate()
|
|
179
180
|
|
|
180
181
|
def watch_alarm_clocks(self):
|
|
@@ -184,6 +185,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
184
185
|
):
|
|
185
186
|
tz = pytz.timezone(alarm_clock.zone.instance.timezone)
|
|
186
187
|
timezone.activate(tz)
|
|
188
|
+
alarm_clock.prepare_controller()
|
|
187
189
|
alarm_clock.tick()
|
|
188
190
|
|
|
189
191
|
def watch_scripts(self):
|
|
@@ -192,6 +194,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
192
194
|
controller_uid=Script.uid,
|
|
193
195
|
config__autostart=True
|
|
194
196
|
).exclude(value='running'):
|
|
197
|
+
script.prepare_controller()
|
|
195
198
|
self.start_script(script)
|
|
196
199
|
|
|
197
200
|
def watch_watering(self):
|
|
@@ -199,6 +202,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
199
202
|
for watering in Component.objects.filter(controller_uid=Watering.uid):
|
|
200
203
|
tz = pytz.timezone(watering.zone.instance.timezone)
|
|
201
204
|
timezone.activate(tz)
|
|
205
|
+
watering.prepare_controller()
|
|
202
206
|
if watering.value['status'] == 'running_program':
|
|
203
207
|
watering.set_program_progress(
|
|
204
208
|
watering.value['program_progress'] + 1
|
|
@@ -211,7 +215,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
211
215
|
self.logger = get_gw_logger(self.gateway_instance.id)
|
|
212
216
|
for task, period in self.periodic_tasks:
|
|
213
217
|
threading.Thread(
|
|
214
|
-
target=self._run_periodic_task, args=(task, period), daemon=True
|
|
218
|
+
target=self._run_periodic_task, args=(exit, task, period), daemon=True
|
|
215
219
|
).start()
|
|
216
220
|
|
|
217
221
|
from simo.generic.controllers import Script, IPCamera
|
|
@@ -261,7 +265,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
261
265
|
mqtt_client.subscribe(command.get_topic())
|
|
262
266
|
|
|
263
267
|
def on_mqtt_message(self, client, userdata, msg):
|
|
264
|
-
from simo.generic.controllers import Script, Blinds
|
|
268
|
+
from simo.generic.controllers import Script, Blinds, AlarmGroup, Gate
|
|
265
269
|
payload = json.loads(msg.payload)
|
|
266
270
|
component = get_event_obj(payload, Component)
|
|
267
271
|
if not component:
|
|
@@ -275,6 +279,10 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
275
279
|
return
|
|
276
280
|
elif component.controller_uid == Blinds.uid:
|
|
277
281
|
self.control_blinds(component, payload.get('set_val'))
|
|
282
|
+
elif component.controller_uid == AlarmGroup.uid:
|
|
283
|
+
self.control_alarm_group(component, payload.get('set_val'))
|
|
284
|
+
elif component.controller_uid == Gate:
|
|
285
|
+
self.control_gate(component, payload.get('set_val'))
|
|
278
286
|
|
|
279
287
|
def start_script(self, component):
|
|
280
288
|
print("START SCRIPT %s" % str(component))
|
|
@@ -325,9 +333,11 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
325
333
|
open_switch = Component.objects.get(
|
|
326
334
|
pk=blinds.config['open_switch']
|
|
327
335
|
)
|
|
336
|
+
open_switch.prepare_controller()
|
|
328
337
|
close_switch = Component.objects.get(
|
|
329
338
|
pk=blinds.config['close_switch']
|
|
330
339
|
)
|
|
340
|
+
close_switch.prepare_controller()
|
|
331
341
|
except:
|
|
332
342
|
return
|
|
333
343
|
|
|
@@ -357,9 +367,70 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
357
367
|
|
|
358
368
|
self.blinds_runners[blinds.id].start()
|
|
359
369
|
|
|
370
|
+
def control_alarm_group(self, alarm_group, value):
|
|
371
|
+
from simo.generic.controllers import AlarmGroup
|
|
372
|
+
|
|
373
|
+
other_alarm_groups = {}
|
|
374
|
+
stats = {
|
|
375
|
+
'disarmed': 0, 'pending-arm': 0, 'armed': 0, 'breached': 0
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
for c_id in alarm_group.config['components']:
|
|
379
|
+
slave = Component.objects.filter(pk=c_id).first()
|
|
380
|
+
if not slave:
|
|
381
|
+
continue
|
|
382
|
+
if value == 'armed':
|
|
383
|
+
if not slave.is_in_alarm():
|
|
384
|
+
slave.arm_status = 'armed'
|
|
385
|
+
stats['armed'] += 1
|
|
386
|
+
else:
|
|
387
|
+
slave.arm_status = 'pending-arm'
|
|
388
|
+
stats['pending-arm'] += 1
|
|
389
|
+
elif value == 'disarmed':
|
|
390
|
+
stats['disarmed'] += 1
|
|
391
|
+
slave.arm_status = 'disarmed'
|
|
392
|
+
|
|
393
|
+
slave.do_not_update_alarm_group = True
|
|
394
|
+
slave.save(update_fields=['arm_status'])
|
|
395
|
+
|
|
396
|
+
for other_group in Component.objects.filter(
|
|
397
|
+
controller_uid=AlarmGroup.uid,
|
|
398
|
+
config__components__contains=slave.id
|
|
399
|
+
).exclude(pk=alarm_group.pk):
|
|
400
|
+
other_alarm_groups[other_group.pk] = other_group
|
|
401
|
+
|
|
402
|
+
alarm_group.value = value
|
|
403
|
+
if stats['pending-arm']:
|
|
404
|
+
alarm_group.value = 'pending-arm'
|
|
405
|
+
alarm_group.config['stats'] = stats
|
|
406
|
+
alarm_group.save()
|
|
407
|
+
|
|
408
|
+
for pk, other_group in other_alarm_groups.items():
|
|
409
|
+
other_group.prepare_controller()
|
|
410
|
+
other_group.refresh_status()
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def control_gate(self, gate, value):
|
|
414
|
+
switch = Component.objects.filter(
|
|
415
|
+
pk=gate.config.get('action_switch')
|
|
416
|
+
).first()
|
|
417
|
+
if not switch:
|
|
418
|
+
return
|
|
419
|
+
switch.prepare_controller()
|
|
360
420
|
|
|
421
|
+
if gate.config.get('action_method') == 'click':
|
|
422
|
+
switch.click()
|
|
423
|
+
else:
|
|
424
|
+
if value == 'open':
|
|
425
|
+
switch.turn_on()
|
|
426
|
+
else:
|
|
427
|
+
switch.turn_off()
|
|
361
428
|
|
|
362
429
|
|
|
363
430
|
class DummyGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
364
431
|
name = "Dummy"
|
|
365
432
|
config_form = BaseGatewayForm
|
|
433
|
+
|
|
434
|
+
def perform_value_send(self, component, value):
|
|
435
|
+
component.controller.set(value)
|
|
436
|
+
|
simo/generic/models.py
CHANGED
|
@@ -63,9 +63,9 @@ def handle_alarm_groups(sender, instance, *args, **kwargs):
|
|
|
63
63
|
alarm_group.set(alarm_group_value)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
@receiver(
|
|
67
|
-
def set_initial_alarm_group_stats(sender, instance, *args, **kwargs):
|
|
68
|
-
if
|
|
66
|
+
@receiver(post_save, sender=Component)
|
|
67
|
+
def set_initial_alarm_group_stats(sender, instance, created, *args, **kwargs):
|
|
68
|
+
if not created:
|
|
69
69
|
return
|
|
70
70
|
if instance.controller_uid != AlarmGroup.uid:
|
|
71
71
|
return
|
simo/multimedia/controllers.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from django.utils.translation import gettext_lazy as _
|
|
2
2
|
from django.core.exceptions import ValidationError
|
|
3
3
|
from simo.core.controllers import BEFORE_SEND, BEFORE_SET
|
|
4
|
-
from simo.core.controllers import
|
|
4
|
+
from simo.core.controllers import Switch, TimerMixin
|
|
5
5
|
from .app_widgets import AudioPlayerWidget, VideoPlayerWidget
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class BasePlayer(
|
|
8
|
+
class BasePlayer(Switch):
|
|
9
9
|
default_config = {
|
|
10
10
|
'has_volume_control': True,
|
|
11
11
|
}
|
|
@@ -22,6 +22,13 @@ class BasePlayer(ControllerBase, TimerMixin):
|
|
|
22
22
|
}
|
|
23
23
|
default_value = 'stopped'
|
|
24
24
|
|
|
25
|
+
def _prepare_for_send(self, value):
|
|
26
|
+
if isinstance(value, bool):
|
|
27
|
+
if value:
|
|
28
|
+
return 'play'
|
|
29
|
+
return 'pause'
|
|
30
|
+
return value
|
|
31
|
+
|
|
25
32
|
def _validate_val(self, value, occasion=None):
|
|
26
33
|
return value
|
|
27
34
|
|
|
@@ -59,12 +66,6 @@ class BasePlayer(ControllerBase, TimerMixin):
|
|
|
59
66
|
def play_library_item(self, val):
|
|
60
67
|
self.send({'play_from_library': val})
|
|
61
68
|
|
|
62
|
-
def turn_on(self):
|
|
63
|
-
self.play()
|
|
64
|
-
|
|
65
|
-
def turn_off(self):
|
|
66
|
-
self.pause()
|
|
67
|
-
|
|
68
69
|
def toggle(self):
|
|
69
70
|
if self.component.value == 'playing':
|
|
70
71
|
self.turn_off()
|
simo/settings.py
CHANGED
|
@@ -41,7 +41,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
|
|
41
41
|
|
|
42
42
|
INSTALLED_APPS = [
|
|
43
43
|
'channels',
|
|
44
|
-
'filebrowser',
|
|
45
44
|
'dal',
|
|
46
45
|
'dal_select2',
|
|
47
46
|
'django.forms',
|
|
@@ -87,8 +86,11 @@ MIDDLEWARE = [
|
|
|
87
86
|
'simo.core.middleware.instance_middleware'
|
|
88
87
|
]
|
|
89
88
|
|
|
89
|
+
|
|
90
|
+
FILE_UPLOAD_MAX_MEMORY_SIZE = 20971520 # 20Mb
|
|
91
|
+
|
|
90
92
|
ROOT_URLCONF = 'urls'
|
|
91
|
-
WSGI_APPLICATION = 'wsgi.application'
|
|
93
|
+
WSGI_APPLICATION = 'simo.wsgi.application'
|
|
92
94
|
|
|
93
95
|
CHANNELS_URLCONF = 'simo.asgi'
|
|
94
96
|
ASGI_APPLICATION = "asgi.application"
|
|
@@ -120,7 +122,7 @@ DATABASES = {
|
|
|
120
122
|
'default': {
|
|
121
123
|
'ENGINE': 'simo.core.db_backend',
|
|
122
124
|
'NAME': 'SIMO',
|
|
123
|
-
'ATOMIC_REQUESTS': False
|
|
125
|
+
'ATOMIC_REQUESTS': False,
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -185,7 +187,8 @@ REST_FRAMEWORK = {
|
|
|
185
187
|
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
|
186
188
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
|
187
189
|
'PAGE_SIZE': 1000,
|
|
188
|
-
'DATETIME_FORMAT': '%s.%f'
|
|
190
|
+
'DATETIME_FORMAT': '%s.%f',
|
|
191
|
+
'DEFAULT_METADATA_CLASS': 'simo.core.api_meta.SIMOAPIMetadata'
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
REDIS_DB = {
|
simo/urls.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
import inspect
|
|
3
|
+
import sys
|
|
3
4
|
from django.urls import path, include
|
|
4
5
|
from django.conf.urls.static import static
|
|
5
6
|
from django.conf import settings
|
|
@@ -9,23 +10,17 @@ from django.apps import apps
|
|
|
9
10
|
from django.contrib.auth.views import LogoutView
|
|
10
11
|
from rest_framework import routers
|
|
11
12
|
from rest_framework.viewsets import GenericViewSet
|
|
12
|
-
from filebrowser.sites import FileBrowserSite
|
|
13
13
|
from django.contrib.admin import site as admin_site
|
|
14
14
|
from simo.users.views import protected_static
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
filebrowser_site = FileBrowserSite(
|
|
18
|
-
name='filebrowser', storage=FileSystemStorage(
|
|
19
|
-
settings.VAR_DIR, settings.VAR_DIR_URL
|
|
20
|
-
)
|
|
21
|
-
)
|
|
22
17
|
|
|
23
18
|
rest_router = routers.DefaultRouter()
|
|
24
19
|
registered_classes = []
|
|
25
20
|
for name, app in apps.app_configs.items():
|
|
26
21
|
try:
|
|
27
22
|
apis = importlib.import_module('%s.api' % app.name)
|
|
28
|
-
except ModuleNotFoundError:
|
|
23
|
+
except ModuleNotFoundError as e:
|
|
29
24
|
continue
|
|
30
25
|
for cls_name, cls in apis.__dict__.items():
|
|
31
26
|
cls_id = '%s.%s' % (app.name, cls_name)
|
|
@@ -39,7 +34,8 @@ for name, app in apps.app_configs.items():
|
|
|
39
34
|
urlpatterns = [
|
|
40
35
|
path('', RedirectView.as_view(pattern_name='admin:index')),
|
|
41
36
|
path('login/', include('simo.users.sso_urls')),
|
|
42
|
-
|
|
37
|
+
|
|
38
|
+
|
|
43
39
|
path('admin/login/',
|
|
44
40
|
RedirectView.as_view(
|
|
45
41
|
pattern_name='login', query_string=True
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/users/admin.py
CHANGED
|
@@ -6,7 +6,7 @@ from django.contrib.auth.admin import UserAdmin as OrgUserAdmin
|
|
|
6
6
|
from django.contrib import admin
|
|
7
7
|
from .models import (
|
|
8
8
|
PermissionsRole, ComponentPermission, User, UserDevice, UserDeviceReportLog,
|
|
9
|
-
InstanceInvitation, InstanceUser
|
|
9
|
+
InstanceInvitation, InstanceUser, Fingerprint
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
|
|
@@ -211,4 +211,11 @@ class InstanceInvitationAdmin(admin.ModelAdmin):
|
|
|
211
211
|
"No invitations were sent."
|
|
212
212
|
)
|
|
213
213
|
|
|
214
|
+
@admin.register(Fingerprint)
|
|
215
|
+
class FingerprintAdmin(admin.ModelAdmin):
|
|
216
|
+
list_display = 'value', 'type', 'date_created', 'user',
|
|
217
|
+
search_fields = 'value', 'type', 'user__name', 'user__email'
|
|
218
|
+
readonly_fields = 'value', 'type', 'date_created'
|
|
214
219
|
|
|
220
|
+
def has_add_permission(self, request):
|
|
221
|
+
return False
|