simo 2.10.9__py3-none-any.whl → 2.11.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.

Files changed (379) hide show
  1. simo/__pycache__/__init__.cpython-312.pyc +0 -0
  2. simo/__pycache__/asgi.cpython-312.pyc +0 -0
  3. simo/__pycache__/celeryc.cpython-312.pyc +0 -0
  4. simo/__pycache__/conf.cpython-312.pyc +0 -0
  5. simo/__pycache__/settings.cpython-312.pyc +0 -0
  6. simo/__pycache__/urls.cpython-312.pyc +0 -0
  7. simo/automation/__pycache__/__init__.cpython-312.pyc +0 -0
  8. simo/automation/__pycache__/app_widgets.cpython-312.pyc +0 -0
  9. simo/automation/__pycache__/controllers.cpython-312.pyc +0 -0
  10. simo/automation/__pycache__/forms.cpython-312.pyc +0 -0
  11. simo/automation/__pycache__/gateways.cpython-312.pyc +0 -0
  12. simo/automation/__pycache__/helpers.cpython-312.pyc +0 -0
  13. simo/automation/__pycache__/models.cpython-312.pyc +0 -0
  14. simo/automation/__pycache__/serializers.cpython-312.pyc +0 -0
  15. simo/automation/__pycache__/state.cpython-312.pyc +0 -0
  16. simo/automation/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  17. simo/automation/migrations/__pycache__/0002_update_helpers_in_scripts.cpython-312.pyc +0 -0
  18. simo/automation/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  19. simo/automation/templates/automations/__pycache__/auto_away.cpython-312.pyc +0 -0
  20. simo/automation/templates/automations/__pycache__/auto_state_script.cpython-312.pyc +0 -0
  21. simo/automation/templates/automations/__pycache__/phones_sleep_script.cpython-312.pyc +0 -0
  22. simo/backups/__pycache__/__init__.cpython-312.pyc +0 -0
  23. simo/backups/__pycache__/admin.cpython-312.pyc +0 -0
  24. simo/backups/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
  25. simo/backups/__pycache__/models.cpython-312.pyc +0 -0
  26. simo/backups/__pycache__/tasks.cpython-312.pyc +0 -0
  27. simo/backups/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  28. simo/backups/migrations/__pycache__/0002_backuplog_backup_level_backup_size.cpython-312.pyc +0 -0
  29. simo/backups/migrations/__pycache__/0003_alter_backuplog_options_alter_backup_size.cpython-312.pyc +0 -0
  30. simo/backups/migrations/__pycache__/0004_alter_backup_options_alter_backuplog_options_and_more.cpython-312.pyc +0 -0
  31. simo/backups/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  32. simo/backups/rescue.img.xz +0 -0
  33. simo/backups/tasks.py +361 -17
  34. simo/core/__pycache__/__init__.cpython-312.pyc +0 -0
  35. simo/core/__pycache__/admin.cpython-312.pyc +0 -0
  36. simo/core/__pycache__/api.cpython-312.pyc +0 -0
  37. simo/core/__pycache__/api_auth.cpython-312.pyc +0 -0
  38. simo/core/__pycache__/api_meta.cpython-312.pyc +0 -0
  39. simo/core/__pycache__/app_widgets.cpython-312.pyc +0 -0
  40. simo/core/__pycache__/apps.cpython-312.pyc +0 -0
  41. simo/core/__pycache__/auto_urls.cpython-312.pyc +0 -0
  42. simo/core/__pycache__/autocomplete_views.cpython-312.pyc +0 -0
  43. simo/core/__pycache__/base_types.cpython-312.pyc +0 -0
  44. simo/core/__pycache__/context.cpython-312.pyc +0 -0
  45. simo/core/__pycache__/controllers.cpython-312.pyc +0 -0
  46. simo/core/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
  47. simo/core/__pycache__/events.cpython-312.pyc +0 -0
  48. simo/core/__pycache__/filters.cpython-312.pyc +0 -0
  49. simo/core/__pycache__/form_fields.cpython-312.pyc +0 -0
  50. simo/core/__pycache__/forms.cpython-312.pyc +0 -0
  51. simo/core/__pycache__/gateways.cpython-312.pyc +0 -0
  52. simo/core/__pycache__/loggers.cpython-312.pyc +0 -0
  53. simo/core/__pycache__/managers.cpython-312.pyc +0 -0
  54. simo/core/__pycache__/middleware.cpython-312.pyc +0 -0
  55. simo/core/__pycache__/models.cpython-312.pyc +0 -0
  56. simo/core/__pycache__/permissions.cpython-312.pyc +0 -0
  57. simo/core/__pycache__/routing.cpython-312.pyc +0 -0
  58. simo/core/__pycache__/serializers.cpython-312.pyc +0 -0
  59. simo/core/__pycache__/signal_receivers.cpython-312.pyc +0 -0
  60. simo/core/__pycache__/socket_consumers.cpython-312.pyc +0 -0
  61. simo/core/__pycache__/storage.cpython-312.pyc +0 -0
  62. simo/core/__pycache__/tasks.cpython-312.pyc +0 -0
  63. simo/core/__pycache__/todos.cpython-312.pyc +0 -0
  64. simo/core/__pycache__/types.cpython-312.pyc +0 -0
  65. simo/core/__pycache__/views.cpython-312.pyc +0 -0
  66. simo/core/__pycache__/widgets.cpython-312.pyc +0 -0
  67. simo/core/controllers.py +6 -3
  68. simo/core/db_backend/__pycache__/__init__.cpython-312.pyc +0 -0
  69. simo/core/db_backend/__pycache__/base.cpython-312.pyc +0 -0
  70. simo/core/drf_braces/__pycache__/__init__.cpython-312.pyc +0 -0
  71. simo/core/drf_braces/__pycache__/mixins.cpython-312.pyc +0 -0
  72. simo/core/drf_braces/__pycache__/models.cpython-312.pyc +0 -0
  73. simo/core/drf_braces/__pycache__/parsers.cpython-312.pyc +0 -0
  74. simo/core/drf_braces/__pycache__/renderers.cpython-312.pyc +0 -0
  75. simo/core/drf_braces/__pycache__/utils.cpython-312.pyc +0 -0
  76. simo/core/drf_braces/fields/__pycache__/__init__.cpython-312.pyc +0 -0
  77. simo/core/drf_braces/fields/__pycache__/_fields.cpython-312.pyc +0 -0
  78. simo/core/drf_braces/fields/__pycache__/custom.cpython-312.pyc +0 -0
  79. simo/core/drf_braces/fields/__pycache__/mixins.cpython-312.pyc +0 -0
  80. simo/core/drf_braces/fields/__pycache__/modified.cpython-312.pyc +0 -0
  81. simo/core/drf_braces/forms/__pycache__/__init__.cpython-312.pyc +0 -0
  82. simo/core/drf_braces/forms/__pycache__/fields.cpython-312.pyc +0 -0
  83. simo/core/drf_braces/forms/__pycache__/serializer_form.cpython-312.pyc +0 -0
  84. simo/core/drf_braces/serializers/__pycache__/__init__.cpython-312.pyc +0 -0
  85. simo/core/drf_braces/serializers/__pycache__/enforce_validation_serializer.cpython-312.pyc +0 -0
  86. simo/core/drf_braces/serializers/__pycache__/form_serializer.cpython-312.pyc +0 -0
  87. simo/core/drf_braces/serializers/__pycache__/swapping.cpython-312.pyc +0 -0
  88. simo/core/drf_braces/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  89. simo/core/drf_braces/tests/__pycache__/test_mixins.cpython-312.pyc +0 -0
  90. simo/core/drf_braces/tests/__pycache__/test_parsers.cpython-312.pyc +0 -0
  91. simo/core/drf_braces/tests/__pycache__/test_renderers.cpython-312.pyc +0 -0
  92. simo/core/drf_braces/tests/__pycache__/test_utils.cpython-312.pyc +0 -0
  93. simo/core/drf_braces/tests/fields/__pycache__/__init__.cpython-312.pyc +0 -0
  94. simo/core/drf_braces/tests/fields/__pycache__/test_custom.cpython-312.pyc +0 -0
  95. simo/core/drf_braces/tests/fields/__pycache__/test_fields.cpython-312.pyc +0 -0
  96. simo/core/drf_braces/tests/fields/__pycache__/test_mixins.cpython-312.pyc +0 -0
  97. simo/core/drf_braces/tests/fields/__pycache__/test_modified.cpython-312.pyc +0 -0
  98. simo/core/drf_braces/tests/forms/__pycache__/__init__.cpython-312.pyc +0 -0
  99. simo/core/drf_braces/tests/forms/__pycache__/test_fields.cpython-312.pyc +0 -0
  100. simo/core/drf_braces/tests/forms/__pycache__/test_serializer_form.cpython-312.pyc +0 -0
  101. simo/core/drf_braces/tests/serializers/__pycache__/__init__.cpython-312.pyc +0 -0
  102. simo/core/drf_braces/tests/serializers/__pycache__/test_enforce_validation_serializer.cpython-312.pyc +0 -0
  103. simo/core/drf_braces/tests/serializers/__pycache__/test_form_serializer.cpython-312.pyc +0 -0
  104. simo/core/drf_braces/tests/serializers/__pycache__/test_swapping.cpython-312.pyc +0 -0
  105. simo/core/management/__pycache__/__init__.cpython-312.pyc +0 -0
  106. simo/core/management/__pycache__/update.cpython-312.pyc +0 -0
  107. simo/core/management/_hub_template/hub/__pycache__/asgi.cpython-312.pyc +0 -0
  108. simo/core/management/_hub_template/hub/__pycache__/celeryc.cpython-312.pyc +0 -0
  109. simo/core/management/_hub_template/hub/__pycache__/manage.cpython-312.pyc +0 -0
  110. simo/core/management/_hub_template/hub/__pycache__/settings.cpython-312.pyc +0 -0
  111. simo/core/management/_hub_template/hub/__pycache__/urls.cpython-312.pyc +0 -0
  112. simo/core/management/_hub_template/hub/__pycache__/wsgi.cpython-312.pyc +0 -0
  113. simo/core/management/commands/__pycache__/__init__.cpython-312.pyc +0 -0
  114. simo/core/management/commands/__pycache__/gateways_manager.cpython-312.pyc +0 -0
  115. simo/core/management/commands/__pycache__/on_http_start.cpython-312.pyc +0 -0
  116. simo/core/management/commands/__pycache__/run_gateway.cpython-312.pyc +0 -0
  117. simo/core/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  118. simo/core/migrations/__pycache__/0002_load_icons.cpython-312.pyc +0 -0
  119. simo/core/migrations/__pycache__/0003_create_default_zones_and_categories.cpython-312.pyc +0 -0
  120. simo/core/migrations/__pycache__/0004_create_generic.cpython-312.pyc +0 -0
  121. simo/core/migrations/__pycache__/0005_component_subcomponents.cpython-312.pyc +0 -0
  122. simo/core/migrations/__pycache__/0006_alter_component_subcomponents.cpython-312.pyc +0 -0
  123. simo/core/migrations/__pycache__/0007_component_change_init_to.cpython-312.pyc +0 -0
  124. simo/core/migrations/__pycache__/0008_alter_component_change_init_to.cpython-312.pyc +0 -0
  125. simo/core/migrations/__pycache__/0009_auto_20220707_1404.cpython-312.pyc +0 -0
  126. simo/core/migrations/__pycache__/0010_historyaggregate.cpython-312.pyc +0 -0
  127. simo/core/migrations/__pycache__/0011_component_last_change.cpython-312.pyc +0 -0
  128. simo/core/migrations/__pycache__/0012_instance.cpython-312.pyc +0 -0
  129. simo/core/migrations/__pycache__/0013_auto_20231003_0754.cpython-312.pyc +0 -0
  130. simo/core/migrations/__pycache__/0014_zone_instance.cpython-312.pyc +0 -0
  131. simo/core/migrations/__pycache__/0015_auto_20231004_1113.cpython-312.pyc +0 -0
  132. simo/core/migrations/__pycache__/0016_auto_20231004_1113.cpython-312.pyc +0 -0
  133. simo/core/migrations/__pycache__/0017_auto_20231004_1313.cpython-312.pyc +0 -0
  134. simo/core/migrations/__pycache__/0018_auto_20231005_0622.cpython-312.pyc +0 -0
  135. simo/core/migrations/__pycache__/0019_alter_gateway_type.cpython-312.pyc +0 -0
  136. simo/core/migrations/__pycache__/0020_component_meta.cpython-312.pyc +0 -0
  137. simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-312.pyc +0 -0
  138. simo/core/migrations/__pycache__/0022_auto_20231221_0735.cpython-312.pyc +0 -0
  139. simo/core/migrations/__pycache__/0023_auto_20231229_1352.cpython-312.pyc +0 -0
  140. simo/core/migrations/__pycache__/0024_alter_instance_device_report_history_days.cpython-312.pyc +0 -0
  141. simo/core/migrations/__pycache__/0025_auto_20240122_1321.cpython-312.pyc +0 -0
  142. simo/core/migrations/__pycache__/0026_category_instance.cpython-312.pyc +0 -0
  143. simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-312.pyc +0 -0
  144. simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-312.pyc +0 -0
  145. simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-312.pyc +0 -0
  146. simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-312.pyc +0 -0
  147. simo/core/migrations/__pycache__/0031_auto_20240429_1231.cpython-312.pyc +0 -0
  148. simo/core/migrations/__pycache__/0032_auto_20240506_0834.cpython-312.pyc +0 -0
  149. simo/core/migrations/__pycache__/0033_auto_20240509_0821.cpython-312.pyc +0 -0
  150. simo/core/migrations/__pycache__/0034_component_error_msg.cpython-312.pyc +0 -0
  151. simo/core/migrations/__pycache__/0035_remove_instance_share_location.cpython-312.pyc +0 -0
  152. simo/core/migrations/__pycache__/0036_auto_20240521_0823.cpython-312.pyc +0 -0
  153. simo/core/migrations/__pycache__/0037_auto_20240606_1057.cpython-312.pyc +0 -0
  154. simo/core/migrations/__pycache__/0038_remove_instance_cover_image_and_more.cpython-312.pyc +0 -0
  155. simo/core/migrations/__pycache__/0039_instance_is_active_alter_instance_timezone.cpython-312.pyc +0 -0
  156. simo/core/migrations/__pycache__/0040_alter_instance_name.cpython-312.pyc +0 -0
  157. simo/core/migrations/__pycache__/0041_alter_instance_slug.cpython-312.pyc +0 -0
  158. simo/core/migrations/__pycache__/0042_alter_instance_timezone.cpython-312.pyc +0 -0
  159. simo/core/migrations/__pycache__/0043_alter_category_instance_alter_instance_timezone_and_more.cpython-312.pyc +0 -0
  160. simo/core/migrations/__pycache__/0044_alter_gateway_type.cpython-312.pyc +0 -0
  161. simo/core/migrations/__pycache__/0045_alter_instance_device_report_history_days_and_more.cpython-312.pyc +0 -0
  162. simo/core/migrations/__pycache__/0046_component_value_translation_alter_gateway_type.cpython-312.pyc +0 -0
  163. simo/core/migrations/__pycache__/0047_alter_component_value_translation.cpython-312.pyc +0 -0
  164. simo/core/migrations/__pycache__/0048_publicfile_privatefile.cpython-312.pyc +0 -0
  165. simo/core/migrations/__pycache__/0049_alter_gateway_type.cpython-312.pyc +0 -0
  166. simo/core/migrations/__pycache__/0050_componenthistory_alive.cpython-312.pyc +0 -0
  167. simo/core/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  168. simo/core/templates/core/__pycache__/value_translation.cpython-312.pyc +0 -0
  169. simo/core/templatetags/__pycache__/__init__.cpython-312.pyc +0 -0
  170. simo/core/templatetags/__pycache__/components_list.cpython-312.pyc +0 -0
  171. simo/core/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  172. simo/core/utils/__pycache__/admin.cpython-312.pyc +0 -0
  173. simo/core/utils/__pycache__/api.cpython-312.pyc +0 -0
  174. simo/core/utils/__pycache__/cache.cpython-312.pyc +0 -0
  175. simo/core/utils/__pycache__/config_values.cpython-312.pyc +0 -0
  176. simo/core/utils/__pycache__/converters.cpython-312.pyc +0 -0
  177. simo/core/utils/__pycache__/easing.cpython-312.pyc +0 -0
  178. simo/core/utils/__pycache__/form_fields.cpython-312.pyc +0 -0
  179. simo/core/utils/__pycache__/form_widgets.cpython-312.pyc +0 -0
  180. simo/core/utils/__pycache__/formsets.cpython-312.pyc +0 -0
  181. simo/core/utils/__pycache__/helpers.cpython-312.pyc +0 -0
  182. simo/core/utils/__pycache__/json.cpython-312.pyc +0 -0
  183. simo/core/utils/__pycache__/logs.cpython-312.pyc +0 -0
  184. simo/core/utils/__pycache__/mixins.cpython-312.pyc +0 -0
  185. simo/core/utils/__pycache__/model_helpers.cpython-312.pyc +0 -0
  186. simo/core/utils/__pycache__/operations.cpython-312.pyc +0 -0
  187. simo/core/utils/__pycache__/relay.cpython-312.pyc +0 -0
  188. simo/core/utils/__pycache__/serialization.cpython-312.pyc +0 -0
  189. simo/core/utils/__pycache__/type_constants.cpython-312.pyc +0 -0
  190. simo/core/utils/__pycache__/validators.cpython-312.pyc +0 -0
  191. simo/fleet/__pycache__/__init__.cpython-312.pyc +0 -0
  192. simo/fleet/__pycache__/admin.cpython-312.pyc +0 -0
  193. simo/fleet/__pycache__/api.cpython-312.pyc +0 -0
  194. simo/fleet/__pycache__/apps.cpython-312.pyc +0 -0
  195. simo/fleet/__pycache__/auto_urls.cpython-312.pyc +0 -0
  196. simo/fleet/__pycache__/base_types.cpython-312.pyc +0 -0
  197. simo/fleet/__pycache__/ble.cpython-312.pyc +0 -0
  198. simo/fleet/__pycache__/controllers.cpython-312.pyc +0 -0
  199. simo/fleet/__pycache__/custom_dali_operations.cpython-312.pyc +0 -0
  200. simo/fleet/__pycache__/forms.cpython-312.pyc +0 -0
  201. simo/fleet/__pycache__/gateways.cpython-312.pyc +0 -0
  202. simo/fleet/__pycache__/managers.cpython-312.pyc +0 -0
  203. simo/fleet/__pycache__/models.cpython-312.pyc +0 -0
  204. simo/fleet/__pycache__/routing.cpython-312.pyc +0 -0
  205. simo/fleet/__pycache__/serializers.cpython-312.pyc +0 -0
  206. simo/fleet/__pycache__/socket_consumers.cpython-312.pyc +0 -0
  207. simo/fleet/__pycache__/tasks.cpython-312.pyc +0 -0
  208. simo/fleet/__pycache__/utils.cpython-312.pyc +0 -0
  209. simo/fleet/__pycache__/views.cpython-312.pyc +0 -0
  210. simo/fleet/controllers.py +102 -47
  211. simo/fleet/custom_dali_operations.py +14 -2
  212. simo/fleet/forms.py +112 -101
  213. simo/fleet/migrations/0054_auto_20250507_1256.py +36 -0
  214. simo/fleet/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  215. simo/fleet/migrations/__pycache__/0002_auto_20220422_0743.cpython-312.pyc +0 -0
  216. simo/fleet/migrations/__pycache__/0003_auto_20220422_0752.cpython-312.pyc +0 -0
  217. simo/fleet/migrations/__pycache__/0004_auto_20220422_0818.cpython-312.pyc +0 -0
  218. simo/fleet/migrations/__pycache__/0005_auto_20220428_0900.cpython-312.pyc +0 -0
  219. simo/fleet/migrations/__pycache__/0006_rename_mac_colonel_uid.cpython-312.pyc +0 -0
  220. simo/fleet/migrations/__pycache__/0007_colonel_socket_connected.cpython-312.pyc +0 -0
  221. simo/fleet/migrations/__pycache__/0008_i2cinterface.cpython-312.pyc +0 -0
  222. simo/fleet/migrations/__pycache__/0009_i2cinterface_name.cpython-312.pyc +0 -0
  223. simo/fleet/migrations/__pycache__/0010_auto_20220602_0746.cpython-312.pyc +0 -0
  224. simo/fleet/migrations/__pycache__/0011_i2cinterface_freq.cpython-312.pyc +0 -0
  225. simo/fleet/migrations/__pycache__/0012_colonel_logs_stream.cpython-312.pyc +0 -0
  226. simo/fleet/migrations/__pycache__/0013_alter_colonel_last_seen.cpython-312.pyc +0 -0
  227. simo/fleet/migrations/__pycache__/0014_auto_20220614_0659.cpython-312.pyc +0 -0
  228. simo/fleet/migrations/__pycache__/0015_auto_20220614_0754.cpython-312.pyc +0 -0
  229. simo/fleet/migrations/__pycache__/0016_auto_20220704_0840.cpython-312.pyc +0 -0
  230. simo/fleet/migrations/__pycache__/0017_alter_colonel_secret.cpython-312.pyc +0 -0
  231. simo/fleet/migrations/__pycache__/0018_colonel_instance.cpython-312.pyc +0 -0
  232. simo/fleet/migrations/__pycache__/0019_auto_20231006_0749.cpython-312.pyc +0 -0
  233. simo/fleet/migrations/__pycache__/0020_instanceoptions.cpython-312.pyc +0 -0
  234. simo/fleet/migrations/__pycache__/0021_auto_20231006_0819.cpython-312.pyc +0 -0
  235. simo/fleet/migrations/__pycache__/0022_remove_colonel_secret.cpython-312.pyc +0 -0
  236. simo/fleet/migrations/__pycache__/0023_colonel_is_authorized.cpython-312.pyc +0 -0
  237. simo/fleet/migrations/__pycache__/0024_colonel_pwm_frequency.cpython-312.pyc +0 -0
  238. simo/fleet/migrations/__pycache__/0025_auto_20240130_1334.cpython-312.pyc +0 -0
  239. simo/fleet/migrations/__pycache__/0026_rename_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
  240. simo/fleet/migrations/__pycache__/0027_auto_20240306_0802.cpython-312.pyc +0 -0
  241. simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.cpython-312.pyc +0 -0
  242. simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-312.pyc +0 -0
  243. simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-312.pyc +0 -0
  244. simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-312.pyc +0 -0
  245. simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-312.pyc +0 -0
  246. simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-312.pyc +0 -0
  247. simo/fleet/migrations/__pycache__/0034_auto_20240418_0735.cpython-312.pyc +0 -0
  248. simo/fleet/migrations/__pycache__/0035_auto_20240514_0855.cpython-312.pyc +0 -0
  249. simo/fleet/migrations/__pycache__/0036_auto_20240605_0702.cpython-312.pyc +0 -0
  250. simo/fleet/migrations/__pycache__/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.cpython-312.pyc +0 -0
  251. simo/fleet/migrations/__pycache__/0038_alter_colonel_type.cpython-312.pyc +0 -0
  252. simo/fleet/migrations/__pycache__/0039_auto_20241016_1047.cpython-312.pyc +0 -0
  253. simo/fleet/migrations/__pycache__/0040_alter_colonel_pwm_frequency.cpython-312.pyc +0 -0
  254. simo/fleet/migrations/__pycache__/0041_alter_colonel_instance_and_more.cpython-312.pyc +0 -0
  255. simo/fleet/migrations/__pycache__/0042_auto_20241120_1028.cpython-312.pyc +0 -0
  256. simo/fleet/migrations/__pycache__/0043_auto_20241203_0930.cpython-312.pyc +0 -0
  257. simo/fleet/migrations/__pycache__/0044_auto_20241210_0707.cpython-312.pyc +0 -0
  258. simo/fleet/migrations/__pycache__/0045_alter_colonel_type_customdalidevice.cpython-312.pyc +0 -0
  259. simo/fleet/migrations/__pycache__/0046_delete_customdalidevice.cpython-312.pyc +0 -0
  260. simo/fleet/migrations/__pycache__/0047_customdalidevice.cpython-312.pyc +0 -0
  261. simo/fleet/migrations/__pycache__/0048_remove_customdalidevice_colonel_and_more.cpython-312.pyc +0 -0
  262. simo/fleet/migrations/__pycache__/0049_alter_customdalidevice_interface.cpython-312.pyc +0 -0
  263. simo/fleet/migrations/__pycache__/0050_customdalidevice_uid.cpython-312.pyc +0 -0
  264. simo/fleet/migrations/__pycache__/0051_customdalidevice_components.cpython-312.pyc +0 -0
  265. simo/fleet/migrations/__pycache__/0052_colonelpin_interface.cpython-312.pyc +0 -0
  266. simo/fleet/migrations/__pycache__/0053_auto_20250507_0713.cpython-312.pyc +0 -0
  267. simo/fleet/migrations/__pycache__/0054_auto_20250507_1256.cpython-312.pyc +0 -0
  268. simo/fleet/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  269. simo/fleet/models.py +1 -1
  270. simo/generic/__pycache__/__init__.cpython-312.pyc +0 -0
  271. simo/generic/__pycache__/app_widgets.cpython-312.pyc +0 -0
  272. simo/generic/__pycache__/base_types.cpython-312.pyc +0 -0
  273. simo/generic/__pycache__/controllers.cpython-312.pyc +0 -0
  274. simo/generic/__pycache__/forms.cpython-312.pyc +0 -0
  275. simo/generic/__pycache__/gateways.cpython-312.pyc +0 -0
  276. simo/generic/__pycache__/models.cpython-312.pyc +0 -0
  277. simo/generic/__pycache__/routing.cpython-312.pyc +0 -0
  278. simo/generic/__pycache__/socket_consumers.cpython-312.pyc +0 -0
  279. simo/generic/__pycache__/tasks.cpython-312.pyc +0 -0
  280. simo/generic/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  281. simo/generic/migrations/__pycache__/0002_auto_20241126_0726.cpython-312.pyc +0 -0
  282. simo/generic/migrations/__pycache__/0003_auto_20250409_1404.cpython-312.pyc +0 -0
  283. simo/generic/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  284. simo/multimedia/__pycache__/__init__.cpython-312.pyc +0 -0
  285. simo/multimedia/__pycache__/admin.cpython-312.pyc +0 -0
  286. simo/multimedia/__pycache__/api.cpython-312.pyc +0 -0
  287. simo/multimedia/__pycache__/app_widgets.cpython-312.pyc +0 -0
  288. simo/multimedia/__pycache__/auto_urls.cpython-312.pyc +0 -0
  289. simo/multimedia/__pycache__/base_types.cpython-312.pyc +0 -0
  290. simo/multimedia/__pycache__/controllers.cpython-312.pyc +0 -0
  291. simo/multimedia/__pycache__/forms.cpython-312.pyc +0 -0
  292. simo/multimedia/__pycache__/models.cpython-312.pyc +0 -0
  293. simo/multimedia/__pycache__/serializers.cpython-312.pyc +0 -0
  294. simo/multimedia/__pycache__/views.cpython-312.pyc +0 -0
  295. simo/multimedia/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  296. simo/multimedia/migrations/__pycache__/0002_sound_length.cpython-312.pyc +0 -0
  297. simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-312.pyc +0 -0
  298. simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-312.pyc +0 -0
  299. simo/multimedia/migrations/__pycache__/0005_remove_sound_slug_sound_date_uploaded.cpython-312.pyc +0 -0
  300. simo/multimedia/migrations/__pycache__/0006_remove_sound_length_sound_duration.cpython-312.pyc +0 -0
  301. simo/multimedia/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  302. simo/notifications/__pycache__/__init__.cpython-312.pyc +0 -0
  303. simo/notifications/__pycache__/admin.cpython-312.pyc +0 -0
  304. simo/notifications/__pycache__/api.cpython-312.pyc +0 -0
  305. simo/notifications/__pycache__/models.cpython-312.pyc +0 -0
  306. simo/notifications/__pycache__/serializers.cpython-312.pyc +0 -0
  307. simo/notifications/__pycache__/utils.cpython-312.pyc +0 -0
  308. simo/notifications/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  309. simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-312.pyc +0 -0
  310. simo/notifications/migrations/__pycache__/0003_alter_notification_instance.cpython-312.pyc +0 -0
  311. simo/notifications/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  312. simo/users/__pycache__/__init__.cpython-312.pyc +0 -0
  313. simo/users/__pycache__/admin.cpython-312.pyc +0 -0
  314. simo/users/__pycache__/api.cpython-312.pyc +0 -0
  315. simo/users/__pycache__/apps.cpython-312.pyc +0 -0
  316. simo/users/__pycache__/auth_backends.cpython-312.pyc +0 -0
  317. simo/users/__pycache__/auto_urls.cpython-312.pyc +0 -0
  318. simo/users/__pycache__/dynamic_settings.cpython-312.pyc +0 -0
  319. simo/users/__pycache__/managers.cpython-312.pyc +0 -0
  320. simo/users/__pycache__/middleware.cpython-312.pyc +0 -0
  321. simo/users/__pycache__/models.cpython-312.pyc +0 -0
  322. simo/users/__pycache__/permissions.cpython-312.pyc +0 -0
  323. simo/users/__pycache__/serializers.cpython-312.pyc +0 -0
  324. simo/users/__pycache__/sso_urls.cpython-312.pyc +0 -0
  325. simo/users/__pycache__/sso_views.cpython-312.pyc +0 -0
  326. simo/users/__pycache__/tasks.cpython-312.pyc +0 -0
  327. simo/users/__pycache__/utils.cpython-312.pyc +0 -0
  328. simo/users/__pycache__/views.cpython-312.pyc +0 -0
  329. simo/users/migrations/__pycache__/0001_initial.cpython-312.pyc +0 -0
  330. simo/users/migrations/__pycache__/0002_componentpermission.cpython-312.pyc +0 -0
  331. simo/users/migrations/__pycache__/0003_create_roles_and_system_user.cpython-312.pyc +0 -0
  332. simo/users/migrations/__pycache__/0004_user_secret_key.cpython-312.pyc +0 -0
  333. simo/users/migrations/__pycache__/0005_permissionsrole_instance.cpython-312.pyc +0 -0
  334. simo/users/migrations/__pycache__/0006_auto_20231003_0850.cpython-312.pyc +0 -0
  335. simo/users/migrations/__pycache__/0007_auto_20231003_1228.cpython-312.pyc +0 -0
  336. simo/users/migrations/__pycache__/0008_auto_20231003_1229.cpython-312.pyc +0 -0
  337. simo/users/migrations/__pycache__/0009_remove_user_role.cpython-312.pyc +0 -0
  338. simo/users/migrations/__pycache__/0010_auto_20231004_1313.cpython-312.pyc +0 -0
  339. simo/users/migrations/__pycache__/0011_auto_20231004_1313.cpython-312.pyc +0 -0
  340. simo/users/migrations/__pycache__/0012_alter_userinstancerole_unique_together.cpython-312.pyc +0 -0
  341. simo/users/migrations/__pycache__/0013_remove_user_roles.cpython-312.pyc +0 -0
  342. simo/users/migrations/__pycache__/0014_user_roles.cpython-312.pyc +0 -0
  343. simo/users/migrations/__pycache__/0015_remove_user_at_home.cpython-312.pyc +0 -0
  344. simo/users/migrations/__pycache__/0016_auto_20231005_1050.cpython-312.pyc +0 -0
  345. simo/users/migrations/__pycache__/0017_auto_20231221_0735.cpython-312.pyc +0 -0
  346. simo/users/migrations/__pycache__/0018_user_is_god.cpython-312.pyc +0 -0
  347. simo/users/migrations/__pycache__/0019_auto_20231221_1155.cpython-312.pyc +0 -0
  348. simo/users/migrations/__pycache__/0020_rename_is_god_user_is_master.cpython-312.pyc +0 -0
  349. simo/users/migrations/__pycache__/0021_alter_permissionsrole_instance.cpython-312.pyc +0 -0
  350. simo/users/migrations/__pycache__/0022_userdevicereportlog_instance.cpython-312.pyc +0 -0
  351. simo/users/migrations/__pycache__/0023_auto_20240105_0719.cpython-312.pyc +0 -0
  352. simo/users/migrations/__pycache__/0024_fingerprint.cpython-312.pyc +0 -0
  353. simo/users/migrations/__pycache__/0025_rename_name_fingerprint_type_and_more.cpython-312.pyc +0 -0
  354. simo/users/migrations/__pycache__/0026_fingerprint_name.cpython-312.pyc +0 -0
  355. simo/users/migrations/__pycache__/0027_permissionsrole_can_manage_components.cpython-312.pyc +0 -0
  356. simo/users/migrations/__pycache__/0028_auto_20240506_1146.cpython-312.pyc +0 -0
  357. simo/users/migrations/__pycache__/0029_alter_instanceuser_instance.cpython-312.pyc +0 -0
  358. simo/users/migrations/__pycache__/0030_userdevice_users.cpython-312.pyc +0 -0
  359. simo/users/migrations/__pycache__/0031_auto_20240923_1115.cpython-312.pyc +0 -0
  360. simo/users/migrations/__pycache__/0032_remove_userdevice_user_alter_userdevice_users.cpython-312.pyc +0 -0
  361. simo/users/migrations/__pycache__/0033_alter_user_ssh_key.cpython-312.pyc +0 -0
  362. simo/users/migrations/__pycache__/0034_instanceuser_last_seen_location_and_more.cpython-312.pyc +0 -0
  363. simo/users/migrations/__pycache__/0035_instanceuser_last_seen_speed_kmh_and_more.cpython-312.pyc +0 -0
  364. simo/users/migrations/__pycache__/0036_instanceuser_phone_on_charge_user_phone_on_charge.cpython-312.pyc +0 -0
  365. simo/users/migrations/__pycache__/0037_rename_last_seen_location_datetime_instanceuser_last_seen_and_more.cpython-312.pyc +0 -0
  366. simo/users/migrations/__pycache__/0038_userdevicereportlog_at_home_and_more.cpython-312.pyc +0 -0
  367. simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-312.pyc +0 -0
  368. simo/users/migrations/__pycache__/0040_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
  369. simo/users/migrations/__pycache__/0041_userdevicereportlog_speed_kmh_received.cpython-312.pyc +0 -0
  370. simo/users/migrations/__pycache__/0042_remove_userdevicereportlog_location_smoothed_and_more.cpython-312.pyc +0 -0
  371. simo/users/migrations/__pycache__/0043_userdevicereportlog_avg_speed_kmh.cpython-312.pyc +0 -0
  372. simo/users/migrations/__pycache__/0044_permissionsrole_is_person.cpython-312.pyc +0 -0
  373. simo/users/migrations/__pycache__/__init__.cpython-312.pyc +0 -0
  374. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/METADATA +1 -1
  375. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/RECORD +379 -376
  376. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/WHEEL +1 -1
  377. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/entry_points.txt +0 -0
  378. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/licenses/LICENSE.md +0 -0
  379. {simo-2.10.9.dist-info → simo-2.11.1.dist-info}/top_level.txt +0 -0
