simo 2.2.9__py3-none-any.whl → 2.2.11__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 (43) hide show
  1. simo/__pycache__/settings.cpython-38.pyc +0 -0
  2. simo/asgi.py +0 -2
  3. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  4. simo/core/__pycache__/forms.cpython-38.pyc +0 -0
  5. simo/core/__pycache__/models.cpython-38.pyc +0 -0
  6. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  7. simo/core/__pycache__/tasks.cpython-38.pyc +0 -0
  8. simo/core/api.py +0 -1
  9. simo/core/forms.py +4 -1
  10. simo/core/management/commands/__pycache__/on_http_start.cpython-38.pyc +0 -0
  11. simo/{management → core/management/commands}/on_http_start.py +10 -6
  12. simo/core/models.py +3 -2
  13. simo/core/tasks.py +0 -4
  14. simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
  15. simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
  16. simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
  17. simo/fleet/__pycache__/utils.cpython-38.pyc +0 -0
  18. simo/fleet/controllers.py +24 -0
  19. simo/fleet/models.py +1 -0
  20. simo/fleet/utils.py +11 -1
  21. simo/management/_hub_template/hub/nginx.conf +14 -2
  22. simo/management/_hub_template/hub/supervisor.conf +17 -2
  23. simo/management/_hub_template/hub/wsgi.py +11 -0
  24. simo/settings.py +0 -1
  25. simo/users/__pycache__/admin.cpython-38.pyc +0 -0
  26. simo/users/__pycache__/api.cpython-38.pyc +0 -0
  27. simo/users/__pycache__/models.cpython-38.pyc +0 -0
  28. simo/users/admin.py +16 -30
  29. simo/users/api.py +12 -5
  30. simo/users/migrations/0030_userdevice_users.py +19 -0
  31. simo/users/migrations/0031_auto_20240923_1115.py +25 -0
  32. simo/users/migrations/0032_remove_userdevice_user_alter_userdevice_users.py +23 -0
  33. simo/users/migrations/__pycache__/0030_userdevice_users.cpython-38.pyc +0 -0
  34. simo/users/migrations/__pycache__/0031_auto_20240923_1115.cpython-38.pyc +0 -0
  35. simo/users/migrations/__pycache__/0032_remove_userdevice_user_alter_userdevice_users.cpython-38.pyc +0 -0
  36. simo/users/models.py +10 -25
  37. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/METADATA +2 -1
  38. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/RECORD +42 -35
  39. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/WHEEL +1 -1
  40. simo/management/__pycache__/on_http_start.cpython-38.pyc +0 -0
  41. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/LICENSE.md +0 -0
  42. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/entry_points.txt +0 -0
  43. {simo-2.2.9.dist-info → simo-2.2.11.dist-info}/top_level.txt +0 -0
Binary file
simo/asgi.py CHANGED
@@ -21,8 +21,6 @@ for name, app in apps.app_configs.items():
21
21
  if isinstance(item, list) and var_name == 'urlpatterns':
22
22
  urlpatterns.extend(item)
23
23
 
