simo 2.10.7__py3-none-any.whl → 2.10.9__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__/__init__.cpython-312.pyc +0 -0
- simo/__pycache__/asgi.cpython-312.pyc +0 -0
- simo/__pycache__/celeryc.cpython-312.pyc +0 -0
- simo/__pycache__/conf.cpython-312.pyc +0 -0
- simo/__pycache__/settings.cpython-312.pyc +0 -0
- simo/__pycache__/urls.cpython-312.pyc +0 -0
- simo/automation/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/automation/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/automation/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/forms.cpython-312.pyc +0 -0
- simo/automation/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/automation/__pycache__/helpers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/models.cpython-312.pyc +0 -0
- simo/automation/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/automation/__pycache__/state.cpython-312.pyc +0 -0
- simo/automation/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/automation/migrations/__pycache__/0002_update_helpers_in_scripts.cpython-312.pyc +0 -0
- simo/automation/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/automation/templates/automations/__pycache__/auto_away.cpython-312.pyc +0 -0
- simo/automation/templates/automations/__pycache__/auto_state_script.cpython-312.pyc +0 -0
- simo/automation/templates/automations/__pycache__/phones_sleep_script.cpython-312.pyc +0 -0
- simo/backups/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/backups/__pycache__/admin.cpython-312.pyc +0 -0
- simo/backups/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/backups/__pycache__/models.cpython-312.pyc +0 -0
- simo/backups/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0002_backuplog_backup_level_backup_size.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0003_alter_backuplog_options_alter_backup_size.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/0004_alter_backup_options_alter_backuplog_options_and_more.cpython-312.pyc +0 -0
- simo/backups/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/__pycache__/admin.cpython-312.pyc +0 -0
- simo/core/__pycache__/api.cpython-312.pyc +0 -0
- simo/core/__pycache__/api_auth.cpython-312.pyc +0 -0
- simo/core/__pycache__/api_meta.cpython-312.pyc +0 -0
- simo/core/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/core/__pycache__/apps.cpython-312.pyc +0 -0
- simo/core/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/core/__pycache__/autocomplete_views.cpython-312.pyc +0 -0
- simo/core/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/core/__pycache__/context.cpython-312.pyc +0 -0
- simo/core/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/core/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/core/__pycache__/events.cpython-312.pyc +0 -0
- simo/core/__pycache__/filters.cpython-312.pyc +0 -0
- simo/core/__pycache__/form_fields.cpython-312.pyc +0 -0
- simo/core/__pycache__/forms.cpython-312.pyc +0 -0
- simo/core/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/core/__pycache__/loggers.cpython-312.pyc +0 -0
- simo/core/__pycache__/managers.cpython-312.pyc +0 -0
- simo/core/__pycache__/middleware.cpython-312.pyc +0 -0
- simo/core/__pycache__/models.cpython-312.pyc +0 -0
- simo/core/__pycache__/permissions.cpython-312.pyc +0 -0
- simo/core/__pycache__/routing.cpython-312.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/core/__pycache__/signal_receivers.cpython-312.pyc +0 -0
- simo/core/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/core/__pycache__/storage.cpython-312.pyc +0 -0
- simo/core/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/core/__pycache__/todos.cpython-312.pyc +0 -0
- simo/core/__pycache__/types.cpython-312.pyc +0 -0
- simo/core/__pycache__/views.cpython-312.pyc +0 -0
- simo/core/__pycache__/widgets.cpython-312.pyc +0 -0
- simo/core/controllers.py +2 -2
- simo/core/db_backend/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/db_backend/__pycache__/base.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/mixins.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/models.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/parsers.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/renderers.cpython-312.pyc +0 -0
- simo/core/drf_braces/__pycache__/utils.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/_fields.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/custom.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/mixins.cpython-312.pyc +0 -0
- simo/core/drf_braces/fields/__pycache__/modified.cpython-312.pyc +0 -0
- simo/core/drf_braces/forms/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/forms/__pycache__/fields.cpython-312.pyc +0 -0
- simo/core/drf_braces/forms/__pycache__/serializer_form.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/enforce_validation_serializer.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/form_serializer.cpython-312.pyc +0 -0
- simo/core/drf_braces/serializers/__pycache__/swapping.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/__pycache__/test_mixins.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/__pycache__/test_parsers.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/__pycache__/test_renderers.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/__pycache__/test_utils.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/fields/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/fields/__pycache__/test_custom.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/fields/__pycache__/test_fields.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/fields/__pycache__/test_mixins.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/fields/__pycache__/test_modified.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/forms/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/forms/__pycache__/test_fields.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/forms/__pycache__/test_serializer_form.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/serializers/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/serializers/__pycache__/test_enforce_validation_serializer.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/serializers/__pycache__/test_form_serializer.cpython-312.pyc +0 -0
- simo/core/drf_braces/tests/serializers/__pycache__/test_swapping.cpython-312.pyc +0 -0
- simo/core/management/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/management/__pycache__/update.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/asgi.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/celeryc.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/manage.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/settings.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/urls.cpython-312.pyc +0 -0
- simo/core/management/_hub_template/hub/__pycache__/wsgi.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/gateways_manager.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/on_http_start.cpython-312.pyc +0 -0
- simo/core/management/commands/__pycache__/run_gateway.cpython-312.pyc +0 -0
- simo/core/migrations/0050_componenthistory_alive.py +18 -0
- simo/core/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0002_load_icons.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0003_create_default_zones_and_categories.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0004_create_generic.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0005_component_subcomponents.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0006_alter_component_subcomponents.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0007_component_change_init_to.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0008_alter_component_change_init_to.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0009_auto_20220707_1404.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0010_historyaggregate.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0011_component_last_change.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0012_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0013_auto_20231003_0754.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0014_zone_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0015_auto_20231004_1113.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0016_auto_20231004_1113.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0017_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0018_auto_20231005_0622.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0019_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0020_component_meta.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0022_auto_20231221_0735.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0023_auto_20231229_1352.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0024_alter_instance_device_report_history_days.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0025_auto_20240122_1321.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0026_category_instance.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0031_auto_20240429_1231.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0032_auto_20240506_0834.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0033_auto_20240509_0821.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0034_component_error_msg.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0035_remove_instance_share_location.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0036_auto_20240521_0823.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0037_auto_20240606_1057.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0038_remove_instance_cover_image_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0039_instance_is_active_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0040_alter_instance_name.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0041_alter_instance_slug.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0042_alter_instance_timezone.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0043_alter_category_instance_alter_instance_timezone_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0044_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0045_alter_instance_device_report_history_days_and_more.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0046_component_value_translation_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0047_alter_component_value_translation.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0048_publicfile_privatefile.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0049_alter_gateway_type.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/0050_componenthistory_alive.cpython-312.pyc +0 -0
- simo/core/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/models.py +3 -1
- simo/core/serializers.py +2 -2
- simo/core/tasks.py +0 -1
- simo/core/templates/admin/component_history.html +18 -2
- simo/core/templates/core/__pycache__/value_translation.cpython-312.pyc +0 -0
- simo/core/templatetags/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/templatetags/__pycache__/components_list.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/admin.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/api.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/cache.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/config_values.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/converters.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/easing.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/form_fields.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/form_widgets.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/formsets.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/helpers.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/json.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/logs.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/mixins.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/model_helpers.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/operations.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/relay.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/serialization.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/type_constants.cpython-312.pyc +0 -0
- simo/core/utils/__pycache__/validators.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/admin.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/api.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/apps.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/ble.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/custom_dali_operations.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/forms.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/managers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/models.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/routing.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/utils.cpython-312.pyc +0 -0
- simo/fleet/__pycache__/views.cpython-312.pyc +0 -0
- simo/fleet/api.py +5 -2
- simo/fleet/controllers.py +98 -14
- simo/fleet/forms.py +67 -107
- simo/fleet/gateways.py +34 -4
- simo/fleet/migrations/0052_colonelpin_interface.py +18 -0
- simo/fleet/migrations/0053_auto_20250507_0713.py +24 -0
- simo/fleet/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0002_auto_20220422_0743.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0003_auto_20220422_0752.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0004_auto_20220422_0818.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0005_auto_20220428_0900.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0006_rename_mac_colonel_uid.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0007_colonel_socket_connected.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0008_i2cinterface.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0009_i2cinterface_name.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0010_auto_20220602_0746.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0011_i2cinterface_freq.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0012_colonel_logs_stream.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0013_alter_colonel_last_seen.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0014_auto_20220614_0659.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0015_auto_20220614_0754.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0016_auto_20220704_0840.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0017_alter_colonel_secret.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0018_colonel_instance.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0019_auto_20231006_0749.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0020_instanceoptions.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0021_auto_20231006_0819.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0022_remove_colonel_secret.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0023_colonel_is_authorized.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0024_colonel_pwm_frequency.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0025_auto_20240130_1334.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0026_rename_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0027_auto_20240306_0802.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0034_auto_20240418_0735.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0035_auto_20240514_0855.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0036_auto_20240605_0702.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0038_alter_colonel_type.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0039_auto_20241016_1047.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0040_alter_colonel_pwm_frequency.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0041_alter_colonel_instance_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0042_auto_20241120_1028.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0043_auto_20241203_0930.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0044_auto_20241210_0707.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0045_alter_colonel_type_customdalidevice.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0046_delete_customdalidevice.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0047_customdalidevice.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0048_remove_customdalidevice_colonel_and_more.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0049_alter_customdalidevice_interface.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0050_customdalidevice_uid.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0051_customdalidevice_components.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0052_colonelpin_interface.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/0053_auto_20250507_0713.cpython-312.pyc +0 -0
- simo/fleet/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/fleet/models.py +96 -34
- simo/fleet/serializers.py +2 -2
- simo/fleet/utils.py +126 -0
- simo/generic/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/generic/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/generic/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/generic/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/generic/__pycache__/forms.cpython-312.pyc +0 -0
- simo/generic/__pycache__/gateways.cpython-312.pyc +0 -0
- simo/generic/__pycache__/models.cpython-312.pyc +0 -0
- simo/generic/__pycache__/routing.cpython-312.pyc +0 -0
- simo/generic/__pycache__/socket_consumers.cpython-312.pyc +0 -0
- simo/generic/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/0002_auto_20241126_0726.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/0003_auto_20250409_1404.cpython-312.pyc +0 -0
- simo/generic/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/admin.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/api.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/app_widgets.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/base_types.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/controllers.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/forms.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/models.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/multimedia/__pycache__/views.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0002_sound_length.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0005_remove_sound_slug_sound_date_uploaded.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/0006_remove_sound_length_sound_duration.cpython-312.pyc +0 -0
- simo/multimedia/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/admin.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/api.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/models.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/notifications/__pycache__/utils.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/0003_alter_notification_instance.cpython-312.pyc +0 -0
- simo/notifications/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/notifications/serializers.py +1 -1
- simo/users/__pycache__/__init__.cpython-312.pyc +0 -0
- simo/users/__pycache__/admin.cpython-312.pyc +0 -0
- simo/users/__pycache__/api.cpython-312.pyc +0 -0
- simo/users/__pycache__/apps.cpython-312.pyc +0 -0
- simo/users/__pycache__/auth_backends.cpython-312.pyc +0 -0
- simo/users/__pycache__/auto_urls.cpython-312.pyc +0 -0
- simo/users/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
- simo/users/__pycache__/managers.cpython-312.pyc +0 -0
- simo/users/__pycache__/middleware.cpython-312.pyc +0 -0
- simo/users/__pycache__/models.cpython-312.pyc +0 -0
- simo/users/__pycache__/permissions.cpython-312.pyc +0 -0
- simo/users/__pycache__/serializers.cpython-312.pyc +0 -0
- simo/users/__pycache__/sso_urls.cpython-312.pyc +0 -0
- simo/users/__pycache__/sso_views.cpython-312.pyc +0 -0
- simo/users/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/users/__pycache__/utils.cpython-312.pyc +0 -0
- simo/users/__pycache__/views.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0002_componentpermission.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0003_create_roles_and_system_user.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0004_user_secret_key.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0005_permissionsrole_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0006_auto_20231003_0850.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0007_auto_20231003_1228.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0008_auto_20231003_1229.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0009_remove_user_role.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0010_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0011_auto_20231004_1313.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0012_alter_userinstancerole_unique_together.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0013_remove_user_roles.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0014_user_roles.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0015_remove_user_at_home.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0016_auto_20231005_1050.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0017_auto_20231221_0735.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0018_user_is_god.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0019_auto_20231221_1155.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0020_rename_is_god_user_is_master.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0021_alter_permissionsrole_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0022_userdevicereportlog_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0023_auto_20240105_0719.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0024_fingerprint.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0025_rename_name_fingerprint_type_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0026_fingerprint_name.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0027_permissionsrole_can_manage_components.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0028_auto_20240506_1146.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0029_alter_instanceuser_instance.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0030_userdevice_users.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0031_auto_20240923_1115.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0032_remove_userdevice_user_alter_userdevice_users.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0033_alter_user_ssh_key.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0034_instanceuser_last_seen_location_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0035_instanceuser_last_seen_speed_kmh_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0036_instanceuser_phone_on_charge_user_phone_on_charge.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0037_rename_last_seen_location_datetime_instanceuser_last_seen_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0038_userdevicereportlog_at_home_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0040_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0041_userdevicereportlog_speed_kmh_received.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0042_remove_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0043_userdevicereportlog_avg_speed_kmh.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/0044_permissionsrole_is_person.cpython-312.pyc +0 -0
- simo/users/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/METADATA +1 -1
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/RECORD +386 -338
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/WHEEL +1 -1
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/entry_points.txt +0 -0
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/licenses/LICENSE.md +0 -0
- {simo-2.10.7.dist-info → simo-2.10.9.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/fleet/api.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from django.db.models import Count
|
|
2
3
|
from django.utils.translation import gettext_lazy as _
|
|
3
4
|
from rest_framework import viewsets
|
|
@@ -66,12 +67,14 @@ class ColonelsViewSet(InstanceMixin, viewsets.ModelViewSet):
|
|
|
66
67
|
@action(detail=True, methods=['post'])
|
|
67
68
|
def move_to(self, request, pk, *args, **kwargs):
|
|
68
69
|
colonel = self.get_object()
|
|
70
|
+
data = json.loads(request.body)
|
|
71
|
+
|
|
69
72
|
target = Colonel.objects.annotate(
|
|
70
73
|
components_count=Count('components')
|
|
71
74
|
).filter(
|
|
72
|
-
pk=
|
|
75
|
+
pk=data.get('target'), instance=self.instance,
|
|
73
76
|
components_count=0, type=colonel.type
|
|
74
|
-
)
|
|
77
|
+
).first()
|
|
75
78
|
if not target:
|
|
76
79
|
raise APIValidationError(_('Invalid target.'), code=400)
|
|
77
80
|
colonel.move_to(target)
|
simo/fleet/controllers.py
CHANGED
|
@@ -164,6 +164,11 @@ class BME680Sensor(DHTSensor):
|
|
|
164
164
|
config_form = BME680SensorConfigForm
|
|
165
165
|
name = "BME68X Climate Sensor (I2C)"
|
|
166
166
|
|
|
167
|
+
def _get_occupied_pins(self):
|
|
168
|
+
return [
|
|
169
|
+
self.component.config['i2c_interface'] + 100,
|
|
170
|
+
]
|
|
171
|
+
|
|
167
172
|
|
|
168
173
|
|
|
169
174
|
class MCP9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
|
|
@@ -180,6 +185,11 @@ class MCP9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
|
|
|
180
185
|
return 'F'
|
|
181
186
|
return 'C'
|
|
182
187
|
|
|
188
|
+
def _get_occupied_pins(self):
|
|
189
|
+
return [
|
|
190
|
+
self.component.config['i2c_interface'] + 100,
|
|
191
|
+
]
|
|
192
|
+
|
|
183
193
|
def _prepare_for_set(self, value):
|
|
184
194
|
if self.component.zone.instance.units_of_measure == 'imperial':
|
|
185
195
|
return round((value[0][1] * 9 / 5) + 32, 1)
|
|
@@ -198,6 +208,11 @@ class ENS160AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
|
|
|
198
208
|
["AQI (UBA)", 0, ""]
|
|
199
209
|
]
|
|
200
210
|
|
|
211
|
+
def _get_occupied_pins(self):
|
|
212
|
+
return [
|
|
213
|
+
self.component.config['i2c_interface'] + 100,
|
|
214
|
+
]
|
|
215
|
+
|
|
201
216
|
def get_co2(self):
|
|
202
217
|
try:
|
|
203
218
|
for entry in self.component.value:
|
|
@@ -855,13 +870,13 @@ class AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
|
|
|
855
870
|
|
|
856
871
|
def _receive_from_device(self, value, *args, **kwargs):
|
|
857
872
|
aqi = 5
|
|
858
|
-
if value <
|
|
873
|
+
if value < 2000:
|
|
859
874
|
aqi = 4
|
|
860
|
-
if value <
|
|
875
|
+
if value < 800:
|
|
861
876
|
aqi = 3
|
|
862
|
-
if value <
|
|
877
|
+
if value < 400:
|
|
863
878
|
aqi = 2
|
|
864
|
-
if value <
|
|
879
|
+
if value < 200:
|
|
865
880
|
aqi = 1
|
|
866
881
|
value = [
|
|
867
882
|
["TVOC", value, "ppb"],
|
|
@@ -968,10 +983,14 @@ class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
|
|
|
968
983
|
config_form = BaseComponentForm
|
|
969
984
|
name = "Room zone presence"
|
|
970
985
|
discovery_msg = _(
|
|
971
|
-
"
|
|
972
|
-
"
|
|
973
|
-
"
|
|
974
|
-
"
|
|
986
|
+
"Your body is a a live space marker now! Your movements are being recorded.<br>"
|
|
987
|
+
"Whenever you hear a beep, new space blob is being included.<br>"
|
|
988
|
+
"Move vigorously in the zone where you want presence to be detected until "
|
|
989
|
+
"you hear no more beeps.<br> "
|
|
990
|
+
"Green color of a sensor indicates, "
|
|
991
|
+
"that the space you are currently in is "
|
|
992
|
+
"already included.<br>"
|
|
993
|
+
"Tip: Dance! :)"
|
|
975
994
|
)
|
|
976
995
|
|
|
977
996
|
@classmethod
|
|
@@ -991,10 +1010,10 @@ class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
|
|
|
991
1010
|
command='discover', type=self.uid.split('.')[-1],
|
|
992
1011
|
).publish()
|
|
993
1012
|
else:
|
|
1013
|
+
from .custom_dali_operations import Frame
|
|
994
1014
|
dali_device = CustomDaliDevice.objects.filter(
|
|
995
1015
|
id=form_cleaned_data['device'][5:]
|
|
996
1016
|
).first()
|
|
997
|
-
from .custom_dali_operations import Frame
|
|
998
1017
|
frame = Frame(40, bytes(bytearray(5)))
|
|
999
1018
|
frame[8:11] = 15 # command to custom dali device
|
|
1000
1019
|
frame[12:15] = 0 # action to perform: start room zone discovery
|
|
@@ -1008,6 +1027,11 @@ class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
|
|
|
1008
1027
|
form = cls.add_form(
|
|
1009
1028
|
controller_uid=cls.uid, data=started_with
|
|
1010
1029
|
)
|
|
1030
|
+
from simo.core.middleware import introduce_instance
|
|
1031
|
+
introduce_instance(form.data['zone'].instance)
|
|
1032
|
+
form = cls.add_form(
|
|
1033
|
+
controller_uid=cls.uid, data=started_with
|
|
1034
|
+
)
|
|
1011
1035
|
form.is_valid()
|
|
1012
1036
|
if form.cleaned_data['device'].startswith('wifi'):
|
|
1013
1037
|
form.instance.alive = False
|
|
@@ -1020,15 +1044,17 @@ class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
|
|
|
1020
1044
|
id=new_component.config['colonel']
|
|
1021
1045
|
), command='finalize',
|
|
1022
1046
|
data={
|
|
1047
|
+
'permanent_id': new_component.id,
|
|
1023
1048
|
'comp_config': {
|
|
1024
|
-
'type':
|
|
1049
|
+
'type': cls.uid.split('.')[-1],
|
|
1025
1050
|
'family': new_component.controller.family,
|
|
1026
|
-
'config': json.loads(json.dumps(new_component.config))
|
|
1051
|
+
'config': json.loads(json.dumps(new_component.config)),
|
|
1027
1052
|
}
|
|
1028
1053
|
}
|
|
1029
1054
|
).publish()
|
|
1030
1055
|
else:
|
|
1031
1056
|
from simo.core.models import Component
|
|
1057
|
+
from .custom_dali_operations import Frame
|
|
1032
1058
|
dali_device = CustomDaliDevice.objects.filter(
|
|
1033
1059
|
id=form.cleaned_data['device'][5:]
|
|
1034
1060
|
).first()
|
|
@@ -1049,12 +1075,70 @@ class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
|
|
|
1049
1075
|
)
|
|
1050
1076
|
form.instance.config['slot'] = free_slots.pop()
|
|
1051
1077
|
new_component = form.save()
|
|
1052
|
-
from .custom_dali_operations import Frame
|
|
1053
1078
|
frame = Frame(40, bytes(bytearray(5)))
|
|
1054
1079
|
frame[8:11] = 15 # command to custom dali device
|
|
1055
1080
|
frame[12:15] = 1 # action to perform: stop room zone discovery
|
|
1056
1081
|
frame[16:18] = new_component.config['slot']
|
|
1057
1082
|
dali_device.transmit(frame)
|
|
1058
1083
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1084
|
+
return new_component
|
|
1085
|
+
|
|
1086
|
+
def repaint(self):
|
|
1087
|
+
"""Repaint included 3D space"""
|
|
1088
|
+
if self.component.config['device'].startswith('wifi'):
|
|
1089
|
+
GatewayObjectCommand(
|
|
1090
|
+
self.component.gateway, Colonel(
|
|
1091
|
+
id=self.component.config['colonel']
|
|
1092
|
+
), command='call', method='repaint', id=self.component.id
|
|
1093
|
+
).publish()
|
|
1094
|
+
else:
|
|
1095
|
+
dali_device = CustomDaliDevice.objects.filter(
|
|
1096
|
+
id=self.component.config['device'][5:]
|
|
1097
|
+
).first()
|
|
1098
|
+
from .custom_dali_operations import Frame
|
|
1099
|
+
frame = Frame(40, bytes(bytearray(5)))
|
|
1100
|
+
frame[8:11] = 15 # command to custom dali device
|
|
1101
|
+
frame[12:15] = 3 # action to perform: repaint
|
|
1102
|
+
frame[16:18] = self.component.config['slot']
|
|
1103
|
+
dali_device.transmit(frame)
|
|
1104
|
+
|
|
1105
|
+
def finish_repaint(self):
|
|
1106
|
+
"""Finish repainting of 3D space"""
|
|
1107
|
+
if self.component.config['device'].startswith('wifi'):
|
|
1108
|
+
GatewayObjectCommand(
|
|
1109
|
+
self.component.gateway, Colonel(
|
|
1110
|
+
id=self.component.config['colonel']
|
|
1111
|
+
), command='call', method='finish_repaint',
|
|
1112
|
+
id=self.component.id
|
|
1113
|
+
).publish()
|
|
1114
|
+
else:
|
|
1115
|
+
dali_device = CustomDaliDevice.objects.filter(
|
|
1116
|
+
id=self.component.config['device'][5:]
|
|
1117
|
+
).first()
|
|
1118
|
+
from .custom_dali_operations import Frame
|
|
1119
|
+
frame = Frame(40, bytes(bytearray(5)))
|
|
1120
|
+
frame[8:11] = 15 # command to custom dali device
|
|
1121
|
+
frame[12:15] = 4 # action to perform: finish repaint
|
|
1122
|
+
frame[16:18] = self.component.config['slot']
|
|
1123
|
+
dali_device.transmit(frame)
|
|
1124
|
+
|
|
1125
|
+
def cancel_repaint(self):
|
|
1126
|
+
"""Finish repainting of 3D space"""
|
|
1127
|
+
if self.component.config['device'].startswith('wifi'):
|
|
1128
|
+
GatewayObjectCommand(
|
|
1129
|
+
self.component.gateway, Colonel(
|
|
1130
|
+
id=self.component.config['colonel']
|
|
1131
|
+
), command='call', method='cancel_repaint',
|
|
1132
|
+
id=self.component.id
|
|
1133
|
+
).publish()
|
|
1134
|
+
else:
|
|
1135
|
+
dali_device = CustomDaliDevice.objects.filter(
|
|
1136
|
+
id=self.component.config['device'][5:]
|
|
1137
|
+
).first()
|
|
1138
|
+
from .custom_dali_operations import Frame
|
|
1139
|
+
frame = Frame(40, bytes(bytearray(5)))
|
|
1140
|
+
frame[8:11] = 15 # command to custom dali device
|
|
1141
|
+
frame[12:15] = 5 # action to perform: cancel repaint
|
|
1142
|
+
frame[16:18] = self.component.config['slot']
|
|
1143
|
+
dali_device.transmit(frame)
|
|
1144
|
+
|
simo/fleet/forms.py
CHANGED
|
@@ -460,65 +460,86 @@ class ColonelDHTSensorConfigForm(ColonelComponentForm):
|
|
|
460
460
|
return super().save(commit=commit)
|
|
461
461
|
|
|
462
462
|
|
|
463
|
-
class
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
463
|
+
class I2CDevice(ColonelComponentForm):
|
|
464
|
+
interface_port = Select2ModelChoiceField(
|
|
465
|
+
label="Interface",
|
|
466
|
+
queryset=ColonelPin.objects.filter(interface__isnull=False),
|
|
467
|
+
url='autocomplete-colonel-pins',
|
|
467
468
|
forward=[
|
|
468
469
|
forward.Self(),
|
|
469
470
|
forward.Field('colonel'),
|
|
470
|
-
forward.Const(
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
]
|
|
474
|
-
)
|
|
475
|
-
i2c_address = forms.TypedChoiceField(
|
|
476
|
-
coerce=int, initial=118,
|
|
477
|
-
choices=((118, "0x76"), (119, "0x77")),
|
|
478
|
-
)
|
|
479
|
-
read_frequency_s = forms.IntegerField(
|
|
480
|
-
initial=60, min_value=1, max_value=60*60*24,
|
|
481
|
-
help_text='read and report climate value every s. '
|
|
482
|
-
'Can not be less than 1s.'
|
|
483
|
-
|
|
471
|
+
forward.Const({'interface__isnull': False}, 'filters'),
|
|
472
|
+
],
|
|
484
473
|
)
|
|
485
474
|
|
|
486
475
|
def clean(self):
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
476
|
+
cleaned_data = super().clean()
|
|
477
|
+
colonel = cleaned_data.get('colonel')
|
|
478
|
+
port_choice = cleaned_data.get('interface_port')
|
|
479
|
+
if not colonel or not port_choice:
|
|
480
|
+
return cleaned_data
|
|
481
|
+
|
|
482
|
+
# Create or fetch the I²C interface
|
|
483
|
+
interface, created = Interface.objects.get_or_create(
|
|
484
|
+
colonel=colonel,
|
|
485
|
+
no=port_choice.interface,
|
|
486
|
+
defaults={'type': 'i2c'},
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
# If it already existed as something else, ensure it's free
|
|
490
|
+
if interface.type != 'i2c':
|
|
491
|
+
occupied = interface.addresses.filter(occupied_by__isnull=False).first()
|
|
492
|
+
if occupied:
|
|
493
|
+
self.add_error(
|
|
494
|
+
'interface_port',
|
|
495
|
+
f"Port already occupied by {occupied.occupied_by}"
|
|
496
|
+
)
|
|
497
|
+
return cleaned_data
|
|
498
|
+
interface.type = 'i2c'
|
|
499
|
+
interface.save()
|
|
500
|
+
|
|
501
|
+
# Check for address collisions on that interface
|
|
502
|
+
other = Component.objects.filter(
|
|
503
|
+
config__colonel=colonel.id,
|
|
504
|
+
config__interface=interface.id,
|
|
505
|
+
config__i2c_address=cleaned_data['i2c_address'],
|
|
506
|
+
).exclude(id=self.instance.id).first()
|
|
507
|
+
if other:
|
|
490
508
|
self.add_error(
|
|
491
|
-
'
|
|
492
|
-
f"
|
|
493
|
-
f"however we need an interface from {self.cleaned_data['colonel']}."
|
|
509
|
+
'i2c_address',
|
|
510
|
+
f"Address already occupied by {other}"
|
|
494
511
|
)
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
).exclude(id=self.instance.id).first()
|
|
500
|
-
if other_comp:
|
|
501
|
-
self.add_error('i2c_address', f'Already occupied by {other_comp}!')
|
|
502
|
-
return self.cleaned_data
|
|
512
|
+
|
|
513
|
+
# stash for save()
|
|
514
|
+
cleaned_data['i2c_interface'] = interface.id
|
|
515
|
+
return cleaned_data
|
|
503
516
|
|
|
504
517
|
def save(self, commit=True):
|
|
505
|
-
|
|
506
|
-
self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
|
|
518
|
+
self.instance.config['i2c_interface'] = self.cleaned_data['i2c_interface']
|
|
507
519
|
return super().save(commit=commit)
|
|
508
520
|
|
|
509
521
|
|
|
510
|
-
class
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
{'type': 'i2c'}, 'filters'
|
|
519
|
-
)
|
|
520
|
-
]
|
|
522
|
+
class BME680SensorConfigForm(I2CDevice):
|
|
523
|
+
i2c_address = forms.TypedChoiceField(
|
|
524
|
+
coerce=int,
|
|
525
|
+
initial=119, # match “0x77 – default”
|
|
526
|
+
choices=(
|
|
527
|
+
(119, "0x77 – default"),
|
|
528
|
+
(118, "0x76 – soldered"),
|
|
529
|
+
),
|
|
521
530
|
)
|
|
531
|
+
read_frequency_s = forms.IntegerField(
|
|
532
|
+
initial=60,
|
|
533
|
+
min_value=1,
|
|
534
|
+
max_value=60 * 60 * 24,
|
|
535
|
+
help_text=(
|
|
536
|
+
"Read and report climate value every second. "
|
|
537
|
+
"Cannot be less than 1 second."
|
|
538
|
+
),
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
class MCP9808SensorConfigForm(I2CDevice):
|
|
522
543
|
i2c_address = forms.TypedChoiceField(
|
|
523
544
|
coerce=int, initial=24,
|
|
524
545
|
choices=(
|
|
@@ -535,43 +556,8 @@ class MCP9808SensorConfigForm(ColonelComponentForm):
|
|
|
535
556
|
|
|
536
557
|
)
|
|
537
558
|
|
|
538
|
-
def clean(self):
|
|
539
|
-
if not self.cleaned_data.get('colonel'):
|
|
540
|
-
return self.cleaned_data
|
|
541
|
-
if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
|
|
542
|
-
self.add_error(
|
|
543
|
-
'interface',
|
|
544
|
-
f"This interface is on {self.cleaned_data['interface'].colonel}, "
|
|
545
|
-
f"however we need an interface from {self.cleaned_data['colonel']}."
|
|
546
|
-
)
|
|
547
|
-
|
|
548
|
-
other_comp = Component.objects.filter(
|
|
549
|
-
config__colonel=self.cleaned_data['colonel'].id,
|
|
550
|
-
config__interface=self.cleaned_data['interface'].id,
|
|
551
|
-
config__i2c_address=self.cleaned_data['i2c_address']
|
|
552
|
-
).exclude(id=self.instance.id).first()
|
|
553
|
-
if other_comp:
|
|
554
|
-
self.add_error('i2c_address', f'Already occupied by {other_comp}!')
|
|
555
|
-
return self.cleaned_data
|
|
556
|
-
|
|
557
|
-
def save(self, commit=True):
|
|
558
|
-
if 'interface' in self.cleaned_data:
|
|
559
|
-
self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
|
|
560
|
-
return super().save(commit=commit)
|
|
561
|
-
|
|
562
559
|
|
|
563
|
-
class ENS160SensorConfigForm(
|
|
564
|
-
interface = Select2ModelChoiceField(
|
|
565
|
-
queryset=Interface.objects.filter(type='i2c'),
|
|
566
|
-
url='autocomplete-interfaces',
|
|
567
|
-
forward=[
|
|
568
|
-
forward.Self(),
|
|
569
|
-
forward.Field('colonel'),
|
|
570
|
-
forward.Const(
|
|
571
|
-
{'type': 'i2c'}, 'filters'
|
|
572
|
-
)
|
|
573
|
-
]
|
|
574
|
-
)
|
|
560
|
+
class ENS160SensorConfigForm(I2CDevice):
|
|
575
561
|
i2c_address = forms.TypedChoiceField(
|
|
576
562
|
coerce=int, initial=83,
|
|
577
563
|
choices=((82, "0x52"), (83, "0x53")),
|
|
@@ -583,30 +569,6 @@ class ENS160SensorConfigForm(ColonelComponentForm):
|
|
|
583
569
|
|
|
584
570
|
)
|
|
585
571
|
|
|
586
|
-
def clean(self):
|
|
587
|
-
if not self.cleaned_data.get('colonel'):
|
|
588
|
-
return self.cleaned_data
|
|
589
|
-
if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
|
|
590
|
-
self.add_error(
|
|
591
|
-
'interface',
|
|
592
|
-
f"This interface is on {self.cleaned_data['interface'].colonel}, "
|
|
593
|
-
f"however we need an interface from {self.cleaned_data['colonel']}."
|
|
594
|
-
)
|
|
595
|
-
other_comp = Component.objects.filter(
|
|
596
|
-
config__colonel=self.cleaned_data['colonel'].id,
|
|
597
|
-
config__interface=self.cleaned_data['interface'].id,
|
|
598
|
-
config__i2c_address=self.cleaned_data['i2c_address']
|
|
599
|
-
).exclude(id=self.instance.id).first()
|
|
600
|
-
if other_comp:
|
|
601
|
-
self.add_error('i2c_address', f'Already occupied by {other_comp}!')
|
|
602
|
-
return self.cleaned_data
|
|
603
|
-
|
|
604
|
-
def save(self, commit=True):
|
|
605
|
-
if 'interface' in self.cleaned_data:
|
|
606
|
-
self.instance.config['i2c_interface'] = \
|
|
607
|
-
self.cleaned_data['interface'].no
|
|
608
|
-
return super().save(commit=commit)
|
|
609
|
-
|
|
610
572
|
|
|
611
573
|
class ColonelTouchSensorConfigForm(ColonelComponentForm):
|
|
612
574
|
pin = Select2ModelChoiceField(
|
|
@@ -1831,8 +1793,6 @@ class CustomDaliDeviceForm(BaseComponentForm):
|
|
|
1831
1793
|
for colonel in Colonel.objects.filter(
|
|
1832
1794
|
type='room-sensor', instance=instance
|
|
1833
1795
|
):
|
|
1834
|
-
if not colonel.is_connected:
|
|
1835
|
-
continue
|
|
1836
1796
|
choices.append((f"wifi-{colonel.id}", colonel.name))
|
|
1837
1797
|
for device in CustomDaliDevice.objects.filter(
|
|
1838
1798
|
instance=instance,
|
simo/fleet/gateways.py
CHANGED
|
@@ -11,6 +11,7 @@ from simo.core.utils.serialization import deserialize_form_data
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
15
16
|
name = "SIMO.io Fleet"
|
|
16
17
|
config_form = BaseGatewayForm
|
|
@@ -101,15 +102,19 @@ class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
101
102
|
gw.finish_discovery()
|
|
102
103
|
continue
|
|
103
104
|
|
|
104
|
-
colonel = Colonel.objects.get(
|
|
105
|
-
id=gw.discovery['init_data']['colonel']['val'][0]['pk']
|
|
106
|
-
)
|
|
107
105
|
if gw.discovery['controller_uid'] == 'simo.fleet.controllers.TTLock':
|
|
106
|
+
colonel = Colonel.objects.get(
|
|
107
|
+
id=gw.discovery['init_data']['colonel']['val'][0]['pk']
|
|
108
|
+
)
|
|
108
109
|
GatewayObjectCommand(
|
|
109
110
|
gw, colonel, command='discover',
|
|
110
111
|
type=gw.discovery['controller_uid']
|
|
111
112
|
).publish()
|
|
112
|
-
elif gw.discovery['controller_uid'] ==
|
|
113
|
+
elif gw.discovery['controller_uid'] == \
|
|
114
|
+
'simo.fleet.controllers.DALIDevice':
|
|
115
|
+
colonel = Colonel.objects.get(
|
|
116
|
+
id=gw.discovery['init_data']['colonel']['val'][0]['pk']
|
|
117
|
+
)
|
|
113
118
|
form_cleaned_data = deserialize_form_data(gw.discovery['init_data'])
|
|
114
119
|
GatewayObjectCommand(
|
|
115
120
|
gw, colonel,
|
|
@@ -117,6 +122,31 @@ class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
117
122
|
type=gw.discovery['controller_uid'],
|
|
118
123
|
i=form_cleaned_data['interface'].no
|
|
119
124
|
).publish()
|
|
125
|
+
elif gw.discovery['controller_uid'] == \
|
|
126
|
+
'simo.fleet.controllers.RoomZonePresenceSensor':
|
|
127
|
+
form_cleaned_data = deserialize_form_data(
|
|
128
|
+
gw.discovery['init_data']
|
|
129
|
+
)
|
|
130
|
+
if form_cleaned_data['device'].startswith('wifi'):
|
|
131
|
+
colonel = Colonel.objects.filter(
|
|
132
|
+
id=form_cleaned_data['device'][5:]
|
|
133
|
+
).first()
|
|
134
|
+
GatewayObjectCommand(
|
|
135
|
+
gw, colonel,
|
|
136
|
+
command='discover', type=self.uid.split('.')[-1],
|
|
137
|
+
).publish()
|
|
138
|
+
else:
|
|
139
|
+
from .models import CustomDaliDevice
|
|
140
|
+
from .custom_dali_operations import Frame
|
|
141
|
+
dali_device = CustomDaliDevice.objects.filter(
|
|
142
|
+
id=form_cleaned_data['device'][5:]
|
|
143
|
+
).first()
|
|
144
|
+
frame = Frame(40, bytes(bytearray(5)))
|
|
145
|
+
frame[8:11] = 15 # command to custom dali device
|
|
146
|
+
frame[12:15] = 0 # action to perform: start room zone discovery
|
|
147
|
+
dali_device.transmit(frame)
|
|
148
|
+
|
|
149
|
+
|
|
120
150
|
|
|
121
151
|
def watch_buttons(self, component):
|
|
122
152
|
for i, ctrl in enumerate(component.config.get('controls', [])):
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 4.2.10 on 2025-05-07 07:13
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('fleet', '0051_customdalidevice_components'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='colonelpin',
|
|
15
|
+
name='interface',
|
|
16
|
+
field=models.PositiveIntegerField(blank=True, null=True),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated by Django 4.2.10 on 2025-05-07 07:13
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def forwards_func(apps, schema_editor):
|
|
7
|
+
ColonelPin = apps.get_model("fleet", "ColonelPin")
|
|
8
|
+
ColonelPin.objects.filter(no=101).update(interface=1)
|
|
9
|
+
ColonelPin.objects.filter(no=102).update(interface=2)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def reverse_func(apps, schema_editor):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Migration(migrations.Migration):
|
|
17
|
+
|
|
18
|
+
dependencies = [
|
|
19
|
+
('fleet', '0052_colonelpin_interface'),
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
operations = [
|
|
23
|
+
migrations.RunPython(forwards_func, reverse_func, elidable=True),
|
|
24
|
+
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|