simo/fleet/controllers.py CHANGED
@@ -10,20 +10,21 @@ from simo.core.controllers import (
10
10
  Switch as BaseSwitch, Dimmer as BaseDimmer,
11
11
  MultiSensor as BaseMultiSensor, RGBWLight as BaseRGBWLight,
12
12
  Blinds as BaseBlinds, Gate as BaseGate,
13
+ Lock, ControllerBase, SingleSwitchWidget
13
14
  )
14
15
  from simo.core.app_widgets import NumericSensorWidget, AirQualityWidget
15
- from simo.core.controllers import Lock, ControllerBase, SingleSwitchWidget
16
16
  from simo.core.utils.helpers import heat_index
17
17
  from simo.core.utils.serialization import (
18
18
  serialize_form_data, deserialize_form_data
19
19
  )
20
20
  from simo.core.forms import BaseComponentForm
21
+ from simo.generic.controllers import StateSelect
21
22
  from .models import Colonel, CustomDaliDevice
22
23
  from .gateways import FleetGatewayHandler
23
24
  from .forms import (
24
25
  ColonelPinChoiceField,
25
26
  ColonelBinarySensorConfigForm, ColonelButtonConfigForm,
26
- ColonelSwitchConfigForm, ColonelPWMOutputConfigForm, DCDriverConfigForm,
27
+ ColonelSwitchConfigForm, ColonelPWMOutputConfigForm, DC10VConfigForm,
27
28
  ColonelNumericSensorConfigForm, ColonelRGBLightConfigForm,
28
29
  ColonelDHTSensorConfigForm, DS18B20SensorConfigForm,
29
30
  BME680SensorConfigForm, MCP9808SensorConfigForm, ENS160SensorConfigForm,
@@ -37,7 +38,7 @@ from .forms import (
37
38
  )
38
39
 
39
40
 
40
- class FleeDeviceMixin:
41
+ class FleetDeviceMixin:
41
42
 
42
43
  def update_options(self, options):
43
44
  GatewayObjectCommand(
@@ -91,11 +92,11 @@ class BasicSensorMixin:
91
92
  self.component.config['pin_no'],
92
93
  ]
93
94
 
94
- class BinarySensor(FleeDeviceMixin, BasicSensorMixin, BaseBinarySensor):
95
+ class BinarySensor(FleetDeviceMixin, BasicSensorMixin, BaseBinarySensor):
95
96
  config_form = ColonelBinarySensorConfigForm
96
97
 
97
98
 
98
- class Button(FleeDeviceMixin, BasicSensorMixin, BaseButton):
99
+ class Button(FleetDeviceMixin, BasicSensorMixin, BaseButton):
99
100
  config_form = ColonelButtonConfigForm
100
101
 
101
102
 
@@ -110,12 +111,12 @@ class BurglarSmokeDetector(BinarySensor):
110
111
  ]