24
- from .management.on_http_start import *
25
-
26
24
  application = ProtocolTypeRouter({
27
25
  "http": get_asgi_application(),
28
26
  'websocket': AuthMiddlewareStack(
Binary file
Binary file
Binary file
Binary file
simo/core/api.py CHANGED
@@ -235,7 +235,6 @@ class ComponentViewSet(
235
235
 
236
236
  return RESTResponse(result)
237
237
 
238
- # TODO: remove post when app is updated for all users
239
238
  @action(detail=True, methods=['post'])
240
239
  def subcomponent(self, request, pk=None, *args, **kwargs):
241
240
  component = self.get_object()
simo/core/forms.py CHANGED
@@ -219,7 +219,10 @@ class ComponentAdminForm(forms.ModelForm):
219
219
 
220
220
  class Meta:
221
221
  model = Component
222
- fields = 'name', 'icon', 'zone', 'category', 'show_in_app', 'notes',
222
+ fields = (
223
+ 'name', 'icon', 'zone', 'category', 'show_in_app', 'notes',
224
+ 'alarm_category'
225
+ )
223
226
  widgets = {
224
227
  'icon': autocomplete.ModelSelect2(
225
228
  url='autocomplete-icon', attrs={'data-html': True}
@@ -1,3 +1,4 @@
1
+ from django.core.management.base import BaseCommand
1
2
  import os
2
3
  import pwd
3
4
  import grp
@@ -53,8 +54,6 @@ def prepare_mosquitto():
53
54
  ['service', 'mosquitto', 'reload'], stdout=subprocess.PIPE
54
55
  )
55
56
 
56
- prepare_mosquitto()
57
-
58
57
 
59
58
  def update_auto_update():
60
59
  import simo
@@ -82,9 +81,6 @@ def update_auto_update():
82
81
  cron_out.communicate(input=str.encode(auto_update_cron))
83
82
 
84
83
 
85
- update_auto_update()
86
-
87
-
88
84
  def maybe_update_to_latest_immediately():
89
85
  from simo.core.tasks import update_latest_version_available, update
90
86
  from simo.core.models import Instance
@@ -100,4 +96,12 @@ def maybe_update_to_latest_immediately():
100
96
  "so we leave that for hub owners.")
101
97
 
102
98
 
103
- maybe_update_to_latest_immediately()
99
+
100
+
101
+ class Command(BaseCommand):
102
+
103
+
104
+ def handle(self, *args, **options):
105
+ prepare_mosquitto()
106
+ update_auto_update()
107
+ maybe_update_to_latest_immediately()
simo/core/models.py CHANGED
@@ -12,7 +12,6 @@ from timezone_utils.choices import ALL_TIMEZONES_CHOICES
12
12
  from location_field.models.plain import PlainLocationField
13
13
  from model_utils import FieldTracker
14
14
  from dirtyfields import DirtyFieldsMixin
15
- from actstream import action
16
15
  from simo.core.utils.mixins import SimoAdminMixin
17
16
  from simo.core.storage import OverwriteStorage
18
17
  from simo.core.utils.validators import validate_svg
@@ -386,7 +385,9 @@ def is_in_alarm(self):
386
385
  ('security', _("Security")), ('fire', _("Fire")),
387
386
  ('flood', _("Flood")), ('other', _("Other"))
388
387
  ),
389
- help_text=_("Enable alarm properties by choosing one of alarm categories.")
388
+ help_text=_(
389
+ "Enable alarm properties by choosing one of alarm categories."
390
+ )
390
391
  )
391
392
  arm_status = models.CharField(
392
393
  max_length=20, db_index=True, default='disarmed', choices=(
simo/core/tasks.py CHANGED
@@ -210,7 +210,6 @@ def sync_with_remote():
210
210
  email=email, defaults={
211
211
  'name': options.get('name'),
212
212
  'is_master': options.get('is_hub_master', False),
213
- 'ssh_key': options.get('ssh_key')
214
213
  })
215
214
  role = None
216
215
  if options.get('is_hub_master') or options.get('is_superuser'):
@@ -236,9 +235,6 @@ def sync_with_remote():
236
235
  if user.name != options.get('name'):
237
236
  user.name = options['name']
238
237
  user.save()
239
- if user.ssh_key != options.get('ssh_key'):
240
- user.ssh_key = options['ssh_key']
241
- user.save()
242
238
 
243
239
  avatar_url = options.get('avatar_url')
244
240
  if avatar_url and user.avatar_url != avatar_url:
Binary file
Binary file
simo/fleet/controllers.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  from django.utils.translation import gettext_lazy as _
3
3
  from django.db.transaction import atomic
4
+ from simo.core.middleware import get_current_instance
4
5
  from simo.core.events import GatewayObjectCommand
5
6
  from simo.core.controllers import (
6
7
  BinarySensor as BaseBinarySensor,
@@ -152,6 +153,13 @@ class DS18B20Sensor(FleeDeviceMixin, BasicSensorMixin, BaseNumericSensor):
152
153
  name = "DS18B20 Temperature sensor"
153
154
 
154
155
 
156
+
157
+ # TODO: need to change this to {
158
+ # 'temp': self.sensor.temperature, 'hum': self.sensor.humidity,
159
+ # 'pressure': self.sensor.pressure, 'gas': self.sensor.gas
160
+ # }
161
+ # which is used by BME680Sensor
162
+
155
163
  class BaseClimateSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
156
164
  app_widget = NumericSensorWidget
157
165
 
@@ -194,6 +202,8 @@ class BaseClimateSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
194
202
  return new_val
195
203
 
196
204
 
205
+
206
+
197
207
  class DHTSensor(BaseClimateSensor):
198
208
  config_form = ColonelDHTSensorConfigForm
199
209
  name = "DHT climate sensor"
@@ -210,6 +220,20 @@ class MPC9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
210
220
  config_form = MPC9808SensorConfigForm
211
221
  name = "MPC9808 Temperature Sensor (I2C)"
212
222
 
223
+ @property
224
+ def default_value_units(self):
225
+ instance = get_current_instance()
226
+ if not instance:
227
+ return 'C'
228
+ if instance.units_of_measure == 'imperial':
229
+ return 'F'
230
+ return 'C'
231
+
232
+ def _prepare_for_set(self, value):
233
+ if self.component.zone.instance.units_of_measure == 'imperial':
234
+ return round((value[0][1] * 9 / 5) + 32, 1)
235
+ return value
236
+
213
237
 
214
238
  class ENS160AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
215
239
  gateway_class = FleetGatewayHandler
simo/fleet/models.py CHANGED
@@ -58,6 +58,7 @@ class Colonel(DirtyFieldsMixin, models.Model):
58
58
  ('4-relays', "4 Relay"),
59
59
  ('ample-wall', "Ample Wall"),
60
60
  ('game-changer', "Game Changer"),
61
+ ('game-changer-mini', "Game Changer Mini"),
61
62
  )
62
63
  )
63
64
  firmware_version = models.CharField(
simo/fleet/utils.py CHANGED
@@ -54,7 +54,10 @@ BASE_ESP32_GPIO_PINS = {
54
54
  39: {'output': False, 'adc': True},
55
55
  }
56
56
 
57
- GPIO_PINS = {'generic': {}, '4-relays': {}, 'ample-wall': {}, 'game-changer': {}}
57
+ GPIO_PINS = {
58
+ 'generic': {}, '4-relays': {}, 'ample-wall': {},
59
+ 'game-changer': {}, 'game-changer-mini': {}
60
+ }
58
61
 
59
62
  for no, data in BASE_ESP32_GPIO_PINS.items():
60
63
  GPIO_PINS['generic'][no] = GPIO_PIN_DEFAULTS.copy()
@@ -90,6 +93,13 @@ for no in range(101, 139):
90
93
  'capacitive': False, 'note': ''
91
94
  }
92
95
 
96
+ for no in range(101, 105):
97
+ GPIO_PINS['game-changer-mini'][no] = {
98
+ 'output': True, 'input': True, 'default_pull': 'LOW',
99
+ 'native': False, 'adc': False,
100
+ 'capacitive': False, 'note': ''
101
+ }
102
+
93
103
 
94
104
  #4-relays
95
105
  for no, data in BASE_ESP32_GPIO_PINS.items():
@@ -23,6 +23,7 @@ server{
23
23
  expires max;
24
24
  }
25
25
 
26
+ # daphne
26
27
  location /ws {
27
28
  include proxy_params;
28
29
 
@@ -32,9 +33,14 @@ server{
32
33
  proxy_pass http://unix:/tmp/http.sock;
33
34
  }
34
35
 
36
+ # gunicorn
35
37
  location / {
36
38
  include proxy_params;
37
- proxy_pass http://unix:/tmp/http.sock;
39
+ proxy_connect_timeout 600;
40
+ proxy_send_timeout 600;
41
+ proxy_read_timeout 600;
42
+ send_timeout 600;
43
+ proxy_pass http://unix:/tmp/gunicorn.sock;
38
44
  }
39
45
  }
40
46
 
@@ -74,6 +80,7 @@ server{
74
80
  expires max;
75
81
  }
76
82
 
83
+ # daphne
77
84
  location /ws {
78
85
  include proxy_params;
79
86
 
@@ -83,9 +90,14 @@ server{
83
90
  proxy_pass http://unix:/tmp/http.sock;
84
91
  }
85
92
 
93
+ # gunicorn
86
94
  location / {
87
95
  include proxy_params;
88
- proxy_pass http://unix:/tmp/http.sock;
96
+ proxy_connect_timeout 600;
97
+ proxy_send_timeout 600;
98
+ proxy_read_timeout 600;
99
+ send_timeout 600;
100
+ proxy_pass http://unix:/tmp/gunicorn.sock;
89
101
  }
90
102
 
91
103
  }
@@ -1,15 +1,30 @@
1
- [program:simo-http]
1
+ # using gunicorn for regular requests
2
+ [program:simo-gunicorn]
3
+ directory={{ project_dir }}/hub/
4
+ command=/bin/sh -c "/usr/bin/python3 manage.py on_http_start && /usr/local/bin/gunicorn --workers 4 --timeout 120 --bind unix:/tmp/gunicorn.sock wsgi:application"
5
+ process_name=%(program_name)s
6
+ user=root
7
+ stdout_logfile=/var/log/simo/gunicorn.log
8
+ stdout_logfile_maxbytes=1MB
9
+ stdout_logfile_backups=3
10
+ redirect_stderr=true
11
+ autostart=true
12
+ autorestart=true
13
+
14
+ # using daphne for socket connections routed to /ws/ on nginx.conf
15
+ [program:simo-daphne]
2
16
  directory={{ project_dir }}/hub/
3
17
  command=/usr/local/bin/daphne -u /tmp/http.sock --access-log /dev/stdout --proxy-headers asgi:application
4
18
  process_name=%(program_name)s
5
19
  user=root
6
- stdout_logfile=/var/log/simo/http.log
20
+ stdout_logfile=/var/log/simo/daphne.log
7
21
  stdout_logfile_maxbytes=1MB
8
22
  stdout_logfile_backups=3
9
23
  redirect_stderr=true
10
24
  autostart=true
11
25
  autorestart=true
12
26
 
27
+
13
28
  [program:simo-gateways]
14
29
  command=/usr/bin/python3 {{ project_dir }}/hub/manage.py gateways_manager
15
30
  process_name=%(program_name)s
@@ -0,0 +1,11 @@
1
+ """
2
+ WSGI config for SIMO.io project.
3
+
4
+ It exposes the WSGI callable as a module-level variable named ``application``.
5
+ """
6
+ import os
7
+ from django.core.wsgi import get_wsgi_application
8
+
9
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
10
+
11
+ application = get_wsgi_application()
simo/settings.py CHANGED
@@ -197,7 +197,6 @@ REST_FRAMEWORK = {
197
197
 
198
198
  REDIS_DB = {
199
199
  'celery': 0, 'default_cache': 1, 'select2_cache': 2,
200
- 'fleet_rs485': 11, 'fleet_wifi': 12
201
200
  }
202
201
 
203
202
  CACHES = {
Binary file
Binary file
simo/users/admin.py CHANGED
@@ -46,22 +46,6 @@ class PermissionsRoleAdmin(admin.ModelAdmin):
46
46
  return fields
47
47
 
48
48
 
49
- class UserDeviceInline(admin.TabularInline):
50
- model = UserDevice
51
- extra = 0
52
- readonly_fields = 'token', 'os', 'last_seen', 'is_primary', 'more'
53
- fields = readonly_fields
54
-
55
- def has_delete_permission(self, request, obj=None):
56
- return False
57
-
58
- def has_add_permission(self, request, obj=None):
59
- return False
60
-
61
- def more(self, obj):
62
- return mark_safe('<a href="%s">more >></a>' % obj.get_admin_url())
63
-
64
-
65
49
  class InstanceUserInline(admin.TabularInline):
66
50
  model = InstanceUser
67
51
  extra = 0
@@ -84,10 +68,9 @@ class UserAdmin(OrgUserAdmin):
84
68
  'last_seen_location',
85
69
  )
86
70
  readonly_fields = (
87
- 'name', 'email', 'avatar',
88
- 'last_action', 'ssh_key', 'is_active'
71
+ 'name', 'email', 'avatar', 'last_action', 'is_active'
89
72
  )
90
- inlines = UserDeviceInline, InstanceUserInline
73
+ inlines = InstanceUserInline,
91
74
 
92
75
  def name_display(self, obj=None):
93
76
  if not obj:
@@ -129,20 +112,18 @@ admin.site.unregister(Group)
129
112
  @admin.register(UserDeviceReportLog)
130
113
  class UserDeviceLogInline(admin.ModelAdmin):
131
114
  model = UserDeviceReportLog
132
- readonly_fields = 'datetime', 'app_open', 'location', 'relay', 'user'
133
- list_display = 'datetime', 'app_open', 'location', 'relay', 'user'
115
+ readonly_fields = 'datetime', 'app_open', 'location', 'relay', 'users'
116
+ list_display = 'datetime', 'app_open', 'location', 'relay', 'users'
134
117
  fields = readonly_fields
135
- list_filter = 'user_device__user',
136
118
 
137
119
  def has_add_permission(self, request, obj=None):
138
120
  return False
139
121
 
140
- def user(self, obj):
141
- return mark_safe(
142
- f'<a href="{obj.user_device.user.get_admin_url()}">'
143
- f'{obj.user_device.user}'
144
- f'</a>'
145
- )
122
+ def users(self, obj):
123
+ return mark_safe(', '.join([
124
+ f'<a href="{user.get_admin_url()}">{user}</a>'
125
+ for user in obj.user_device.users.all()
126
+ ]))
146
127
 
147
128
  def get_queryset(self, request):
148
129
  qs = super().get_queryset(request)
@@ -155,9 +136,9 @@ class UserDeviceLogInline(admin.ModelAdmin):
155
136
 
156
137
  @admin.register(UserDevice)
157
138
  class UserDeviceAdmin(admin.ModelAdmin):
158
- list_display = 'token', 'os', 'last_seen', 'is_primary', 'user'
139
+ list_display = 'token', 'os', 'last_seen', 'is_primary', 'users_display'
159
140
  readonly_fields = (
160
- 'user', 'token', 'os', 'last_seen',
141
+ 'users_display', 'token', 'os', 'last_seen',
161
142
  )
162
143
  fields = readonly_fields + ('last_seen_location', 'is_primary')
163
144
 
@@ -167,6 +148,11 @@ class UserDeviceAdmin(admin.ModelAdmin):
167
148
  return qs
168
149
  return qs.filter(user__role__instance__in=request.user.instances)
169
150
 
151
+ def users_display(self, obj):
152
+ return ', '.join([str(u) for u in obj.users.all()])
153
+ users_display.short_description = 'Users'
154
+
155
+
170
156
 
171
157
  @admin.register(InstanceInvitation)
172
158
  class InstanceInvitationAdmin(admin.ModelAdmin):
simo/users/api.py CHANGED
@@ -37,7 +37,7 @@ class UsersViewSet(mixins.RetrieveModelMixin,
37
37
 
38
38
  return queryset.filter(
39
39
  Q(roles__instance=self.instance) | Q(id=self.request.user.id)
40
- )
40
+ ).distinct()
41
41
 
42
42
 
43
43
  def check_permission_to_change(self, request, target_user):
@@ -160,14 +160,13 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
160
160
  status=status.HTTP_400_BAD_REQUEST
161
161
  )
162
162
 
163
- defaults = {'os': request.data['os'], 'user': request.user}
163
+ defaults = {'os': request.data['os']}
164
164
  user_device, new = UserDevice.objects.get_or_create(
165
165
  token=request.data['device_token'],
166
166
  defaults=defaults
167
167
  )
168
- if not new:
169
- for key, val in defaults.items():
170
- setattr(user_device, key, val)
168
+ user_device.users.add(request.user)
169
+
171
170
  try:
172
171
  location = Point(
173
172
  *[float(c) for c in request.data.get('location').split(',')],
@@ -181,10 +180,18 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
181
180
  user_device.last_seen_location = ','.join(
182
181
  [str(i) for i in location]
183
182
  ) if location else None
183
+
184
184
  if request.data.get('app_open', False):
185
185
  user_device.is_primary = True
186
+ UserDevice.objects.filter(
187
+ users=request.user
188
+ ).exclude(id=user_device.id).update(is_primary=False)
186
189
  user_device.save()
187
190
 
191
+ request.user.last_seen_location = user_device.last_seen_location
192
+ request.user.last_seen_location_datetime = user_device.last_seen
193
+ request.user.save()
194
+
188
195
  relay = None
189
196
  if request.META.get('HTTP_HOST', '').endswith('.simo.io'):
190
197
  relay = request.META.get('HTTP_HOST')
@@ -0,0 +1,19 @@
1
+ # Generated by Django 4.2.10 on 2024-09-23 11:15
2
+
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('users', '0029_alter_instanceuser_instance'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='userdevice',
16
+ name='users',
17
+ field=models.ManyToManyField(to=settings.AUTH_USER_MODEL),
18
+ ),
19
+ ]
@@ -0,0 +1,25 @@
1
+ # Generated by Django 4.2.10 on 2024-09-23 10:54
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ def forwards_func(apps, schema_editor):
7
+ UserDevice = apps.get_model("users", "UserDevice")
8
+
9
+ for ud in UserDevice.objects.all():
10
+ ud.users.add(ud.user)
11
+
12
+
13
+ def reverse_func(apps, schema_editor):
14
+ pass
15
+
16
+
17
+ class Migration(migrations.Migration):
18
+
19
+ dependencies = [
20
+ ('users', '0030_userdevice_users'),
21
+ ]
22
+
23
+ operations = [
24
+ migrations.RunPython(forwards_func, reverse_func, elidable=True),
25
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 4.2.10 on 2024-09-23 11:40
2
+
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('users', '0031_auto_20240923_1115'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.RemoveField(
15
+ model_name='userdevice',
16
+ name='user',
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='userdevice',
20
+ name='users',
21
+ field=models.ManyToManyField(related_name='devices', to=settings.AUTH_USER_MODEL),
22
+ ),
23
+ ]
simo/users/models.py CHANGED
@@ -164,9 +164,8 @@ class User(AbstractBaseUser, SimoAdminMixin):
164
164
  )
165
165
  ssh_key = models.TextField(
166
166
  null=True, blank=True,
167
- help_text="DO NOT EDIT IT MANUALLY! Comes from SIMO.io. <br>"
168
- "Will be placed in /root/.ssh/authorized_keys "
169
- "if user is active and has superuser rights."
167
+ help_text="Will be placed in /root/.ssh/authorized_keys "
168
+ "if user is active and is master of a hub."
170
169
  )
171
170
  last_seen_location = PlainLocationField(
172
171
  zoom=7, null=True, blank=True, help_text="Sent by user mobile app"
@@ -390,22 +389,13 @@ class Fingerprint(models.Model):
390
389
 
391
390
 
392
391
  class UserDevice(models.Model, SimoAdminMixin):
393
- user = models.ForeignKey(
394
- User, on_delete=models.CASCADE, related_name='devices'
395
- )
392
+ users = models.ManyToManyField(User, related_name='devices')
396
393
  os = models.CharField(max_length=100, db_index=True)
397
394
  token = models.CharField(max_length=1000, db_index=True, unique=True)
398
395
  is_primary = models.BooleanField(default=True, db_index=True)
399
396
  last_seen = models.DateTimeField(auto_now_add=True, db_index=True)
400
397
  last_seen_location = PlainLocationField(zoom=7, null=True, blank=True)
401
398
 
402
- def save(self, *args, **kwargs):
403
- if self.is_primary:
404
- UserDevice.objects.filter(user=self.user).exclude(
405
- pk=self.pk
406
- ).update(is_primary=False)
407
- return super().save(*args, **kwargs)
408
-
409
399
  class Meta:
410
400
  ordering = '-last_seen',
411
401
 
@@ -437,21 +427,15 @@ def set_user_at_home(sender, instance, created, **kwargs):
437
427
  if not created:
438
428
  return
439
429
 
440
- if not instance.relay:
441
- for item in InstanceUser.objects.filter(user=instance.user_device.user):
430
+ if not instance.location and not instance.relay:
431
+ for item in InstanceUser.objects.filter(
432
+ user__in=instance.user_device.users.all()
433
+ ):
442
434
  item.at_home = True
443
435
  item.save()
444
436
  return
445
- if not instance.location:
446
- return
447
-
448
- instance.user_device.last_seen_location = instance.location
449
- instance.user_device.save()
450
- instance.user_device.user.last_seen_location = instance.location
451
- instance.user_device.user.last_seen_location_datetime = timezone.now()
452
- instance.user_device.user.save()
453
437
 
454
- for hub_instance in Instance.objects.all():
438
+ for hub_instance in Instance.objects.filter(is_active=True):
455
439
  try:
456
440
  instance_location = Point(
457
441
  [float(hub_instance.location.split(',')[0]),
@@ -471,7 +455,8 @@ def set_user_at_home(sender, instance, created, **kwargs):
471
455
  return
472
456
  else:
473
457
  for item in InstanceUser.objects.filter(
474
- user=instance.user_device.user, instance=hub_instance
458
+ user__in=instance.user_device.users.all(),
459
+ instance=hub_instance
475
460
  ):
476
461
  item.at_home = distance(
477
462
  instance_location, log_location
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.2.9
3
+ Version: 2.2.11
4
4
  Summary: Smart Home on Steroids!
5
5
  Author-email: Simanas Venčkauskas <simanas@simo.io>
6
6
  Project-URL: Homepage, https://simo.io
@@ -48,4 +48,5 @@ Requires-Dist: daphne ==4.1.2
48
48
  Requires-Dist: Pillow ==9.5.0
49
49
  Requires-Dist: django-markdownify ==0.9.5
50
50
  Requires-Dist: django-activity-stream ==2.0.0
51
+ Requires-Dist: gunicorn ==23.0.0
51
52
 
@@ -1,20 +1,20 @@
1
1
  simo/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
2
- simo/asgi.py,sha256=RphoxqFJjh8Tm8RGC2ztDfFedCyn3a3JQwsLMdAtuaM,863
2
+ simo/asgi.py,sha256=L8CUVZLM32IMzWDZ4IShdDN-m69t7oxAUeHods4-xNM,822
3
3
  simo/celeryc.py,sha256=eab7_e9rw0c__DCeoUFUh_tjAGVlulxVrk75BaJf57Q,1512
4
4
  simo/conf.py,sha256=H2BhXAV8MEDVXF8AbkaLSfR4ULd-9_bS4bnhE5sE5fg,112
5
5
  simo/scripting.py,sha256=PVIkGsiMDWj4CNTbOM3rq7pJ6ruavuns-ZMU7VudLa4,923
6
- simo/settings.py,sha256=p1T_M-eooNjIAcqRPTYsQRMTRNeOAgi24ZJ703nYKh4,6953
6
+ simo/settings.py,sha256=E3hOPNASGnoNvhw_K3GbApsHjCnskJgEyeWYIQlEdxE,6913
7
7
  simo/urls.py,sha256=fRmAsNQ_pzFloimLmxNeDcR6hHRJ3rOoZ3kGy8zOQ_A,2402
8
8
  simo/__pycache__/__init__.cpython-38.pyc,sha256=j81de0BqHMr6bs0C7cuYrXl7HwtK_vv8hDEtAdSwDJc,153
9
9
  simo/__pycache__/asgi.cpython-38.pyc,sha256=UI_puPxc6q4otRqtz0IALTwrh00975iGxc0UyQgLreQ,891
10
10
  simo/__pycache__/celeryc.cpython-38.pyc,sha256=eSRoaKwfYlxVaxAiwqpQ2ndEcx7W-VpZtbxRFSV8UYg,1653
11
11
  simo/__pycache__/conf.cpython-38.pyc,sha256=MYP2yk3ULxiYwZsZR6tCLjKnU-z03A3avzQzIn66y3k,273
12
- simo/__pycache__/settings.cpython-38.pyc,sha256=ZdhdXOZPZOAljVIHlClO3YFQLpRlqi4LnwLKXcoCcRk,6108
12
+ simo/__pycache__/settings.cpython-38.pyc,sha256=FOalzITYVDHyqsGfbl8zNws0oBITfcs5XgHPao0QyLg,6065
13
13
  simo/__pycache__/urls.cpython-38.pyc,sha256=u0x6EqT8S1YfDOSPgbI8Kf-RDlveY9OV-EDXMYKAQ7w,2125
14
14
  simo/__pycache__/wsgi.cpython-38.pyc,sha256=TpRxO7VM_ql31hbKphVdanydC5RI1nHB4l0QA2pdWxo,322
15
15
  simo/core/__init__.py,sha256=_s2TjJfQImsMrTIxqLAx9AZie1Ojmm6sCHASdl3WLGU,50
16
16
  simo/core/admin.py,sha256=hoJ0OhfWL9T0d6JCY6_Gm3GR-nrgtDR2UQM67rMsjiE,18141
17
- simo/core/api.py,sha256=bA_dw4JRNQvmQ7yyet7P2nrIfTy86L0rlCsGE6VtUnA,28010
17
+ simo/core/api.py,sha256=laWtqQUL0ngjTtdDGqcUH42WYzWd9WYJwcKL3yCsDk4,27952
18
18
  simo/core/api_auth.py,sha256=vCxvczA8aWNcW0VyKs5WlC_ytlqeGP_H_hkKUNVkCwM,1247
19
19
  simo/core/api_meta.py,sha256=EaiY-dCADP__9MvLpoHvhjytFT92IrxPZDv95xgqasU,4955
20
20
  simo/core/app_widgets.py,sha256=4Lh9FDzdkfh_mccJMe09dyRTT3Uqf9VXwbkurJ9E9oQ,2115
@@ -28,26 +28,26 @@ simo/core/dynamic_settings.py,sha256=U9pY7p_hoeD1LxobIvxZqQ7Zn_4MhYMqZvsr4O0PAYs
28
28
  simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
29
29
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
30
30
  simo/core/form_fields.py,sha256=9tIjiEN3IE55GPyB4tOlfkd51JDne3-h8pKhpL3tLFE,2220
31
- simo/core/forms.py,sha256=AE-WWLOCH1O2TkhGzmYX2yr3QZJEB4mVh111SLVBuys,21851
31
+ simo/core/forms.py,sha256=sFVz8tENhi4QSudORu_e5tlGEC0aXumy6wzJqQNYBPk,21904
32
32
  simo/core/gateways.py,sha256=m0eS3XjVe34Dge6xtoCq16kFWCKJcdQrT0JW0REqoq8,3715
33
33
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
34
34
  simo/core/managers.py,sha256=n-b3I4uXzfHKTeB1VMjSaMsDUxp8FegFJwnbV1IsWQ4,3019
35
35
  simo/core/middleware.py,sha256=LIMpHJDQ4zx9dfmy5z0-rEW2EPO9d-iG1ZJbJ_6t6hc,1927
36
- simo/core/models.py,sha256=Mg6UjGQjA5WtxO2kq9fO-iW2f9UzDh58etcZ9-X5RSU,21570
36
+ simo/core/models.py,sha256=hQA8SeAPtGRSs4gk-bci2Ni3ZANtS62V-IDgCyJh2qE,21563
37
37
  simo/core/permissions.py,sha256=v0iJM4LOeYoEfMiw3OLPYio272G1aUEAg_z9Wd1q5m0,2993
38
38
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
39
39
  simo/core/serializers.py,sha256=quXznnTKCm57rvRgke0mBnlWmaO8C5scJ8R251wa1jY,20869
40
40
  simo/core/signal_receivers.py,sha256=9-qFCCeSLcMFEMg6QUtKOVgUsoNoqhzGoI98nuNSTEo,6228
41
41
  simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
42
42
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
43
- simo/core/tasks.py,sha256=BAnCnNPuHtZQL9CG4n_e6G_aKL0aZBZFjp-HOWQg4O0,14049
43
+ simo/core/tasks.py,sha256=pWVq9JGbZQIjwiG02KkfAqyAL8cYAiSA7AWJZbKFYfc,13846
44
44
  simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
45
45
  simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
46
46
  simo/core/views.py,sha256=VVqfEPzK0EdbVMMarkG8rd7cODG5QHpXnr3e8UdrTQE,2600
47
47
  simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
48
48
  simo/core/__pycache__/__init__.cpython-38.pyc,sha256=ZJFM_XN0RmJMULQulgA_wFiOnEtsMoedcOWnXjH-Y8o,208
49
49
  simo/core/__pycache__/admin.cpython-38.pyc,sha256=c5Q8YfIiLk25yVCxQvNsH-lwuOwfQa88X6xDYjOBogU,13428
50
- simo/core/__pycache__/api.cpython-38.pyc,sha256=RKwWpa0RqwMqDJ9U9AE6JIzrjIknt-Lsv0ZqENf6UzU,21838
50
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=Fs0SFPiz8rA0zUUDGEGnY6EAZuPuvwtvx9yByf6O3uQ,21838
51
51
  simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=6M9Cl_ha4y_Vf8Rv4GMYL8dcBCmp0KzYi6jn3SQTgys,1712
52
52
  simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=VYx5ZeDyNBI4B_CBEIhV5B3GnLsMOx9s3rNZTSMODco,3703
53
53
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=vUCEAYqppjgRZYMs6pTuSxWWuZxreLygPuPBGw044dQ,3643
@@ -61,19 +61,19 @@ simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=9ge2uV4QBKdA4f2pIZp
61
61
  simo/core/__pycache__/events.cpython-38.pyc,sha256=A1Axx-qftd1r7st7wkO3DkvTdt9-RkcJe5KJhpzJVk8,5109
62
62
  simo/core/__pycache__/filters.cpython-38.pyc,sha256=VIMADCBiYhziIyRmxAyUDJluZvuZmiC4bNYWTRsGSao,721
63
63
  simo/core/__pycache__/form_fields.cpython-38.pyc,sha256=u0voKXkA64xbH6LY_-jMBHQS4mOJZZeuB9WTvtv9JWE,3433
64
- simo/core/__pycache__/forms.cpython-38.pyc,sha256=yK5bcsGXG9QAi965Kg4jjKA6Wbi0nzluNStWjDVjIPQ,17887
64
+ simo/core/__pycache__/forms.cpython-38.pyc,sha256=JDCNYJQrZHUaMb4qZ6A0f1JptoCHQK1yfJwMJlhV7fI,17892
65
65
  simo/core/__pycache__/gateways.cpython-38.pyc,sha256=D1ooHL-iSpQrxnD8uAl4xWFJmm-QWZfbkLiLlFOMtdU,4553
66
66
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
67
67
  simo/core/__pycache__/managers.cpython-38.pyc,sha256=6RTIxyjOgpQGtAqcUyE2vFPS09w1V5Wmd_vOV7rHRRI,3370
68
68
  simo/core/__pycache__/middleware.cpython-38.pyc,sha256=UZTX3tUUHkigr_3GiSLbUX3RbJBg1_JBPiXy6saJ9GA,1911
69
- simo/core/__pycache__/models.cpython-38.pyc,sha256=rKg-_vQ-3L3_NKbCd0HIij7Nyev1t7SOz32-6PS4Rds,17907
69
+ simo/core/__pycache__/models.cpython-38.pyc,sha256=h_neN4zzReOTuou4NX9RbgVJ8T47z0tLqSr37Fm1iHU,17874
70
70
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=fH4iyqd9DdzRLEu2b621-FeM-napR0M7hzBUTHo9Q3g,2972
71
71
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
72
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=g2xW2Epw2ne2qUS41Dsrvr9Ih56v5Ba0VfmetJJRlXk,19495
72
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=PzKJTctrfXeTtD1QlRL5vKKIW4YxB5MuEPj_Z2w9Wgc,19495
73
73
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=3Bt9S47DR_ZFS3O-crElFgLLXPIYyDgPIc2ibwEkaic,4904
74
74
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=NJUr7nRyHFvmAumxxWpsod5wzVVZM99rCEuJs1utHA4,8432
75
75
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
76
- simo/core/__pycache__/tasks.cpython-38.pyc,sha256=O3FjdRHaMDFiuOGMCrzaMjNYSpekogYXbEzD8IUfkv0,9604
76
+ simo/core/__pycache__/tasks.cpython-38.pyc,sha256=WHUW2vB78F0J-E_JX5SNW8Yieugam8Jqerg88NRJTDE,9533
77
77
  simo/core/__pycache__/todos.cpython-38.pyc,sha256=lOqGZ58siHM3isoJV4r7sg8igrfE9fFd-jSfeBa0AQI,253
78
78
  simo/core/__pycache__/views.cpython-38.pyc,sha256=D7X_fFxYySe-mKNB4bEnIt9ubYM7CbbRcIpX52Ou4RE,2809
79
79
  simo/core/__pycache__/widgets.cpython-38.pyc,sha256=sR0ZeHCHrhnNDBJuRrxp3zUsfBp0xrtF0xrK2TkQv1o,3520
@@ -130,10 +130,12 @@ simo/core/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
130
130
  simo/core/management/__pycache__/__init__.cpython-38.pyc,sha256=Ptf1WzljXMt3wP1tzOy6q3JfLERYDs66wSHBVdrzjHg,169
131
131
  simo/core/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  simo/core/management/commands/gateways_manager.py,sha256=a_JmUG1SPJhbhPh5QdViCT5DL0YvKQH-KsO8ptLhB34,6970
133
+ simo/core/management/commands/on_http_start.py,sha256=FuSm3pEOB4gfO_GFtx8lZXaeZaYnA6HbrEmtgoZF8-k,3457
133
134
  simo/core/management/commands/run_gateway.py,sha256=bp0FQQoBeOSoxjHCCMicDL1fxPZZGyLgnq2QKht3bJo,645
134
135
  simo/core/management/commands/update.py,sha256=Y2_6EL8E757nr-MjSuIpdSsEItI0yN42DT5P1e1zkno,175
135
136
  simo/core/management/commands/__pycache__/__init__.cpython-38.pyc,sha256=WKpfZZpAB9D7U4X6oWQIrU_H-6rUmq8Gl9fj9XaY2fw,178
136
137
  simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc,sha256=pgEJdchhOcqKCpjdRMeF0_QKJfMmfSkl_W4TUwcgS9o,6031
138
+ simo/core/management/commands/__pycache__/on_http_start.cpython-38.pyc,sha256=LQeFW3oYYRrEPEcGghyeahFE114-4VbnKH4XaVGcQcg,3235
137
139
  simo/core/migrations/0001_initial.py,sha256=0Uy7IqJxQQYlurs8Mw_RJy7NaWS7BU0VFmZBBz8YkQI,9220
138
140
  simo/core/migrations/0002_load_icons.py,sha256=s9TtGo5NWEyWV3BspfbDNAlWqmQWxmDj7GjEaJXruFk,2044
139
141
  simo/core/migrations/0003_create_default_zones_and_categories.py,sha256=g7Ee6_gLQvrhM9u2tgLpcYTN5xmsRtuvU3_Ya3yoxqM,395
@@ -10191,16 +10193,16 @@ simo/fleet/api.py,sha256=Hxn84xI-Q77HxjINgRbjSJQOv9jii4OL20LxK0VSrS8,2499
10191
10193
  simo/fleet/auto_urls.py,sha256=UX66eR2ykMqFgfIllW-RTdjup5-FieCWl_BVm3CcXKg,702
10192
10194
  simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
10193
10195
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10194
- simo/fleet/controllers.py,sha256=9IJnT6ATuKsfIAh7oTJgSZCY2c9HVIOBLqd0CQ3mjC4,29790
10196
+ simo/fleet/controllers.py,sha256=NOoM7XmMIJfqw92JE5PI6sQo-Vlzb67YDMtebUW7T9k,30507
10195
10197
  simo/fleet/forms.py,sha256=YF34ZCDbLeAKpq4u0KTi8IsyqhDtNUWcal2DELRayuI,57668
10196
10198
  simo/fleet/gateways.py,sha256=lKEJW0MgaOEiNnijH50DNSVChvaUT3TA3UurcI57P8k,5677
10197
10199
  simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
10198
- simo/fleet/models.py,sha256=t_oi6EYSkg8Y5p3trJPv4MqW6AyUcylge9Bfw83mWCg,16462
10200
+ simo/fleet/models.py,sha256=dJYDTHBz1OizzP51G0fdKHSuW98CsqBX-NhgjcVqYHY,16518
10199
10201
  simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
10200
10202
  simo/fleet/serializers.py,sha256=-16BjY_bp9VbDOYuD0V54h7r_RHpuLNkJX0SydWL9aU,2247
10201
10203
  simo/fleet/socket_consumers.py,sha256=aBNTxvYIw5a5l2ns9x0LnjVJvp4NValEJG4MT4hGAT0,17903
10202
10204
  simo/fleet/tasks.py,sha256=AGq9BXFNAqkhOANsPvId8yjEbDtVCB3MRsi_AKDpgIM,821
10203
- simo/fleet/utils.py,sha256=BYqvLexbIJzBdPVPsPuMfkrzM0zHVwo0HPkCFBxOJEQ,4455
10205
+ simo/fleet/utils.py,sha256=4RaoxyOByh3_Svb-WgTdQjG6R6ZGRN4Zf7-daFc4H80,4708
10204
10206
  simo/fleet/views.py,sha256=OzsumjMjjt2WEXuThBzSAHcTNLU2dyBtvz4IyeHoAaA,3226
10205
10207
  simo/fleet/__pycache__/__init__.cpython-38.pyc,sha256=pIZE7EL6-cuJ3pQtaSwjKLrKLsTYelp1k9sRhXKLh6s,159
10206
10208
  simo/fleet/__pycache__/admin.cpython-38.pyc,sha256=IqVvpyyOnHChnEc07GubvtH6Tk1PA0rcYGYrJDg0hm4,6503
@@ -10208,16 +10210,16 @@ simo/fleet/__pycache__/api.cpython-38.pyc,sha256=rL9fb7cCQatyFvXyKmlNOKmxVo8vHYe
10208
10210
  simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=Tc6a6BCXHjijP8U2jE2ghlJwnSNrGm59-hW5t-80wF0,689
10209
10211
  simo/fleet/__pycache__/base_types.cpython-38.pyc,sha256=deyPwjpT6xZiFxBGFnj5b7R-lbdOTh2krgpJhrcGVhc,274
10210
10212
  simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
10211
- simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=PXWcEzGvEVtaKfQah35liipySnaGpswwyDG_MKm5phU,24860
10212
- simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=8Pl_cztv5iYmIySOFqiCk3NnVAvIu7os0-r5OjI05iA,39066
10213
+ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=Pot0NMkAvOR6YEX0UYVApcGlLzLQWS-zWSa7byDL8Zc,25373
10214
+ simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=LOxl1jynQbd_36Qa8eyTRkHLXiA575Ph29XVqGX0qsU,39066
10213
10215
  simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=0RKVn0ndreVKhsrukqeLPSdMnRrsQ_W7yeVeBkRLfIk,5058
10214
10216
  simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
10215
- simo/fleet/__pycache__/models.cpython-38.pyc,sha256=GZ01BjdvTn6_XJBfV8VrSldJ67X06ne-xW4CsQ6N6Wc,13756
10217
+ simo/fleet/__pycache__/models.cpython-38.pyc,sha256=pEiMWANjJpKXSR60PosKCUQOKpo6tSvCeWX4VP-0Lns,13796
10216
10218
  simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
10217
10219
  simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=9ljhwoHkolcVrJwOVbYCbGPAUKgALRwor_M3W_K0adE,3173
10218
10220
  simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=oAnUJbrKjhC3-G-o4F-bx3ZztQf7JhmHi-Sh3cm4-4s,13549
10219
10221
  simo/fleet/__pycache__/tasks.cpython-38.pyc,sha256=RoNxL2WUiW67s9O9DjaYVVjCBSZu2nje0Qn9FJkWVS0,1116
10220
- simo/fleet/__pycache__/utils.cpython-38.pyc,sha256=e-cajNdKJjfBbZ9LdO7KUIccafp1xIIrVosjzM2v1BQ,3239
10222
+ simo/fleet/__pycache__/utils.cpython-38.pyc,sha256=J2N68RzYUnzFeqKH50x9Vtrwd3nrkMKBWOfD99IvfIs,3344
10221
10223
  simo/fleet/__pycache__/views.cpython-38.pyc,sha256=qwW2t_SNX7lLBS1RvYuxYBk9XRkeUcir5O5VYcrjMLY,3136
10222
10224
  simo/fleet/migrations/0001_initial.py,sha256=lce8nkD8Sz6pYr-XJSpDm4CMDuB6TA__WtnHpIp-eA4,1326
10223
10225
  simo/fleet/migrations/0002_auto_20220422_0743.py,sha256=sFOfAjnQOzcJjE8lHrrHgTaGilJNYswMdXphgVzUZqY,825
@@ -10345,17 +10347,16 @@ simo/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10345
10347
  simo/management/auto_update.py,sha256=4MDrJHdtC5LxEJM258Y0kc5yI4yloeKhDjh-S2BN-ZQ,2115
10346
10348
  simo/management/copy_template.py,sha256=Iehq57FYMzdHNp3LU4ue6rr6AkRiGeOthG7PoGWd88Q,2002
10347
10349
  simo/management/install.py,sha256=hy2LB0sPNpaFHv2Wvp6CeiItvKJb3sFVU0lJuz02VDM,10127
10348
- simo/management/on_http_start.py,sha256=ZDotfMQaCjksD5FFf3eZYgJS-gd_-7eZhYTHLaD-448,3312
10349
10350
  simo/management/__pycache__/__init__.cpython-38.pyc,sha256=ey9k5mPsmvAHRVf5Du6QUqy40LgBCAPN_B5EaR6h9Eg,164
10350
10351
  simo/management/__pycache__/auto_update.cpython-38.pyc,sha256=OAp7w4PdXY0xeo7Yof7O_x9y7qNMyZV4ZerRlswjQ2I,1681
10351
- simo/management/__pycache__/on_http_start.cpython-38.pyc,sha256=ERfcMNz3QnqDJTJ4PwbmDfLgPCh5hrEcaedejARFkUQ,2864
10352
10352
  simo/management/_hub_template/hub/asgi.py,sha256=ElN_fdeSkf0Ysa7pS9rJVmZ1HmLhFxb8jFaMLqe1220,126
10353
10353
  simo/management/_hub_template/hub/celeryc.py,sha256=3ksDXftIZKJ4Cq9WNKJERdZdQlDEnjTQXycweRFmsSQ,27
10354
10354
  simo/management/_hub_template/hub/manage.py,sha256=PNNlw3EVeIJDgkG0l-klqoxsKWfTYWG9jzRG0upmAaI,620
10355
- simo/management/_hub_template/hub/nginx.conf,sha256=wAV7wWgZc9JqhLI94i-j1olhLwMi8SCvE8NiyTEDwJI,2002
10355
+ simo/management/_hub_template/hub/nginx.conf,sha256=40hvXL42MeiqqkLURNcDQsRudv1dNFLJnvb2-Y3RCkk,2394
10356
10356
  simo/management/_hub_template/hub/settings.py,sha256=4QhvhbtLRxHvAntwqG_qeAAtpDUqKvN4jzw9u3vqff8,361
10357
- simo/management/_hub_template/hub/supervisor.conf,sha256=IY3fdK0fDD2eAothB0n54xhjQj8LYoXIR96-Adda5Z8,1353
10357
+ simo/management/_hub_template/hub/supervisor.conf,sha256=M5FgVi6JS_nel6_Ptt4Dwz2Vugc0gFalxrs90a7R11E,1872
10358
10358
  simo/management/_hub_template/hub/urls.py,sha256=Ydm-1BkYAzWeEF-MKSDIFf-7aE4qNLPm48-SA51XgJQ,25
10359
+ simo/management/_hub_template/hub/wsgi.py,sha256=Lo-huLHnMDTxSmMBOodVFMWBls9poddrV2KRzXU0xGo,280
10359
10360
  simo/multimedia/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10360
10361
  simo/multimedia/admin.py,sha256=GgXiKTLfi3omjBurU-bKgneJRK-tAeiR8o2jo3zD7zs,1002
10361
10362
  simo/multimedia/api.py,sha256=mZ5BTggWdc_kL8P70JGC3rTCiZKPnxWYoyNcAQkFnX4,285
@@ -10403,15 +10404,15 @@ simo/notifications/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=YnO
10403
10404
  simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.pyc,sha256=Gkb3Qwr_zglGibQg9g5ekIgxtGapS4ENXVWQVHqM56I,794
10404
10405
  simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=YMBRHVon2nWDtIUbghckjnC12sIg_ykPWhV5aM0tto4,178
10405
10406
  simo/users/__init__.py,sha256=6a7uBpCWB_DR7p54rbHusc0xvi1qfT1ZCCQGb6TiBh8,52
10406
- simo/users/admin.py,sha256=6RKGnwcrmewJFPzpqnxYn8rxjHO4tJPVFJvA3eMum2s,6746
10407
- simo/users/api.py,sha256=HUY4H9kK_HZKeN4VFERcbNDp6Mmp6p2LdDKBDFvWGUE,10096
10407
+ simo/users/admin.py,sha256=QQgan5_DyX22LdNFSWf2LHnTRO8gdQD4N295R-owuz0,6397
10408
+ simo/users/api.py,sha256=kUcdHm-WUn6z_AnFEXHnjYu8YX2MW1Z-NlAysRmSdLI,10333
10408
10409
  simo/users/apps.py,sha256=cq0A8-U1HALEwev0TicgFhr4CAu7Icz8rwq0HfOaL4E,207
10409
10410
  simo/users/auth_backends.py,sha256=bBSNXQJ88TRXaQxyh1aETfmOIfiDr08Jnj8rSY9sHDk,4074
10410
10411
  simo/users/auto_urls.py,sha256=lcJvteBsbHQMJieZpDz-63tDYejLApqsW3CUnDakd7k,272
10411
10412
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
10412
10413
  simo/users/managers.py,sha256=M_51bk9z4jn8e2Ci3pJfIqbf6cRNqfQNSOAg0vPl6Vo,175
10413
10414
  simo/users/middleware.py,sha256=GMCrnWSc_2qCleyQIkfQGdL-pU-UTEcSg1wPvIKZ9uk,1210
10414
- simo/users/models.py,sha256=F3rkYmofakoVzr7szjr8t8014-bbN_Nkv1TVOVKoIF8,19761
10415
+ simo/users/models.py,sha256=5ZMXBFExo1oO6vKYn4qOBSbgCp2kiAFNK82hm2k70vA,19195
10415
10416
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
10416
10417
  simo/users/serializers.py,sha256=a4R408ZgWVbF7OFw4bBfN33Wnn8ljqS8iFcsqmllkWU,2552
10417
10418
  simo/users/sso_urls.py,sha256=gQOaPvGMYFD0NCVSwyoWO-mTEHe5j9sbzV_RK7kdvp0,251
@@ -10420,15 +10421,15 @@ simo/users/tasks.py,sha256=HJAqiyWGsaN3wSfquU0UyQ20jL-njXeaaTOdDT3TQ3s,979
10420
10421
  simo/users/utils.py,sha256=7gU_TDnAOsDYqJM0CFo8efPah2bTXfGpXxRqzD5RiSs,1270
10421
10422
  simo/users/views.py,sha256=dOQVvmlHG7ihWKJLFUBcqKOA0UDctlMKR0pTc36JZqg,3487
10422
10423
  simo/users/__pycache__/__init__.cpython-38.pyc,sha256=VFoDJE_SKKaPqqYaaBYd1Ndb1hjakkTo_u0EG_XJ1GM,211
10423
- simo/users/__pycache__/admin.cpython-38.pyc,sha256=paoWxwJgOyDF7RT7LIviDqggdELG9-fbydc9UfqHV10,7500
10424
- simo/users/__pycache__/api.cpython-38.pyc,sha256=QqQL0MyG8-_7HkqPvqwINuYoco-pJEQ8zT8Crr7t3Rc,8602
10424
+ simo/users/__pycache__/admin.cpython-38.pyc,sha256=zwD7hbwzZ4VwsQlrtG8j8KOqTRDQmhup-Y_hcbZDXD0,7315
10425
+ simo/users/__pycache__/api.cpython-38.pyc,sha256=25he7r5DHfcLYveXWhn6gQDV2R6YnpKbUVBNInR1q_s,8714
10425
10426
  simo/users/__pycache__/apps.cpython-38.pyc,sha256=dgbWL8CxzzISJQTmq_4IztPJ2UzykNVdqA2Ae1PmeGk,605
10426
10427
  simo/users/__pycache__/auth_backends.cpython-38.pyc,sha256=n5nx2QSXNj2idzRcGE6bAagMN-8qxoCs580H1EFZXls,3105
10427
10428
  simo/users/__pycache__/auto_urls.cpython-38.pyc,sha256=K-3sz2h-cEitoflSmZk1t0eUg5mQMMGLNZFREVwG7_o,430
10428
10429
  simo/users/__pycache__/dynamic_settings.cpython-38.pyc,sha256=6F8JBjZkHykySnmZjNEzjS0ijbmPdcp9yUAZ5kqq_Fo,864
10429
10430
  simo/users/__pycache__/managers.cpython-38.pyc,sha256=C5-diljm874RAFMTkZdcfzPhkHzlUGPAhz2gTvqkDy8,604
10430
10431
  simo/users/__pycache__/middleware.cpython-38.pyc,sha256=Tj4nVEAvxEW3xA63fBRiJWRJpz_M848ZOqbHioc_IPE,1149
10431
- simo/users/__pycache__/models.cpython-38.pyc,sha256=_EIJC_Q1XeqxI7yKr6dOw6tv6o_GkA3TaFZ9YH5de1g,18193
10432
+ simo/users/__pycache__/models.cpython-38.pyc,sha256=q5ROEWKeXud_MK3olV7aMTstmbl4hAYIjs7H8L_v4Jc,17817
10432
10433
  simo/users/__pycache__/permissions.cpython-38.pyc,sha256=ez5NxoL_JUeeH6GsKhvFreuA3FCBgGf9floSypdXUtM,633
10433
10434
  simo/users/__pycache__/serializers.cpython-38.pyc,sha256=PuMy6H0PhEhq89RFmdnFH4pMHB0N3w7opJEFS90JUCY,3477
10434
10435
  simo/users/__pycache__/sso_urls.cpython-38.pyc,sha256=uAwDozpOmrhUald-8tOHANILXkH7-TI8fNYXOtPkSY8,402
@@ -10465,6 +10466,9 @@ simo/users/migrations/0026_fingerprint_name.py,sha256=DPmfi1brbaPymdNiPgc7dINSKy
10465
10466
  simo/users/migrations/0027_permissionsrole_can_manage_components.py,sha256=VcGZE6u-q6UkGo7D01K_T1XBtIvIGe8SCk5ZPRrPpGo,485
10466
10467
  simo/users/migrations/0028_auto_20240506_1146.py,sha256=7RUFF2rJH-bnPeHwc77p8Q4kEAc3owyG4qp9Kc4aKhU,716
10467
10468
  simo/users/migrations/0029_alter_instanceuser_instance.py,sha256=5ebO0vX9lCnTXBMkWg8633sBCBLNtMLfbocVY-uyQhE,588
10469
+ simo/users/migrations/0030_userdevice_users.py,sha256=cYY7yChsxOOauHAPIQUzLjLLiOA6kkopTQBE-M9HH10,448
10470
+ simo/users/migrations/0031_auto_20240923_1115.py,sha256=RyhmpsxpSXK9Ejbh3cHm9fTnDOcLFQsTH9-2MpNK5YU,514
10471
+ simo/users/migrations/0032_remove_userdevice_user_alter_userdevice_users.py,sha256=pM0B4ghsw6LWDvT_9owUmqIHQiraauTGYm_EePhVBUQ,570
10468
10472
  simo/users/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10469
10473
  simo/users/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=e4XOKaYRb7l0P7cBnHHi5FQQJMlwjK0g7iqgM-xKmNI,4215
10470
10474
  simo/users/migrations/__pycache__/0002_componentpermission.cpython-38.pyc,sha256=pknJnpic8p6Vdx9DX41FfODXNnvexDswJtUCmC5w1tg,995
@@ -10497,6 +10501,9 @@ simo/users/migrations/__pycache__/0028_auto_20240506_1146.cpython-38.pyc,sha256=
10497
10501
  simo/users/migrations/__pycache__/0029_alter_instanceuser_instance.cpython-38.pyc,sha256=2EsX6ksqPomNHiPCORDYENqn2yI7dQUK_4hMSpMVxDE,823
10498
10502
  simo/users/migrations/__pycache__/0029_alter_instanceuser_options_instanceuser_order.cpython-38.pyc,sha256=aqC63NS8xpFKzLuvL00_axUAvjTzqmvlgfkD03bzakg,721
10499
10503
  simo/users/migrations/__pycache__/0030_alter_instanceuser_options_remove_instanceuser_order.cpython-38.pyc,sha256=uC2t0g2AGdQ53Z621ZcS4-n6UGxjRUM6AFUAMrGIMnY,658
10504
+ simo/users/migrations/__pycache__/0030_userdevice_users.cpython-38.pyc,sha256=PWQ77FvS69xbGdzC9E7qXX9RLQ9QC4a__0h0oRAI7Ec,674
10505
+ simo/users/migrations/__pycache__/0031_auto_20240923_1115.cpython-38.pyc,sha256=0nT2ftDPi0yV6j-p9Am-nVsTy2kY0msM_f2k0eP9EoU,866
10506
+ simo/users/migrations/__pycache__/0032_remove_userdevice_user_alter_userdevice_users.cpython-38.pyc,sha256=SDKPEIkt9DYEBRm63GAnxG1yRKKm-JP3pizaJdbAUks,772
10500
10507
  simo/users/migrations/__pycache__/__init__.cpython-38.pyc,sha256=NKq7WLgktK8WV1oOqCPbAbdkrPV5GRGhYx4VxxI4dcs,170
10501
10508
  simo/users/templates/conf/mosquitto.conf,sha256=1eIGNuRu4Y3hfAU6qiWix648eCRrw0oOT24PnyFI4ys,189
10502
10509
  simo/users/templates/conf/mosquitto_acls.conf,sha256=ga44caTDNQE0CBKw55iM2jOuna6-9fKGwAhjyERZdRE,500
@@ -10506,9 +10513,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10506
10513
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10507
10514
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10508
10515
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10509
- simo-2.2.9.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10510
- simo-2.2.9.dist-info/METADATA,sha256=1UFNm0bYqKsBbPc6SjdYGFfT3BTrNxcRt3GVKW6ZluU,1847
10511
- simo-2.2.9.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
10512
- simo-2.2.9.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10513
- simo-2.2.9.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10514
- simo-2.2.9.dist-info/RECORD,,
10516
+ simo-2.2.11.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10517
+ simo-2.2.11.dist-info/METADATA,sha256=MwJmlJfWOd9kH5Wrw9ZMSYFI7xVeyetdleeMo5LOJ5k,1881
10518
+ simo-2.2.11.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
10519
+ simo-2.2.11.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10520
+ simo-2.2.11.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10521
+ simo-2.2.11.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5