simo 1.7.20__py3-none-any.whl → 2.0.0__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 +112 -32
- 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 +54 -25
- 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 +134 -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.0.dist-info}/METADATA +8 -9
- {simo-1.7.20.dist-info → simo-2.0.0.dist-info}/RECORD +173 -189
- {simo-1.7.20.dist-info → simo-2.0.0.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.0.dist-info}/LICENSE.md +0 -0
- {simo-1.7.20.dist-info → simo-2.0.0.dist-info}/top_level.txt +0 -0
simo/fleet/socket_consumers.py
CHANGED
|
@@ -2,23 +2,24 @@ import asyncio
|
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
4
|
import pytz
|
|
5
|
-
import
|
|
5
|
+
import traceback
|
|
6
6
|
import sys
|
|
7
|
+
import zlib
|
|
8
|
+
from django.db import transaction
|
|
7
9
|
from logging.handlers import RotatingFileHandler
|
|
8
|
-
from django.urls import reverse
|
|
9
10
|
from django.utils import timezone
|
|
10
11
|
from django.conf import settings
|
|
11
12
|
import paho.mqtt.client as mqtt
|
|
12
13
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
|
13
14
|
from asgiref.sync import sync_to_async
|
|
14
|
-
from simo.core.utils.helpers import get_random_string
|
|
15
15
|
from simo.core.utils.model_helpers import get_log_file_path
|
|
16
16
|
from simo.core.events import GatewayObjectCommand, get_event_obj
|
|
17
|
-
from simo.core.utils.helpers import get_self_ip
|
|
18
17
|
from simo.core.models import Gateway, Instance, Component
|
|
19
18
|
from simo.conf import dynamic_settings
|
|
19
|
+
from simo.users.models import Fingerprint
|
|
20
20
|
from .gateways import FleetGatewayHandler
|
|
21
21
|
from .models import Colonel
|
|
22
|
+
from .controllers import TTLock
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class FleetConsumer(AsyncWebsocketConsumer):
|
|
@@ -43,9 +44,8 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
43
44
|
|
|
44
45
|
async def connect(self):
|
|
45
46
|
|
|
46
|
-
print("Fleet socket connect! Headers: ", self.scope['headers'])
|
|
47
47
|
headers = {
|
|
48
|
-
item[0].decode(): item[1].decode() for item in self.scope['headers']
|
|
48
|
+
item[0].decode().lower(): item[1].decode() for item in self.scope['headers']
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
instance_uid = headers.get('instance-uid')
|
|
@@ -81,44 +81,40 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
81
81
|
tz = await sync_to_async(get_tz, thread_sensitive=True)()
|
|
82
82
|
timezone.activate(tz)
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
def get_colonel():
|
|
85
|
+
# looks like update_or_create doesn't work in socket/async environment.
|
|
86
|
+
defaults={
|
|
87
87
|
'instance': self.instance,
|
|
88
|
+
'name': headers.get('colonel-name'),
|
|
88
89
|
'type': headers['colonel-type'],
|
|
89
90
|
'firmware_version': headers['firmware-version'],
|
|
90
91
|
'last_seen': timezone.now()
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
+
with transaction.atomic():
|
|
94
|
+
colonel, new = Colonel.objects.get_or_create(
|
|
95
|
+
uid=headers['colonel-uid'], defaults=defaults
|
|
96
|
+
)
|
|
97
|
+
if not new:
|
|
98
|
+
for key, val in defaults.items():
|
|
99
|
+
setattr(colonel, key, val)
|
|
100
|
+
if new:
|
|
101
|
+
colonel.enabled = True
|
|
102
|
+
colonel.save()
|
|
103
|
+
|
|
104
|
+
return colonel, new
|
|
105
|
+
|
|
106
|
+
self.colonel, new = await sync_to_async(
|
|
107
|
+
get_colonel, thread_sensitive=True
|
|
108
|
+
)()
|
|
93
109
|
|
|
94
|
-
print(f"Colonel {self.colonel} connected
|
|
110
|
+
print(f"Colonel {self.colonel} connected!")
|
|
95
111
|
if not self.colonel.enabled:
|
|
96
112
|
print("Colonel %s drop, it's not enabled!" % str(self.colonel))
|
|
97
113
|
await self.accept()
|
|
98
114
|
return await self.close()
|
|
99
115
|
|
|
100
|
-
if
|
|
101
|
-
|
|
102
|
-
self.colonel.name = name
|
|
103
|
-
self.colonel.save()
|
|
104
|
-
|
|
105
|
-
await sync_to_async(
|
|
106
|
-
save_colonel_name, thread_sensitive=True
|
|
107
|
-
)(headers['colonel-name'])
|
|
108
|
-
|
|
109
|
-
def set_colonel_authorized(val):
|
|
110
|
-
self.colonel.is_authorized = val
|
|
111
|
-
self.colonel.save()
|
|
112
|
-
|
|
113
|
-
if headers.get('instance-uid') == self.colonel.instance.uid \
|
|
114
|
-
and headers.get('instance-secret') == self.colonel.instance.fleet_options.secret_key:
|
|
115
|
-
await sync_to_async(
|
|
116
|
-
set_colonel_authorized, thread_sensitive=True
|
|
117
|
-
)(True)
|
|
118
|
-
else:
|
|
119
|
-
await sync_to_async(
|
|
120
|
-
set_colonel_authorized, thread_sensitive=True
|
|
121
|
-
)(False)
|
|
116
|
+
if headers.get('instance-uid') != self.colonel.instance.uid \
|
|
117
|
+
or headers.get('instance-secret') != self.colonel.instance.fleet_options.secret_key:
|
|
122
118
|
print("NOT authorized!")
|
|
123
119
|
return await self.close()
|
|
124
120
|
|
|
@@ -126,16 +122,27 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
126
122
|
|
|
127
123
|
await self.accept()
|
|
128
124
|
|
|
125
|
+
await self.log_colonel_connected()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def get_gateway():
|
|
129
|
+
return Gateway.objects.filter(
|
|
130
|
+
type=FleetGatewayHandler.uid
|
|
131
|
+
).first()
|
|
132
|
+
|
|
133
|
+
self.gateway = await sync_to_async(
|
|
134
|
+
get_gateway, thread_sensitive=True
|
|
135
|
+
)()
|
|
136
|
+
|
|
129
137
|
if self.colonel.firmware_auto_update \
|
|
130
138
|
and self.colonel.minor_upgrade_available:
|
|
131
139
|
await self.firmware_update(self.colonel.minor_upgrade_available)
|
|
132
140
|
else:
|
|
133
141
|
def on_mqtt_connect(mqtt_client, userdata, flags, rc):
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
mqtt_client.subscribe(command.get_topic())
|
|
142
|
+
command = GatewayObjectCommand(self.gateway)
|
|
143
|
+
TOPIC = command.get_topic()
|
|
144
|
+
print("SUBSCRIBE TO TOPIC: ", TOPIC)
|
|
145
|
+
mqtt_client.subscribe(TOPIC)
|
|
139
146
|
|
|
140
147
|
self.mqtt_client = mqtt.Client()
|
|
141
148
|
self.mqtt_client.username_pw_set('root', settings.SECRET_KEY)
|
|
@@ -153,9 +160,11 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
153
160
|
# If we force this, vales get overridden by what is last
|
|
154
161
|
# known by the hub
|
|
155
162
|
# config = await self.get_config_data()
|
|
156
|
-
# await self.
|
|
163
|
+
# await self.send_data(
|
|
157
164
|
# 'command': 'set_config', 'data': config
|
|
158
|
-
# })
|
|
165
|
+
# })
|
|
166
|
+
|
|
167
|
+
await self.send_data({'command': 'hello'})
|
|
159
168
|
|
|
160
169
|
asyncio.create_task(self.watch_connection())
|
|
161
170
|
|
|
@@ -174,11 +183,11 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
174
183
|
await asyncio.sleep(10)
|
|
175
184
|
# Default pinging system sometimes get's lost somewhere,
|
|
176
185
|
# therefore we use our own to ensure connection
|
|
177
|
-
await self.
|
|
186
|
+
await self.send_data({'command': 'ping'})
|
|
178
187
|
|
|
179
188
|
async def firmware_update(self, to_version):
|
|
180
189
|
print("Firmware update: ", str(self.colonel))
|
|
181
|
-
await self.
|
|
190
|
+
await self.send_data({'command': 'ota_update', 'version': to_version})
|
|
182
191
|
|
|
183
192
|
async def get_config_data(self):
|
|
184
193
|
self.colonel = await sync_to_async(
|
|
@@ -207,67 +216,162 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
207
216
|
}
|
|
208
217
|
config_data['settings'].update(instance_options)
|
|
209
218
|
i2c_interfaces = await sync_to_async(list, thread_sensitive=True)(
|
|
210
|
-
self.colonel.i2c_interfaces.all()
|
|
219
|
+
self.colonel.i2c_interfaces.all().select_related(
|
|
220
|
+
'scl_pin', 'sda_pin'
|
|
221
|
+
)
|
|
211
222
|
)
|
|
212
223
|
for i2c_interface in i2c_interfaces:
|
|
213
224
|
config_data['interfaces']['i2c-%d' % i2c_interface.no] = {
|
|
214
|
-
'scl': i2c_interface.scl_pin, 'sda': i2c_interface.sda_pin,
|
|
225
|
+
'scl': i2c_interface.scl_pin.no, 'sda': i2c_interface.sda_pin.no,
|
|
215
226
|
'freq': i2c_interface.freq
|
|
216
227
|
}
|
|
217
228
|
components = await sync_to_async(
|
|
218
229
|
list, thread_sensitive=True
|
|
219
|
-
)(self.colonel.components.all())
|
|
220
|
-
|
|
230
|
+
)(self.colonel.components.all().prefetch_related('slaves'))
|
|
231
|
+
|
|
232
|
+
def get_comp_config(comp):
|
|
221
233
|
try:
|
|
222
|
-
|
|
223
|
-
'type':
|
|
224
|
-
'
|
|
225
|
-
|
|
226
|
-
|
|
234
|
+
comp_config = {
|
|
235
|
+
'type': comp.controller.uid.split('.')[-1],
|
|
236
|
+
'val': comp.controller._prepare_for_send(
|
|
237
|
+
comp.value
|
|
238
|
+
),
|
|
239
|
+
'config': comp.controller._get_colonel_config()
|
|
227
240
|
}
|
|
241
|
+
slaves = [
|
|
242
|
+
s.id for s in comp.slaves.all()
|
|
243
|
+
if s.config.get('colonel') == self.colonel.id
|
|
244
|
+
]
|
|
245
|
+
if slaves:
|
|
246
|
+
comp_config['slaves'] = slaves
|
|
247
|
+
if comp.meta.get('options'):
|
|
248
|
+
comp_config['options'] = comp.meta['options']
|
|
249
|
+
|
|
250
|
+
config_data['devices'][str(comp.id)] = comp_config
|
|
228
251
|
except:
|
|
252
|
+
print("Error preparing component config")
|
|
253
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
254
|
+
else:
|
|
255
|
+
return comp_config
|
|
256
|
+
|
|
257
|
+
for component in components:
|
|
258
|
+
|
|
259
|
+
comp_config = components = await sync_to_async(
|
|
260
|
+
get_comp_config, thread_sensitive=True
|
|
261
|
+
)(component)
|
|
262
|
+
|
|
263
|
+
if not comp_config:
|
|
229
264
|
continue
|
|
230
265
|
|
|
266
|
+
slaves = [
|
|
267
|
+
s.id for s in component.slaves.all()
|
|
268
|
+
if s.config.get('colonel') == self.colonel.id
|
|
269
|
+
]
|
|
270
|
+
if slaves:
|
|
271
|
+
comp_config['slaves'] = slaves
|
|
272
|
+
if component.meta.get('options'):
|
|
273
|
+
comp_config['options'] = component.meta['options']
|
|
274
|
+
|
|
275
|
+
config_data['devices'][str(component.id)] = comp_config
|
|
276
|
+
|
|
277
|
+
|
|
231
278
|
return config_data
|
|
232
279
|
|
|
233
280
|
def on_mqtt_message(self, client, userdata, msg):
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
281
|
+
try:
|
|
282
|
+
payload = json.loads(msg.payload)
|
|
283
|
+
|
|
284
|
+
if 'bulk_send' in payload:
|
|
285
|
+
colonel_component_ids = [c['id'] for c in Component.objects.filter(
|
|
286
|
+
config__colonel=self.colonel.id,
|
|
287
|
+
gateway__in=Gateway.objects.filter(type=FleetGatewayHandler.uid),
|
|
288
|
+
id__in=[int(id) for id in payload['bulk_send'].keys()]
|
|
289
|
+
).values('id')]
|
|
290
|
+
bulk_send_data = []
|
|
291
|
+
for comp_id, value in payload['bulk_send'].items():
|
|
292
|
+
if int(comp_id) not in colonel_component_ids:
|
|
293
|
+
continue
|
|
294
|
+
bulk_send_data.append({'id': int(comp_id), 'val': value})
|
|
295
|
+
if bulk_send_data:
|
|
296
|
+
asyncio.run(self.send_data({
|
|
297
|
+
'command': 'bulk_set',
|
|
298
|
+
'values': bulk_send_data
|
|
299
|
+
}))
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
obj = get_event_obj(payload)
|
|
303
|
+
|
|
304
|
+
if obj == self.colonel:
|
|
305
|
+
if payload.get('command') == 'update_firmware':
|
|
306
|
+
asyncio.run(self.firmware_update(payload['to_version']))
|
|
307
|
+
elif payload.get('command') == 'update_config':
|
|
308
|
+
async def send_config():
|
|
309
|
+
config = await self.get_config_data()
|
|
310
|
+
await self.send_data({
|
|
311
|
+
'command': 'set_config', 'data': config
|
|
312
|
+
}, compress=True)
|
|
313
|
+
asyncio.run(send_config())
|
|
314
|
+
elif payload.get('command') == 'discover-ttlock':
|
|
315
|
+
print("SEND discover-ttlock command!")
|
|
316
|
+
asyncio.run(self.send_data({
|
|
317
|
+
'command': 'discover-ttlock'
|
|
318
|
+
}))
|
|
319
|
+
elif payload.get('command') == 'finalize':
|
|
320
|
+
asyncio.run(self.send_data({
|
|
321
|
+
'command': 'finalize',
|
|
322
|
+
'data': payload.get('data', {})
|
|
323
|
+
}))
|
|
324
|
+
else:
|
|
325
|
+
asyncio.run(self.send_data(payload))
|
|
326
|
+
|
|
327
|
+
elif isinstance(obj, Component):
|
|
328
|
+
if int(obj.config.get('colonel')) != self.colonel.id:
|
|
329
|
+
return
|
|
330
|
+
if 'set_val' in payload:
|
|
331
|
+
asyncio.run(self.send_data({
|
|
332
|
+
'command': 'set_val',
|
|
333
|
+
'id': obj.id,
|
|
334
|
+
'val': payload['set_val']
|
|
335
|
+
}))
|
|
336
|
+
if 'update_options' in payload:
|
|
337
|
+
asyncio.run(self.send_data({
|
|
338
|
+
'command': 'update_options',
|
|
339
|
+
'id': obj.id,
|
|
340
|
+
'options': payload['options']
|
|
341
|
+
}))
|
|
342
|
+
|
|
343
|
+
except Exception as e:
|
|
344
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
345
|
+
|
|
253
346
|
|
|
254
347
|
async def receive(self, text_data=None, bytes_data=None):
|
|
255
348
|
if text_data:
|
|
256
|
-
print("
|
|
349
|
+
print(f"{self.colonel}: {text_data}")
|
|
257
350
|
data = json.loads(text_data)
|
|
258
351
|
if 'get_config' in data:
|
|
259
352
|
config = await self.get_config_data()
|
|
260
|
-
|
|
353
|
+
print("Send config: ", config)
|
|
354
|
+
await self.send_data({
|
|
261
355
|
'command': 'set_config', 'data': config
|
|
262
|
-
})
|
|
356
|
+
}, compress=True)
|
|
263
357
|
elif 'comp' in data:
|
|
264
358
|
try:
|
|
359
|
+
try:
|
|
360
|
+
id=int(data['comp'])
|
|
361
|
+
except:
|
|
362
|
+
return
|
|
363
|
+
|
|
265
364
|
component = await sync_to_async(
|
|
266
365
|
Component.objects.get, thread_sensitive=True
|
|
267
|
-
)(id=
|
|
366
|
+
)(id=id)
|
|
268
367
|
|
|
269
368
|
if 'val' in data:
|
|
270
369
|
def receive_val(val):
|
|
370
|
+
if data.get('actor'):
|
|
371
|
+
fingerprint = Fingerprint.objects.filter(
|
|
372
|
+
value=f"ttlock-{component.id}-{data.get('actor')}",
|
|
373
|
+
).first()
|
|
374
|
+
component.change_init_fingerprint = fingerprint
|
|
271
375
|
component.controller._receive_from_device(
|
|
272
376
|
val, bool(data.get('alive'))
|
|
273
377
|
)
|
|
@@ -276,7 +380,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
276
380
|
)(data['val'])
|
|
277
381
|
|
|
278
382
|
if 'options' in data:
|
|
279
|
-
print("Received options update")
|
|
280
383
|
def receive_options(val):
|
|
281
384
|
component.meta['options'] = val
|
|
282
385
|
component.save()
|
|
@@ -284,8 +387,55 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
284
387
|
receive_options, thread_sensitive=True
|
|
285
388
|
)(data['options'])
|
|
286
389
|
|
|
390
|
+
if 'codes' in data and component.controller_uid == TTLock.uid:
|
|
391
|
+
def save_codes(codes):
|
|
392
|
+
component.meta['codes'] = codes
|
|
393
|
+
for code in codes:
|
|
394
|
+
Fingerprint.objects.get_or_create(
|
|
395
|
+
value=f"ttlock-{component.id}-code-{str(code)}",
|
|
396
|
+
defaults={'type': "TTLock code"}
|
|
397
|
+
)
|
|
398
|
+
component.save()
|
|
399
|
+
await sync_to_async(
|
|
400
|
+
save_codes, thread_sensitive=True
|
|
401
|
+
)(data['codes'])
|
|
402
|
+
if 'fingerprints' in data and component.controller_uid == TTLock.uid:
|
|
403
|
+
def save_codes(codes):
|
|
404
|
+
component.meta['fingerprints'] = codes
|
|
405
|
+
for code in codes:
|
|
406
|
+
Fingerprint.objects.get_or_create(
|
|
407
|
+
value=f"ttlock-{component.id}-finger-{str(code)}",
|
|
408
|
+
defaults={'type': "TTLock Fingerprint"}
|
|
409
|
+
)
|
|
410
|
+
component.save()
|
|
411
|
+
await sync_to_async(
|
|
412
|
+
save_codes, thread_sensitive=True
|
|
413
|
+
)(data['fingerprints'])
|
|
414
|
+
|
|
287
415
|
except Exception as e:
|
|
288
|
-
print(
|
|
416
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
417
|
+
|
|
418
|
+
elif 'discover-ttlock' in data:
|
|
419
|
+
def process_discovery_result():
|
|
420
|
+
self.gateway.refresh_from_db()
|
|
421
|
+
if self.gateway.discovery.get('finished'):
|
|
422
|
+
return Component.objects.filter(
|
|
423
|
+
meta__finalization_data__temp_id=data['result']['id']
|
|
424
|
+
).first()
|
|
425
|
+
try:
|
|
426
|
+
self.gateway.process_discovery(data)
|
|
427
|
+
except Exception as e:
|
|
428
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
429
|
+
self.gateway.finish_discovery()
|
|
430
|
+
|
|
431
|
+
finished_comp = await sync_to_async(
|
|
432
|
+
process_discovery_result, thread_sensitive=True
|
|
433
|
+
)()
|
|
434
|
+
if finished_comp:
|
|
435
|
+
await self.send_data({
|
|
436
|
+
'command': 'finalize',
|
|
437
|
+
'data': finished_comp.meta['finalization_data']
|
|
438
|
+
})
|
|
289
439
|
|
|
290
440
|
elif bytes_data:
|
|
291
441
|
if not self.colonel_logger:
|
|
@@ -294,6 +444,11 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
294
444
|
for logline in bytes_data.decode(errors='replace').split('\n'):
|
|
295
445
|
self.colonel_logger.log(logging.INFO, logline)
|
|
296
446
|
|
|
447
|
+
await self.log_colonel_connected()
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
async def log_colonel_connected(self):
|
|
451
|
+
|
|
297
452
|
def save_last_seen():
|
|
298
453
|
self.colonel.socket_connected = True
|
|
299
454
|
self.colonel.last_seen = timezone.now()
|
|
@@ -303,6 +458,14 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
303
458
|
|
|
304
459
|
await sync_to_async(save_last_seen, thread_sensitive=True)()
|
|
305
460
|
|
|
461
|
+
async def send_data(self, data, compress=False):
|
|
462
|
+
data = json.dumps(data)
|
|
463
|
+
if compress:
|
|
464
|
+
data = zlib.compress(data.encode())
|
|
465
|
+
await self.send(bytes_data=data)
|
|
466
|
+
else:
|
|
467
|
+
await self.send(data)
|
|
468
|
+
|
|
306
469
|
|
|
307
470
|
async def start_logger(self):
|
|
308
471
|
self.colonel_logger = logging.getLogger(
|
simo/fleet/utils.py
CHANGED
|
@@ -51,26 +51,19 @@ BASE_ESP32_GPIO_PINS = {
|
|
|
51
51
|
39: {'output': False, 'adc': True},
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
GPIO_PINS = {'generic': {}, '
|
|
54
|
+
GPIO_PINS = {'generic': {}, '4-relays': {}, 'ample-wall': {}, 'game-changer': {}}
|
|
55
55
|
|
|
56
56
|
for no, data in BASE_ESP32_GPIO_PINS.items():
|
|
57
57
|
GPIO_PINS['generic'][no] = GPIO_PIN_DEFAULTS.copy()
|
|
58
58
|
|
|
59
|
-
#
|
|
59
|
+
# ample-wall
|
|
60
60
|
for no, data in BASE_ESP32_GPIO_PINS.items():
|
|
61
|
-
if no in (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if no == 2:
|
|
66
|
-
# onboard LED
|
|
67
|
-
continue
|
|
68
|
-
|
|
69
|
-
GPIO_PINS['wESP32'][no] = GPIO_PIN_DEFAULTS.copy()
|
|
70
|
-
GPIO_PINS['wESP32'][no].update(data)
|
|
61
|
+
if no in (4, 12, 13, 14, 15, 23, 32, 33, 34, 36, 39):
|
|
62
|
+
GPIO_PINS['ample-wall'][no] = GPIO_PIN_DEFAULTS.copy()
|
|
63
|
+
GPIO_PINS['ample-wall'][no].update(data)
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
GPIO_PINS['game-changer'][no] = GPIO_PIN_DEFAULTS.copy()
|
|
66
|
+
GPIO_PINS['game-changer'][no].update(data)
|
|
74
67
|
|
|
75
68
|
|
|
76
69
|
for no in range(101, 126):
|
|
@@ -87,6 +80,14 @@ for no in range(126, 133):
|
|
|
87
80
|
}
|
|
88
81
|
|
|
89
82
|
|
|
83
|
+
for no in range(101, 133):
|
|
84
|
+
GPIO_PINS['game-changer'][no] = {
|
|
85
|
+
'output': True, 'input': True, 'default_pull': 'LOW',
|
|
86
|
+
'native': False, 'adc': False,
|
|
87
|
+
'capacitive': False, 'note': ''
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
90
91
|
#4-relays
|
|
91
92
|
for no, data in BASE_ESP32_GPIO_PINS.items():
|
|
92
93
|
if no == 12:
|
|
@@ -113,42 +114,3 @@ for no, data in BASE_ESP32_GPIO_PINS.items():
|
|
|
113
114
|
GPIO_PINS['4-relays'][no]['note'] = 'Relay4'
|
|
114
115
|
else:
|
|
115
116
|
GPIO_PINS['4-relays'][no].update(data)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def get_available_gpio_pins(colonel=None, filters=None, selected=None):
|
|
119
|
-
if not colonel:
|
|
120
|
-
return {no: GPIO_PIN_DEFAULTS for no in range(200)}
|
|
121
|
-
if not filters:
|
|
122
|
-
filters = {}
|
|
123
|
-
pins = {}
|
|
124
|
-
allow_occupied = filters.pop('allow_occupied', None)
|
|
125
|
-
for key, data in GPIO_PINS.get(colonel.type, {}).items():
|
|
126
|
-
if str(key) in colonel.occupied_pins and not allow_occupied:
|
|
127
|
-
if selected:
|
|
128
|
-
if int(key) != int(selected):
|
|
129
|
-
continue
|
|
130
|
-
else:
|
|
131
|
-
continue
|
|
132
|
-
skip = False
|
|
133
|
-
for filter_param, filter_val in filters.items():
|
|
134
|
-
if data[filter_param] != filter_val:
|
|
135
|
-
skip = True
|
|
136
|
-
if skip:
|
|
137
|
-
continue
|
|
138
|
-
pins[key] = data
|
|
139
|
-
return pins
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def get_gpio_pins_choices(colonel=None, filters=None, selected=None):
|
|
143
|
-
choices = []
|
|
144
|
-
for key, data in get_available_gpio_pins(
|
|
145
|
-
colonel, filters, selected
|
|
146
|
-
).items():
|
|
147
|
-
if key < 100:
|
|
148
|
-
name = 'GPIO%d' % key
|
|
149
|
-
else:
|
|
150
|
-
name = 'E-%d' % (key - 100)
|
|
151
|
-
if data.get('note'):
|
|
152
|
-
name += ' | %s' % data['note']
|
|
153
|
-
choices.append((key, name))
|
|
154
|
-
return choices
|
simo/fleet/views.py
CHANGED
|
@@ -1,32 +1,46 @@
|
|
|
1
|
-
import
|
|
2
|
-
from django.http import
|
|
3
|
-
from django.
|
|
1
|
+
from django.contrib.contenttypes.models import ContentType
|
|
2
|
+
from django.http import HttpResponse, Http404
|
|
3
|
+
from django.db.models import Q
|
|
4
4
|
from dal import autocomplete
|
|
5
|
-
from .
|
|
6
|
-
from .
|
|
5
|
+
from simo.core.utils.helpers import search_queryset
|
|
6
|
+
from .models import Colonel, ColonelPin, I2CInterface
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def colonels_ping(request):
|
|
10
10
|
return HttpResponse('pong')
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class PinsSelectAutocomplete(autocomplete.
|
|
13
|
+
class PinsSelectAutocomplete(autocomplete.Select2QuerySetView):
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def get_queryset(self):
|
|
16
16
|
if not self.request.user.is_staff:
|
|
17
|
-
return
|
|
17
|
+
return ColonelPin.objects.none()
|
|
18
18
|
|
|
19
19
|
try:
|
|
20
|
-
|
|
20
|
+
colonel = Colonel.objects.get(
|
|
21
21
|
pk=self.forwarded.get("colonel")
|
|
22
22
|
)
|
|
23
23
|
except:
|
|
24
|
-
return
|
|
24
|
+
return ColonelPin.objects.none()
|
|
25
|
+
|
|
26
|
+
qs = ColonelPin.objects.filter(colonel=colonel)
|
|
27
|
+
|
|
28
|
+
if self.forwarded.get('self'):
|
|
29
|
+
qs = qs.filter(
|
|
30
|
+
Q(occupied_by_id=None) | Q(
|
|
31
|
+
id=int(self.forwarded['self'])
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
else:
|
|
35
|
+
qs = qs.filter(occupied_by_id=None)
|
|
36
|
+
|
|
37
|
+
if self.forwarded.get('filters'):
|
|
38
|
+
qs = qs.filter(**self.forwarded.get('filters'))
|
|
39
|
+
|
|
40
|
+
if self.q:
|
|
41
|
+
qs = search_queryset(qs, self.q, ('label', ))
|
|
25
42
|
|
|
26
|
-
return
|
|
27
|
-
esp_device, self.forwarded.get('filters'),
|
|
28
|
-
self.forwarded.get('self')
|
|
29
|
-
)
|
|
43
|
+
return qs
|
|
30
44
|
|
|
31
45
|
|
|
32
46
|
class I2CInterfaceSelectAutocomplete(autocomplete.Select2ListView):
|