111
112
 
112
113
 
113
- class DS18B20Sensor(FleeDeviceMixin, BasicSensorMixin, BaseNumericSensor):
114
+ class DS18B20Sensor(FleetDeviceMixin, BasicSensorMixin, BaseNumericSensor):
114
115
  config_form = DS18B20SensorConfigForm
115
116
  name = "DS18B20 Temperature sensor"
116
117
 
117
118
 
118
- class DHTSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
119
+ class DHTSensor(FleetDeviceMixin, BasicSensorMixin, BaseMultiSensor):
119
120
  config_form = ColonelDHTSensorConfigForm
120
121
  name = "DHT climate sensor"
121
122
  app_widget = NumericSensorWidget
@@ -171,7 +172,7 @@ class BME680Sensor(DHTSensor):
171
172
 
172
173
 
173
174
 
174
- class MCP9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
175
+ class MCP9808TempSensor(FleetDeviceMixin, BaseNumericSensor):
175
176
  gateway_class = FleetGatewayHandler
176
177
  config_form = MCP9808SensorConfigForm
177
178
  name = "MCP9808 Temperature Sensor (I2C)"
@@ -196,7 +197,7 @@ class MCP9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
196
197
  return value
197
198
 
198
199
 
199
- class ENS160AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
200
+ class ENS160AirQualitySensor(FleetDeviceMixin, BaseMultiSensor):
200
201
  gateway_class = FleetGatewayHandler
201
202
  config_form = ENS160SensorConfigForm
202
203
  name = "ENS160 Air Quality Sensor (I2C)"
@@ -257,7 +258,7 @@ class BasicOutputMixin:
257
258
  ).publish()
258
259
 
259
260
 
260
- class Switch(FleeDeviceMixin, BasicOutputMixin, BaseSwitch):
261
+ class Switch(FleetDeviceMixin, BasicOutputMixin, BaseSwitch):
261
262
  config_form = ColonelSwitchConfigForm
262
263
 
263
264
  def signal(self, pulses):
@@ -313,8 +314,8 @@ class FadeMixin:
313
314
  ).publish()
314
315
 
315
316
 
316
- class PWMOutput(FadeMixin, FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
317
- name = "Dimmer"
317
+ class PWMOutput(FadeMixin, FleetDeviceMixin, BasicOutputMixin, BaseDimmer):
318
+ name = "AC/DC Dimmer | PWM Driver"
318
319
  config_form = ColonelPWMOutputConfigForm
319
320
 
320
321
  def _prepare_for_send(self, value):
@@ -344,7 +345,7 @@ class PWMOutput(FadeMixin, FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
344
345
 
345
346
  def _prepare_for_set(self, pwm_value):
346
347
  conf = self.component.config
347
- duty_max = 1023 - (conf.get('device_min', 0) * 0.01 * 1023)
348
+ duty_max = 1023 - conf.get('device_min', 0) * 0.01 * 1023
348
349
  duty_min = 1023 - conf.get('device_max', 100) * 0.01 * 1023
349
350
 
350
351
  if pwm_value > duty_max:
@@ -352,7 +353,7 @@ class PWMOutput(FadeMixin, FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
352
353
  elif pwm_value < duty_min:
353
354
  value = conf.get('min', 0)
354
355
  else:
355
- pwm_amplitude =duty_max - duty_min
356
+ pwm_amplitude = duty_max - duty_min
356
357
  relative_value = (pwm_value - duty_min) / pwm_amplitude
357
358
  val_amplitude = conf.get('max', 100) - conf.get('min', 0)
358
359
  value = conf.get('min', 0) + val_amplitude * relative_value
@@ -362,57 +363,71 @@ class PWMOutput(FadeMixin, FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
362
363
  return round(value, 3)
363
364
 
364
365
 
365
- class DCDriver(FadeMixin, FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
366
- name = "0 - 24V DC Driver"
367
- config_form = DCDriverConfigForm
368
- default_value_units = 'V'
366
+ class DC10VDriver(FadeMixin, FleetDeviceMixin, BasicOutputMixin, BaseDimmer):
367
+ name = "0 - 10V Driver"
368
+ config_form = DC10VConfigForm
369
+ default_value_units = '%'
369
370
 
370
371
  def _prepare_for_send(self, value):
371
372
  conf = self.component.config
372
- if value >= conf.get('max', 24):
373
- value = conf.get('max', 24)
373
+ if value >= conf.get('max', 100):
374
+ value = conf.get('max', 100)
374
375
  elif value < conf.get('min', 0):
375
376
  value = conf.get('min', 0)
376
377
 
377
- if value >= conf.get('max', 24):
378
- pwm_value = 1023
379
- elif value <= conf.get('min', 100):
380
- pwm_value = 0
378
+ if value >= conf.get('max', 100):
379
+ if conf.get('inverse') == True:
380
+ pwm_value = 0
381
+ else:
382
+ pwm_value = 1023
383
+ elif value <= conf.get('min', 0):
384
+ if conf.get('inverse') == True:
385
+ pwm_value = 1023
386
+ else:
387
+ pwm_value = 0
381
388
  else:
382
- val_amplitude = conf.get('max', 24) - conf.get('min', 0)
389
+ val_amplitude = conf.get('max', 100) - conf.get('min', 0)
383
390
  val_relative = value / val_amplitude
384
391
 
385
- duty_max = conf.get('device_max', 24) / 24 * 1023
386
- duty_min = conf.get('device_min', 0) / 24 * 1023
387
-
388
- pwm_amplitude = duty_max - duty_min
389
- pwm_value = duty_min + pwm_amplitude * val_relative
392
+ if conf.get('inverse') == True:
393
+ duty_max = 1023 - conf.get('device_min', 0) / 10 * 1023
394
+ duty_min = 1023 - conf.get('device_max', 10) / 10 * 1023
395
+ pwm_amplitude = duty_max - duty_min
396
+ pwm_value = duty_min + pwm_amplitude * val_relative
397
+ pwm_value = duty_max - pwm_value + duty_min
398
+ else:
399
+ duty_max = conf.get('device_max', 10) / 10 * 1023
400
+ duty_min = conf.get('device_min', 0) / 10 * 1023
401
+ pwm_amplitude = duty_max - duty_min
402
+ pwm_value = duty_min + pwm_amplitude * val_relative
390
403
 
391
404
  return pwm_value
392
405
 
393
406
  def _prepare_for_set(self, pwm_value):
394
407
  conf = self.component.config
395
- duty_max = conf.get('device_max', 24) / 24 * 1023
396
- duty_min = conf.get('device_min', 0) / 24 * 1023
408
+ if conf.get('inverse') == True:
409
+ pwm_value = 1023 - pwm_value
410
+ duty_max = conf.get('device_max', 10) / 10 * 1023
411
+ duty_min = conf.get('device_min', 0) / 10 * 1023
397
412
 
398
413
  if pwm_value > duty_max:
399
- value = conf.get('max', 24)
414
+ value = conf.get('max', 100)
400
415
  elif pwm_value < duty_min:
401
416
  value = conf.get('min', 0)
402
417
  else:
403
418
  pwm_amplitude = duty_max - duty_min
404
419
  relative_value = (pwm_value - duty_min) / pwm_amplitude
405
- val_amplitude = conf.get('max', 24) - conf.get('min', 0)
420
+ val_amplitude = conf.get('max', 100) - conf.get('min', 0)
406
421
  value = conf.get('min', 0) + val_amplitude * relative_value
407
422
 
408
423
  return round(value, 3)
409
424
 
410
425
 
411
- class RGBLight(FleeDeviceMixin, BasicOutputMixin, BaseRGBWLight):
426
+ class RGBLight(FleetDeviceMixin, BasicOutputMixin, BaseRGBWLight):
412
427
  config_form = ColonelRGBLightConfigForm
413
428
 
414
429
 
415
- class DualMotorValve(FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
430
+ class DualMotorValve(FleetDeviceMixin, BasicOutputMixin, BaseDimmer):
416
431
  gateway_class = FleetGatewayHandler
417
432
  config_form = DualMotorValveForm
418
433
  name = "Dual Motor Valve"
@@ -444,7 +459,7 @@ class DualMotorValve(FleeDeviceMixin, BasicOutputMixin, BaseDimmer):
444
459
  return conf.get('min', 0) + (value / 100) * val_amplitude
445
460
 
446
461
 
447
- class Blinds(FleeDeviceMixin, BasicOutputMixin, BaseBlinds):
462
+ class Blinds(FleetDeviceMixin, BasicOutputMixin, BaseBlinds):
448
463
  gateway_class = FleetGatewayHandler
449
464
  config_form = BlindsConfigForm
450
465
 
@@ -459,7 +474,7 @@ class Blinds(FleeDeviceMixin, BasicOutputMixin, BaseBlinds):
459
474
  return pins
460
475
 
461
476
 
462
- class Gate(FleeDeviceMixin, BasicOutputMixin, BaseGate):
477
+ class Gate(FleetDeviceMixin, BasicOutputMixin, BaseGate):
463
478
  gateway_class = FleetGatewayHandler
464
479
  config_form = GateConfigForm
465
480
 
@@ -475,7 +490,7 @@ class Gate(FleeDeviceMixin, BasicOutputMixin, BaseGate):
475
490
 
476
491
 
477
492
 
478
- class TTLock(FleeDeviceMixin, Lock):
493
+ class TTLock(FleetDeviceMixin, Lock):
479
494
  gateway_class = FleetGatewayHandler
480
495
  config_form = TTLockConfigForm
481
496
  name = 'TTLock'
@@ -666,7 +681,7 @@ class TTLock(FleeDeviceMixin, Lock):
666
681
 
667
682
 
668
683
 
669
- class DALIDevice(FleeDeviceMixin, ControllerBase):
684
+ class DALIDevice(FleetDeviceMixin, ControllerBase):
670
685
  gateway_class = FleetGatewayHandler
671
686
  config_form = DALIDeviceConfigForm
672
687
  name = "DALI Device"
@@ -785,7 +800,7 @@ class DALILamp(FadeMixin, BaseDimmer, DALIDevice):
785
800
  config_form = DaliLampForm
786
801
 
787
802
 
788
- class DALIGearGroup(FadeMixin, FleeDeviceMixin, BaseDimmer):
803
+ class DALIGearGroup(FadeMixin, FleetDeviceMixin, BaseDimmer):
789
804
  gateway_class = FleetGatewayHandler
790
805
  family = 'dali'
791
806
  manual_add = True
@@ -844,7 +859,7 @@ class DALIButton(BaseButton, DALIDevice):
844
859
  config_form = DALIButtonConfigForm
845
860
 
846
861
 
847
- class RoomSensor(FleeDeviceMixin, ControllerBase):
862
+ class RoomSensor(FleetDeviceMixin, ControllerBase):
848
863
  gateway_class = FleetGatewayHandler
849
864
  config_form = RoomSensorDeviceConfigForm
850
865
  name = "Room Sensor"
@@ -854,9 +869,49 @@ class RoomSensor(FleeDeviceMixin, ControllerBase):
854
869
 
855
870
  def _validate_val(self, value, occasion=None):
856
871
  return value
872
+
873
+
874
+ class RoomSiren(FleetDeviceMixin, StateSelect):
875
+ gateway_class = FleetGatewayHandler
876
+ config_form = BaseComponentForm
877
+ default_config = {'states': [
878
+ {'icon': 'bell', 'slug': 'silent', 'name': "Silent"},
879
+ {'icon': 'bell-exclamation', 'slug': 'warning', 'name': "Warning"},
880
+ {'icon': 'bell-on', 'slug': 'alarm', 'name': "Alarm"},
881
+ {'icon': 'circle-check', 'slug': 'success', 'name': "Success"},
882
+ {'icon': 'circle-xmark', 'slug': 'error', 'name': "Error"},
883
+ {'icon': 'siren-on', 'slug': 'panic', 'name': "Panic"},
884
+ ]}
885
+ VALUES_MAP = {
886
+ 'silent': 0, 'warning': 1, 'alarm': 2,
887
+ 'success': 3, 'error': 4, 'panic': 5
888
+ }
889
+
890
+ def turn_on(self):
891
+ self.send('panic')
892
+
893
+ def turn_off(self):
894
+ self.send('silent')
895
+
896
+ def _send_to_device(self, value):
897
+ if self.component.config.get('colonel'):
898
+ GatewayObjectCommand(
899
+ self.component.gateway, self.component, set_val=value
900
+ ).publish()
901
+ else:
902
+ dali_device = CustomDaliDevice.objects.filter(
903
+ id=self.component.config['dali_device']
904
+ ).first()
905
+ from .custom_dali_operations import Frame
906
+ frame = Frame(40, bytes(bytearray(5)))
907
+ frame[8:11] = 15 # command to custom dali device
908
+ frame[12:15] = 6 # action to perform: set value
909
+ frame[16:20] = 0 # device on which to perform value set
910
+ frame[21:24] = self.VALUES_MAP[value]
911
+ dali_device.transmit(frame)
857
912
 
858
913
 
859
- class AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
914
+ class AirQualitySensor(FleetDeviceMixin, BaseMultiSensor):
860
915
  gateway_class = FleetGatewayHandler
861
916
  config_form = BaseComponentForm
862
917
  name = "Air Quality Sensor"
@@ -901,7 +956,7 @@ class AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
901
956
  return
902
957
 
903
958
 
904
- class TempHumSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
959
+ class TempHumSensor(FleetDeviceMixin, BasicSensorMixin, BaseMultiSensor):
905
960
  gateway_class = FleetGatewayHandler
906
961
  config_form = BaseComponentForm
907
962
  name = "Temperature & Humidity sensor"
@@ -956,7 +1011,7 @@ class TempHumSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
956
1011
  return super()._receive_from_device(new_val, *args, **kwargs)
957
1012
 
958
1013
 
959
- class AmbientLightSensor(FleeDeviceMixin, BaseNumericSensor):
1014
+ class AmbientLightSensor(FleetDeviceMixin, BaseNumericSensor):
960
1015
  gateway_class = FleetGatewayHandler
961
1016
  name = "Ambient lighting sensor"
962
1017
  manual_add = False
@@ -971,13 +1026,13 @@ class AmbientLightSensor(FleeDeviceMixin, BaseNumericSensor):
971
1026
  }
972
1027
 
973
1028
 
974
- class RoomPresenceSensor(FleeDeviceMixin, BaseBinarySensor):
1029
+ class RoomPresenceSensor(FleetDeviceMixin, BaseBinarySensor):
975
1030
  gateway_class = FleetGatewayHandler
976
1031
  name = "Human presence sensor"
977
1032
  manual_add = False
978
1033
 
979
1034
 
980
- class RoomZonePresenceSensor(FleeDeviceMixin, BaseBinarySensor):
1035
+ class RoomZonePresenceSensor(FleetDeviceMixin, BaseBinarySensor):
981
1036
  gateway_class = FleetGatewayHandler
982
1037
  add_form = RoomZonePresenceConfigForm
983
1038
  config_form = BaseComponentForm
@@ -2,7 +2,7 @@ from django.utils import timezone
2
2
  from simo.core.models import Component
3
3
  from .models import Interface, CustomDaliDevice
4
4
  from .controllers import (
5
- TempHumSensor, AirQualitySensor, AmbientLightSensor,
5
+ RoomSiren, TempHumSensor, AirQualitySensor, AmbientLightSensor,
6
6
  RoomPresenceSensor, RoomZonePresenceSensor
7
7
  )
8
8
 
@@ -234,6 +234,7 @@ def process_frame(colonel_id, interface_no, data):
234
234
  comp.controller._receive_from_device(voc)
235
235
 
236
236
  elif frame[8:11] == 1:
237
+ # presence sensors
237
238
  comp = Component.objects.filter(
238
239
  controller_uid=AmbientLightSensor.uid, config__dali_device=device.id
239
240
  ).first()
@@ -272,4 +273,15 @@ def process_frame(colonel_id, interface_no, data):
272
273
  # was never successfully created
273
274
  if zone_sensors[slot].alive:
274
275
  zone_sensors[slot].alive = False
275
- zone_sensors[slot].save()
276
+ zone_sensors[slot].save()
277
+
278
+ elif frame[8:11] == 2:
279
+ # siren and others
280
+ comp = Component.objects.filter(
281
+ controller_uid=RoomSiren.uid, config__dali_device=device.id
282
+ ).first()
283
+ if comp:
284
+ VALUES_MAP = {
285
+ int_v: str_v for str_v, int_v in RoomSiren.VALUES_MAP.items()
286
+ }
287
+ comp.controller._receive_from_device(VALUES_MAP[frame[12:16]])
simo/fleet/forms.py CHANGED
@@ -689,7 +689,75 @@ class ColonelSwitchConfigForm(ColonelComponentForm):
689
689
  return obj
690
690
 
691
691
 
692
- class ColonelPWMOutputConfigForm(ColonelComponentForm):
692
+ class PWMOutputBaseConfig(ColonelComponentForm):
693
+
694
+ def __init__(self, *args, **kwargs):
695
+ super().__init__(*args, **kwargs)
696
+ if 'value_units' in self.fields:
697
+ self.fields['value_units'].initial = self.controller.default_value_units
698
+ self.basic_fields.extend(
699
+ ['value_units', 'turn_on_time', 'turn_off_time', 'skew']
700
+ )
701
+ if self.instance.pk and 'slaves' in self.fields:
702
+ self.fields['slaves'].initial = self.instance.slaves.all()
703
+
704
+ def clean_slaves(self):
705
+ if not self.cleaned_data['slaves'] or not self.instance:
706
+ return self.cleaned_data['slaves']
707
+ return validate_slaves(self.cleaned_data['slaves'], self.instance)
708
+
709
+ def clean(self):
710
+ super().clean()
711
+ if 'output_pin' in self.cleaned_data:
712
+ self._clean_pin('output_pin')
713
+ if 'controls' in self.cleaned_data:
714
+ self._clean_controls()
715
+
716
+ if self.cleaned_data.get('output_pin') and self.cleaned_data.get('controls'):
717
+ for ctrl in self.cleaned_data['controls']:
718
+ if not ctrl['input'].startswith('pin'):
719
+ continue
720
+ if int(ctrl['input'][4:]) == self.cleaned_data['output_pin'].id:
721
+ self.add_error(
722
+ "output_pin",
723
+ "Can't be used as control pin at the same time!"
724
+ )
725
+ return self.cleaned_data
726
+
727
+
728
+ def save(self, commit=True):
729
+ if 'output_pin' in self.cleaned_data:
730
+ self.instance.config['output_pin_no'] = self.cleaned_data['output_pin'].no
731
+
732
+ update_colonel = False
733
+ if not self.instance.pk:
734
+ update_colonel = True
735
+ elif 'output_pin' in self.changed_data:
736
+ update_colonel = True
737
+ elif 'slaves' in self.changed_data:
738
+ update_colonel = True
739
+ if not update_colonel:
740
+ old = Component.objects.get(id=self.instance.id)
741
+ if old.config.get('controls') != self.cleaned_data.get('controls'):
742
+ update_colonel = True
743
+
744
+ obj = super().save(commit=commit)
745
+ if commit and 'slaves' in self.cleaned_data:
746
+ obj.slaves.set(self.cleaned_data['slaves'])
747
+ if not update_colonel:
748
+ GatewayObjectCommand(
749
+ obj.gateway, self.cleaned_data['colonel'], id=obj.id,
750
+ command='call', method='update_config', args=[
751
+ obj.controller._get_colonel_config()
752
+ ]
753
+ ).publish()
754
+ if commit and self.cleaned_data.get('controls'):
755
+ GatewayObjectCommand(
756
+ self.instance.gateway, obj, command='watch_buttons'
757
+ ).publish()
758
+ return obj
759
+
760
+ class ColonelPWMOutputConfigForm(PWMOutputBaseConfig):
693
761
  output_pin = Select2ModelChoiceField(
694
762
  label="Port",
695
763
  queryset=ColonelPin.objects.filter(output=True),
@@ -758,74 +826,8 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
758
826
  )
759
827
  )
760
828
 
761
- def __init__(self, *args, **kwargs):
762
- super().__init__(*args, **kwargs)
763
- if 'value_units' in self.fields:
764
- self.fields['value_units'].initial = self.controller.default_value_units
765
- self.basic_fields.extend(
766
- ['value_units', 'turn_on_time', 'turn_off_time', 'skew']
767
- )
768
- if self.instance.pk and 'slaves' in self.fields:
769
- self.fields['slaves'].initial = self.instance.slaves.all()
770
-
771
- def clean_slaves(self):
772
- if not self.cleaned_data['slaves'] or not self.instance:
773
- return self.cleaned_data['slaves']
774
- return validate_slaves(self.cleaned_data['slaves'], self.instance)
775
-
776
- def clean(self):
777
- super().clean()
778
- if 'output_pin' in self.cleaned_data:
779
- self._clean_pin('output_pin')
780
- if 'controls' in self.cleaned_data:
781
- self._clean_controls()
782
-
783
- if self.cleaned_data.get('output_pin') and self.cleaned_data.get('controls'):
784
- for ctrl in self.cleaned_data['controls']:
785
- if not ctrl['input'].startswith('pin'):
786
- continue
787
- if int(ctrl['input'][4:]) == self.cleaned_data['output_pin'].id:
788
- self.add_error(
789
- "output_pin",
790
- "Can't be used as control pin at the same time!"
791
- )
792
- return self.cleaned_data
793
-
794
-
795
- def save(self, commit=True):
796
- if 'output_pin' in self.cleaned_data:
797
- self.instance.config['output_pin_no'] = self.cleaned_data['output_pin'].no
798
-
799
- update_colonel = False
800
- if not self.instance.pk:
801
- update_colonel = True
802
- elif 'output_pin' in self.changed_data:
803
- update_colonel = True
804
- elif 'slaves' in self.changed_data:
805
- update_colonel = True
806
- if not update_colonel:
807
- old = Component.objects.get(id=self.instance.id)
808
- if old.config.get('controls') != self.cleaned_data.get('controls'):
809
- update_colonel = True
810
829
 
811
- obj = super().save(commit=commit)
812
- if commit and 'slaves' in self.cleaned_data:
813
- obj.slaves.set(self.cleaned_data['slaves'])
814
- if not update_colonel:
815
- GatewayObjectCommand(
816
- obj.gateway, self.cleaned_data['colonel'], id=obj.id,
817
- command='call', method='update_config', args=[
818
- obj.controller._get_colonel_config()
819
- ]
820
- ).publish()
821
- if commit and self.cleaned_data.get('controls'):
822
- GatewayObjectCommand(
823
- self.instance.gateway, obj, command='watch_buttons'
824
- ).publish()
825
- return obj
826
-
827
-
828
- class DCDriverConfigForm(ColonelComponentForm):
830
+ class DC10VConfigForm(PWMOutputBaseConfig):
829
831
  output_pin = Select2ModelChoiceField(
830
832
  label="Port",
831
833
  queryset=ColonelPin.objects.filter(output=True),
@@ -841,53 +843,60 @@ class DCDriverConfigForm(ColonelComponentForm):
841
843
  help_text="Minimum component value displayed to the user."
842
844
  )
843
845
  max = forms.FloatField(
844
- required=True, initial=24,
846
+ required=True, initial=100,
845
847
  help_text="Maximum component value displayed to the user."
846
848
  )
847
- value_units = forms.CharField(required=False)
849
+ value_units = forms.CharField(required=False, initial='%')
848
850
 
849
851
  device_min = forms.FloatField(
850
852
  label="Device minimum Voltage.",
851
853
  help_text="This will be the lowest possible voltage value of a device.\n"
852
854
  "Don't forget to adjust your component min value accordingly "
853
855
  "if you change this.",
854
- initial=0, min_value=0, max_value=24,
856
+ initial=0, min_value=0, max_value=10,
855
857
  )
856
- device_max = forms.IntegerField(
858
+ device_max = forms.FloatField(
857
859
  label="Device maximum Voltage.",
858
- help_text="Can be set lower than it's natural maximum of 24V. \n"
860
+ help_text="Can be set lower than it's natural maximum of 10V. \n"
859
861
  "Don't forget to adjust your component max value accordingly "
860
862
  "if you change this.",
861
- initial=24, min_value=0, max_value=24,
863
+ initial=10, min_value=0, max_value=10,
862
864
  )
865
+ inverse = forms.BooleanField(required=False, initial=False)
863
866
 
864
- def clean(self):
865
- super().clean()
866
- if 'output_pin' in self.cleaned_data:
867
- self._clean_pin('output_pin')
868
- return self.cleaned_data
869
-
870
-
871
- def save(self, commit=True):
872
- if 'output_pin' in self.cleaned_data:
873
- self.instance.config['output_pin_no'] = self.cleaned_data['output_pin'].no
874
-
875
- update_colonel = False
876
- if not self.instance.pk:
877
- update_colonel = True
878
- elif 'output_pin' in self.changed_data:
879
- update_colonel = True
880
-
881
- obj = super().save(commit=commit)
867
+ turn_on_time = forms.IntegerField(
868
+ min_value=0, max_value=60000, initial=0,
869
+ help_text="Turn on speed in ms. 1500 is a great quick default for controlling lights. "
870
+ "10000 - great slow default."
871
+ )
872
+ turn_off_time = forms.IntegerField(
873
+ min_value=0, max_value=60000, initial=0,
874
+ help_text="Turn off speed in ms. 3000 is a great quick default when controlling lights. "
875
+ "20000 - great slow default"
876
+ )
877
+ skew = forms.ChoiceField(
878
+ initial='linear', choices=EASING_CHOICES,
879
+ help_text="easeOutSine - offers most naturally looking effect for lights."
880
+ )
881
+ on_value = forms.FloatField(
882
+ required=False,
883
+ help_text="Static ON value used to turn on the device with physical controls. <br>"
884
+ "Leaving this field empty turns the device on to the last used value."
885
+ )
882
886
 
883
- if not update_colonel:
884
- GatewayObjectCommand(
885
- obj.gateway, self.cleaned_data['colonel'], id=obj.id,
886
- command='call', method='update_config', args=[
887
- obj.controller._get_colonel_config()
888
- ]
889
- ).publish()
890
- return obj
887
+ slaves = Select2ModelMultipleChoiceField(
888
+ queryset=Component.objects.filter(
889
+ base_type__in=('dimmer',),
890
+ ),
891
+ url='autocomplete-component',
892
+ forward=(forward.Const(['dimmer', ], 'base_type'),),
893
+ required=False
894
+ )
895
+ controls = FormsetField(
896
+ formset_factory(
897
+ ControlForm, can_delete=True, can_order=True, extra=0, max_num=10
898
+ )
899
+ )
891
900
 
892
901
 
893
902
  class ColonelRGBLightConfigForm(ColonelComponentForm):
@@ -1814,6 +1823,7 @@ class CustomDaliDeviceForm(BaseComponentForm):
1814
1823
 
1815
1824
  class RoomSensorDeviceConfigForm(CustomDaliDeviceForm):
1816
1825
 
1826
+
1817
1827
  def save(self, commit=True):
1818
1828
  from simo.core.models import Icon
1819
1829
  colonel = None
@@ -1827,13 +1837,14 @@ class RoomSensorDeviceConfigForm(CustomDaliDeviceForm):
1827
1837
  colonel = device
1828
1838
 
1829
1839
  from .controllers import (
1830
- AirQualitySensor, TempHumSensor, AmbientLightSensor,
1840
+ RoomSiren, AirQualitySensor, TempHumSensor, AmbientLightSensor,
1831
1841
  RoomPresenceSensor
1832
1842
  )
1833
1843
 
1834
1844
  org_name = self.cleaned_data['name']
1835
1845
  org_icon = self.cleaned_data['icon']
1836
1846
  for CtrlClass, icon, suffix in (
1847
+ (RoomSiren, 'siren', 'siren'),
1837
1848
  (AirQualitySensor, 'leaf', 'air quality'),
1838
1849
  (TempHumSensor, 'temperature-half', 'temperature'),
1839
1850
  (AmbientLightSensor, 'brightness-low', 'brightness'),