simo 2.5.4__py3-none-any.whl → 2.5.5__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.

Binary file
simo/core/middleware.py CHANGED
@@ -37,11 +37,13 @@ def get_current_instance(request=None):
37
37
 
38
38
  instance = getattr(_thread_locals, 'instance', None)
39
39
 
40
- if not instance:
41
- from .models import Instance
42
- instance = Instance.objects.filter(is_active=True).first()
43
- if instance:
44
- introduce_instance(instance)
40
+ # NEVER FORCE THIS! IT's A very BAD IDEA!
41
+ # For example gateways run on an instance neutral environment!
42
+ # if not instance:
43
+ # from .models import Instance
44
+ # instance = Instance.objects.filter(is_active=True).first()
45
+ # if instance:
46
+ # introduce_instance(instance)
45
47
  return instance
46
48
 
47
49
 
@@ -92,8 +94,13 @@ def instance_middleware(get_response):
92
94
 
93
95
  if instance:
94
96
  introduce_instance(instance, request)
95
- tz = pytz.timezone(instance.timezone)
96
- timezone.activate(tz)
97
+ try:
98
+ # should never, but just in case
99
+ tz = pytz.timezone(instance.timezone)
100
+ timezone.activate(tz)
101
+ except:
102
+ tz = pytz.timezone('UTC')
103
+ timezone.activate(tz)
97
104
 
98
105
  response = get_response(request)
99
106
 
simo/core/models.py CHANGED
@@ -61,7 +61,7 @@ def post_icon_delete(sender, instance, *args, **kwargs):
61
61
  pass
62
62
 
63
63
 
64
- class Instance(models.Model, SimoAdminMixin):
64
+ class Instance(DirtyFieldsMixin, models.Model, SimoAdminMixin):
65
65
  # Multiple home instances can be had on a single hub computer!
66
66
  # For example separate hotel apartments
67
67
  # or something of that kind.
@@ -101,7 +101,7 @@ class Instance(models.Model, SimoAdminMixin):
101
101
  User, null=True, blank=True, on_delete=models.SET_NULL
102
102
  )
103
103
 
104
- objects = InstanceManager()
104
+ #objects = InstanceManager()
105
105
 
106
106
 
107
107
  def __str__(self):
@@ -118,7 +118,9 @@ class Instance(models.Model, SimoAdminMixin):
118
118
 
119
119
 
120
120
  class Zone(DirtyFieldsMixin, models.Model, SimoAdminMixin):
121
- instance = models.ForeignKey(Instance, on_delete=models.CASCADE)
121
+ instance = models.ForeignKey(
122
+ Instance, on_delete=models.CASCADE, related_name='zones'
123
+ )
122
124
  name = models.CharField(_('name'), max_length=40)
123
125
  order = models.PositiveIntegerField(
124
126
  default=0, blank=False, null=False, db_index=True
@@ -5,6 +5,7 @@ from django.db.models.signals import post_save, post_delete
5
5
  from django.dispatch import receiver
6
6
  from django.utils import timezone
7
7
  from django.conf import settings
8
+ from django.template.loader import render_to_string
8
9
  from actstream import action
9
10
  from simo.users.models import PermissionsRole
10
11
  from .models import Instance, Gateway, Component, Icon, Zone, Category
@@ -43,6 +44,7 @@ def create_instance_defaults(sender, instance, created, **kwargs):
43
44
 
44
45
  # Create default categories
45
46
  climate_category = None
47
+ other_category = None
46
48
  for i, data in enumerate([
47
49
  ("All", 'star'), ("Climate", 'temperature-half'),
48
50
  ("Lights", 'lightbulb'), ("Security", 'eye'),
@@ -63,17 +65,17 @@ def create_instance_defaults(sender, instance, created, **kwargs):
63
65
  )
64
66
  if cat.name == 'Climate':
65
67
  climate_category = cat
68
+ if cat.name == 'Other':
69
+ other_category = cat
66
70
 
67
71
  # Create generic gateway and components
68
72
 
69
73
  generic, new = Gateway.objects.get_or_create(
70
74
  type='simo.generic.gateways.GenericGatewayHandler'
71
75
  )
72
- generic.start()
73
76
  dummy, new = Gateway.objects.get_or_create(
74
77
  type='simo.generic.gateways.DummyGatewayHandler'
75
78
  )
76
- dummy.start()
77
79
  weather_icon = Icon.objects.get(slug='cloud-bolt-sun')
78
80
 
79
81
  Component.objects.create(
@@ -85,6 +87,63 @@ def create_instance_defaults(sender, instance, created, **kwargs):
85
87
  config={'is_main': True}
86
88
  )
87
89
 
90
+ state_comp = Component.objects.create(
91
+ name='State', icon=Icon.objects.get(slug='home'),
92
+ zone=other_zone,
93
+ category=other_category,
94
+ gateway=generic, base_type='state-select',
95
+ controller_uid='simo.generic.controllers.StateSelect',
96
+ value='day',
97
+ config={"states": [
98
+ {"icon": "house-day", "name": "Day", "slug": "day"},
99
+ {"icon": "house-night", "name": "Evening", "slug": "evening"},
100
+ {"icon": "moon-cloud", "name": "Night", "slug": "night"},
101
+ {"icon": "house-person-leave", "name": "Away", "slug": "away"},
102
+ {"icon": "island-tropical", "name": "Vacation", "slug": "vacation"}
103
+ ], "is_main": True}
104
+ )
105
+
106
+
107
+ auto_state_code = render_to_string(
108
+ 'core/auto_state_script.py', {'state_comp_id': state_comp.id}
109
+ )
110
+ Component.objects.create(
111
+ name='Auto state', icon=Icon.objects.get(slug='bolt'),
112
+ zone=other_zone,
113
+ category=other_category,
114
+ gateway=generic, base_type='script',
115
+ controller_uid='simo.generic.controllers.Script',
116
+ config={
117
+ "code": auto_state_code, 'autostart': True, 'keep_alive': True,
118
+ "notes": f"""
119
+ The script automatically controls the states of the "State" component (ID:{state_comp.id}) — 'day,' 'evening,' 'night,' 'away.'
120
+ The 'day' state is activated on weekdays from 10 a.m., and on weekends from 11 a.m. When the sun sets, the 'evening' state is activated, and at midnight, the 'night' state is activated.
121
+ If no one is home, the 'away' state is activated.
122
+ If a different state, such as 'vacation,' is selected, the script stops running and waits until the State is switched back to one of the controlled states.
123
+ If one of the controlled states is manually selected, the script waits until that state is reached automatically and, once aligned with the manually set state, resumes its operation in normal mode.
124
+ """
125
+ }
126
+ )
127
+
128
+ code = render_to_string(
129
+ 'core/auto_night_day_script.py', {'state_comp_id': state_comp.id}
130
+ )
131
+ Component.objects.create(
132
+ name='Auto night/day by owner phones on charge',
133
+ icon=Icon.objects.get(slug='bolt'), zone=other_zone,
134
+ category=other_category, show_in_app=False,
135
+ gateway=generic, base_type='script',
136
+ controller_uid='simo.generic.controllers.Script',
137
+ config={
138
+ "code": code, 'autostart': True, 'keep_alive': True,
139
+ "notes": f"""
140
+ Automatically sets State component (ID: {state_comp.id}) to "night" if it is later than 10pm and all home owners phones who are at home are put on charge.
141
+ Sets State component to "day" state as soon as none of the home owners phones are on charge and it is 6am or later.
142
+
143
+ """
144
+ }
145
+ )
146
+
88
147
  # Create default User permission roles
89
148
 
90
149
  PermissionsRole.objects.create(
@@ -96,6 +155,8 @@ def create_instance_defaults(sender, instance, created, **kwargs):
96
155
  PermissionsRole.objects.create(
97
156
  instance=instance, name="Guest", is_owner=True
98
157
  )
158
+ generic.start()
159
+ dummy.start()
99
160
 
100
161
 
101
162
  @receiver(post_save, sender=Zone)
@@ -0,0 +1,62 @@
1
+ import time
2
+ import random
3
+ from django.utils import timezone
4
+ from simo.core.middleware import get_current_instance
5
+ from simo.core.models import Component
6
+ from simo.users.models import InstanceUser
7
+ from simo.generic.scripting.helpers import LocalSun
8
+
9
+
10
+ class Automation:
11
+ STATE_COMPONENT_ID = {{ state_comp_id }}
12
+
13
+ def __init__(self):
14
+ self.instance = get_current_instance()
15
+ self.state = Component.objects.get(id=self.STATE_COMPONENT_ID)
16
+ self.sun = LocalSun(self.instance.location)
17
+ self.night_is_on = False
18
+
19
+ def check_owner_phones(self, state, instance_users, datetime):
20
+ if not self.night_is_on:
21
+ if not (datetime.hour >= 22 or datetime.hour < 6):
22
+ return
23
+
24
+ for iuser in instance_users:
25
+ # skipping users that are not at home
26
+ if not iuser.at_home:
27
+ continue
28
+ if not iuser.phone_on_charge:
29
+ # at least one user's phone is not yet on charge
30
+ return
31
+ self.night_is_on = True
32
+ return 'night'
33
+ else:
34
+ # return new_state diena only if there are still users
35
+ # at home, none of them have their phones on charge
36
+ # and current state is still night
37
+ for iuser in instance_users:
38
+ # skipping users that are not at home
39
+ if not iuser.at_home:
40
+ continue
41
+ if iuser.phone_on_charge:
42
+ # at least one user's phone is still on charge
43
+ return
44
+ else:
45
+ self.night_is_on = False
46
+ if not self.night_is_on and state.value == 'night':
47
+ return 'day'
48
+
49
+ def run(self):
50
+ while True:
51
+ instance_users = InstanceUser.objects.filter(
52
+ is_active=True, role__is_owner=True
53
+ )
54
+ self.state.refresh_from_db()
55
+ new_state = self.check_owner_phones(
56
+ self.state, instance_users, timezone.localtime()
57
+ )
58
+ if new_state:
59
+ self.state.send(new_state)
60
+
61
+ # randomize script load
62
+ time.sleep(random.randint(20, 40))
@@ -0,0 +1,78 @@
1
+ import time
2
+ from django.utils import timezone
3
+ from simo.core.middleware import get_current_instance
4
+ from simo.core.models import Component
5
+ from simo.users.models import InstanceUser
6
+ from simo.generic.scripting.helpers import LocalSun
7
+
8
+
9
+ class Automation:
10
+ STATE_COMPONENT_ID = {{ state_comp_id }}
11
+ last_state = None
12
+ weekdays_morning_hour = 10
13
+ weekends_morning_hour = 11
14
+
15
+ def __init__(self):
16
+ self.instance = get_current_instance()
17
+ self.state = Component.objects.get(id=self.STATE_COMPONENT_ID)
18
+ self.sun = LocalSun(self.instance.location)
19
+
20
+ def check_at_home(self):
21
+ return bool(InstanceUser.objects.filter(
22
+ is_active=True, at_home=True
23
+ ).count())
24
+
25
+ def calculate_appropriate_state(self, localtime, at_home):
26
+ if not at_home:
27
+ return 'away'
28
+ if self.sun.is_night(localtime) \
29
+ and self.sun.get_sunset_time(localtime) < localtime:
30
+ return 'evening'
31
+
32
+ if localtime.weekday() < 5 \
33
+ and localtime.hour < self.weekdays_morning_hour:
34
+ return 'night'
35
+
36
+ if localtime.weekday() >= 5 \
37
+ and localtime.hour < self.weekends_morning_hour:
38
+ return 'night'
39
+
40
+ return 'day'
41
+
42
+ def get_new_state(self, state, localtime, at_home):
43
+ # If state component on vacation or in some other state
44
+ # we do not interfere!
45
+ if state.value not in ('day', 'night', 'evening', 'away'):
46
+ return
47
+ should_be = self.calculate_appropriate_state(
48
+ localtime, at_home
49
+ )
50
+
51
+ if self.last_state != state.value:
52
+ # user changed something manually
53
+ # we must first wait for appropriate state to get in to
54
+ # manually selected one, only then we will transition to forward.
55
+ if should_be == state.value:
56
+ print("Consensus with system users reached!")
57
+ self.last_state = should_be
58
+ elif self.last_state != should_be:
59
+ print("New state: ", should_be)
60
+ self.last_state = should_be
61
+ return should_be
62
+
63
+ def run(self):
64
+ # do not interfere on script start,
65
+ # only later when we absolutely must
66
+ self.last_state = self.get_new_state(
67
+ self.state, timezone.localtime(),
68
+ self.check_at_home()
69
+ )
70
+ while True:
71
+ self.state.refresh_from_db()
72
+ new_state_value = self.get_new_state(
73
+ self.state, timezone.localtime(),
74
+ self.check_at_home()
75
+ )
76
+ if new_state_value:
77
+ self.state.send(new_state_value)
78
+ time.sleep(10)
simo/generic/gateways.py CHANGED
@@ -74,7 +74,10 @@ class ScriptRunHandler(multiprocessing.Process):
74
74
  def run(self):
75
75
  db_connection.connect()
76
76
  self.component = Component.objects.get(id=self.component_id)
77
- tz = pytz.timezone(self.component.zone.instance.timezone)
77
+ try:
78
+ tz = pytz.timezone(self.component.zone.instance.timezone)
79
+ except:
80
+ tz = pytz.timezone('UTC')
78
81
  timezone.activate(tz)
79
82
  introduce_instance(self.component.zone.instance)
80
83
  self.logger = get_component_logger(self.component)
@@ -151,7 +154,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
151
154
  for id, process in self.running_scripts.items():
152
155
  if process.is_alive():
153
156
  if not Component.objects.filter(id=id).count():
154
- # script is deleted.
157
+ # script is deleted, or instance deactivated
155
158
  process.terminate()
156
159
  continue
157
160
  component = Component.objects.filter(id=id).exclude(
simo/generic/models.py CHANGED
@@ -8,6 +8,7 @@ from simo.core.models import Instance, Component
8
8
  from simo.users.models import InstanceUser
9
9
 
10
10
 
11
+
11
12
  @receiver(post_save, sender=Component)
12
13
  def handle_alarm_groups(sender, instance, *args, **kwargs):
13
14
  if not instance.alarm_category:
@@ -1,7 +1,5 @@
1
1
  import time
2
2
  import random
3
- import pytz
4
- from datetime import datetime
5
3
  from django.utils import timezone
6
4
  from simo.core.middleware import get_current_instance
7
5
  from simo.core.models import Component
@@ -65,3 +63,4 @@ class Automation:
65
63
 
66
64
 
67
65
  def test(self):
66
+ pass
@@ -1,4 +1,5 @@
1
1
  from django.contrib import admin
2
+ from simo.core.middleware import get_current_instance
2
3
  from .models import Notification, UserNotification
3
4
 
4
5
 
@@ -15,9 +16,12 @@ class NotificationAdmin(admin.ModelAdmin):
15
16
  actions = 'dispatch',
16
17
 
17
18
  def get_queryset(self, request):
18
- return super().get_queryset(request).filter(
19
- instance__in=request.user.instances
20
- ).prefetch_related('to_users')
19
+ qs = super().get_queryset(request)
20
+ instance = get_current_instance()
21
+ if instance:
22
+ qs = qs.filter(instance=instance)
23
+ return qs.prefetch_related('to_users')
24
+
21
25
 
22
26
  def to(self, obj):
23
27
  return ', '.join([str(u) for u in obj.to_users.all()])
Binary file
simo/users/api.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ import datetime
2
3
  from django.db.models import Q
3
4
  from rest_framework import viewsets, mixins, status
4
5
  from rest_framework.serializers import Serializer
@@ -211,12 +212,6 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
211
212
  [str(i) for i in location]
212
213
  ) if location else None
213
214
 
214
- speed_mps = float(request.data.get('speed', 0))
215
- if speed_mps < 0:
216
- speed_mps = 0
217
- speed_kmh = speed_mps * 3.6
218
-
219
-
220
215
  if request.data.get('app_open', False):
221
216
  user_device.is_primary = True
222
217
  UserDevice.objects.filter(
@@ -231,7 +226,21 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
231
226
  ) < dynamic_settings['users__at_home_radius']
232
227
  elif not relay:
233
228
  iu.at_home = True
234
-
229
+ speed_kmh = 0
230
+ if user_device.last_seen_location and iu.last_seen_location \
231
+ and iu.last_seen > timezone.now() - datetime.timedelta(seconds=30):
232
+ if user_device.last_seen_location == iu.last_seen_location:
233
+ speed_kmh = iu.last_seen_speed_kmh
234
+ else:
235
+ seconds_passed = (timezone.now() - user_device.last_seen).seconds
236
+ if not seconds_passed:
237
+ speed_kmh = 0
238
+ else:
239
+ moved_distance = haversine_distance(
240
+ iu.last_seen_location, user_device.last_seen_location
241
+ )
242
+ speed_mps = moved_distance / seconds_passed
243
+ speed_kmh = speed_mps * 3.6
235
244
  iu.last_seen = user_device.last_seen
236
245
  iu.last_seen_location = user_device.last_seen_location
237
246
  iu.last_seen_speed_kmh = speed_kmh
simo/users/models.py CHANGED
@@ -289,13 +289,13 @@ class User(AbstractBaseUser, SimoAdminMixin):
289
289
  instances = cache.get(cache_key, 'expired')
290
290
  if instances == 'expired':
291
291
  if self.is_master:
292
- instances = Instance.objects.all()
292
+ instances = Instance.objects.filter(is_active=True)
293
293
  else:
294
294
  instances = Instance.objects.filter(id__in=[
295
295
  r.instance.id for r in self.instance_roles.filter(
296
296
  is_active=True, instance__isnull=False
297
297
  )
298
- ])
298
+ ], is_active=True)
299
299
  cache.set(cache_key, instances, 10)
300
300
  return instances
301
301
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.5.4
3
+ Version: 2.5.5
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
@@ -51,12 +51,12 @@ simo/core/forms.py,sha256=nL_trDNs7RLic11zLSen4EobtywGx8igUMYe7Ojuv1k,21988
51
51
  simo/core/gateways.py,sha256=m0eS3XjVe34Dge6xtoCq16kFWCKJcdQrT0JW0REqoq8,3715
52
52
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
53
53
  simo/core/managers.py,sha256=n-b3I4uXzfHKTeB1VMjSaMsDUxp8FegFJwnbV1IsWQ4,3019
54
- simo/core/middleware.py,sha256=ypyZfVZN3bEEudhg3-Ho4GacMol4u1QJ19it6MnZ_D8,2896
55
- simo/core/models.py,sha256=fEbRVY128-FdjG2ueQhBlSMRpvKcxY2VKCJUqXsSMPI,22441
54
+ simo/core/middleware.py,sha256=hExD7Vmw7eitk0vAjOwKzkwrtuw8YxpflF92j_CA2YY,3193
55
+ simo/core/models.py,sha256=OSvBVfl5rmkx_h6cfQ3k_2gxoV9Nk1f8rvdoQtALquw,22496
56
56
  simo/core/permissions.py,sha256=v0iJM4LOeYoEfMiw3OLPYio272G1aUEAg_z9Wd1q5m0,2993
57
57
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
58
58
  simo/core/serializers.py,sha256=Pa2lhJ6VgNalbH4awbKdGJCYAPNsu5WQWfo6Tz6LbOQ,20782
59
- simo/core/signal_receivers.py,sha256=Mt3bDLEIO3ygqG9fCiObJ3oPv4P1F4NAjiqo5sbmY6g,6248
59
+ simo/core/signal_receivers.py,sha256=qCpzEUv5Bl9--K8fe08GVDmE6EBOj292YBia1TYDdSE,9267
60
60
  simo/core/socket_consumers.py,sha256=trRZvBGTJ7xIbfdmVvn7zoiWp_qssSkMZykDrI5YQyE,9783
61
61
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
62
62
  simo/core/tasks.py,sha256=dLutVjQdAhZVFldQpWilQEYfPcTFqkAoyGao0MTuKJ0,14583
@@ -84,12 +84,12 @@ simo/core/__pycache__/forms.cpython-38.pyc,sha256=O_mCWAQHAJhiqcKLUina7tIFbw5uXw
84
84
  simo/core/__pycache__/gateways.cpython-38.pyc,sha256=D1ooHL-iSpQrxnD8uAl4xWFJmm-QWZfbkLiLlFOMtdU,4553
85
85
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
86
86
  simo/core/__pycache__/managers.cpython-38.pyc,sha256=6RTIxyjOgpQGtAqcUyE2vFPS09w1V5Wmd_vOV7rHRRI,3370
87
- simo/core/__pycache__/middleware.cpython-38.pyc,sha256=w97mv2fyREGL8F0rDHFyZvFD85DqiOSW_R1OlLXkrHs,2494
88
- simo/core/__pycache__/models.cpython-38.pyc,sha256=vq7ysMUjqPdcPl6DfLzAzmJWPC9_WNR5W789w8fZirc,18460
87
+ simo/core/__pycache__/middleware.cpython-38.pyc,sha256=iOSTXSQl3sEsa-9kx_6w5zbEByRtfzJHT6XkUIYMGdE,2469
88
+ simo/core/__pycache__/models.cpython-38.pyc,sha256=4lNUqjILHQyssviRXrr82-03Bc5LxgUrdQ_OmWozahE,18459
89
89
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=fH4iyqd9DdzRLEu2b621-FeM-napR0M7hzBUTHo9Q3g,2972
90
90
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
91
91
  simo/core/__pycache__/serializers.cpython-38.pyc,sha256=qIHxrurPk555mHc9P8Udg9eGv-ODw1FTmBS_jXrPuws,19220
92
- simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=MoIxnq-Eny7Ob-9Afv6ue7htA5Di-UoohprHosR6Z_U,4903
92
+ simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=lBVca6zNPVn3Ev98ekjPGzBR1MJk4xI19CyMcm4lf6A,7056
93
93
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=KqbO1cOewodVPcy0-htVefyUjCuELKV0o7fOfYqfgPc,8490
94
94
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
95
95
  simo/core/__pycache__/tasks.cpython-38.pyc,sha256=qQZ1wP3ksyh6c6kmqMtkYxGs-MTTDhaqQDlYfK7vQ7c,10003
@@ -161,7 +161,7 @@ simo/core/management/commands/gateways_manager.py,sha256=oHzgC-eV4w_KHkiz6eCAlt3
161
161
  simo/core/management/commands/on_http_start.py,sha256=A2V40pyGY7AfONhtnxiGATOkqd0i9FUvRRxkwyAJF9k,2252
162
162
  simo/core/management/commands/run_gateway.py,sha256=bp0FQQoBeOSoxjHCCMicDL1fxPZZGyLgnq2QKht3bJo,645
163
163
  simo/core/management/commands/__pycache__/__init__.cpython-38.pyc,sha256=WKpfZZpAB9D7U4X6oWQIrU_H-6rUmq8Gl9fj9XaY2fw,178
164
- simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc,sha256=pgEJdchhOcqKCpjdRMeF0_QKJfMmfSkl_W4TUwcgS9o,6031
164
+ simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc,sha256=g5xhLz6AgU7cGZ5EmoiBZIZuZbs9AN01ZRZEOCEFqeE,6031
165
165
  simo/core/management/commands/__pycache__/on_http_start.cpython-38.pyc,sha256=LQeFW3oYYRrEPEcGghyeahFE114-4VbnKH4XaVGcQcg,3235
166
166
  simo/core/migrations/0001_initial.py,sha256=0Uy7IqJxQQYlurs8Mw_RJy7NaWS7BU0VFmZBBz8YkQI,9220
167
167
  simo/core/migrations/0002_load_icons.py,sha256=s9TtGo5NWEyWV3BspfbDNAlWqmQWxmDj7GjEaJXruFk,2044
@@ -10166,6 +10166,8 @@ simo/core/templates/admin/users/qr_code.html,sha256=kE4WNSVsPUvNUFnSUAY8jiD9JCvc
10166
10166
  simo/core/templates/admin/wizard/discovery.html,sha256=xpAiXgKneT0d53c7h1MyAjoOFdXc_lDaH9TdelrggVU,6608
10167
10167
  simo/core/templates/admin/wizard/field.html,sha256=ZbgzAUMs6RdJDH44yQ3-rmAkPmBdsIvBTk1RAQaENAs,413
10168
10168
  simo/core/templates/admin/wizard/wizard_add.html,sha256=RPkwKXctu_yxJxjJqcvVEzG4YtK9-CJK801RPxleWRE,4127
10169
+ simo/core/templates/core/auto_night_day_script.py,sha256=IJ-akeGG-aSWY1loJHArCH2PhQj_IzsukH5O62f9JLw,2231
10170
+ simo/core/templates/core/auto_state_script.py,sha256=_UhSTpeCnv1oOzRzdOI9EXGdaSYevBolWChCKfPPZ6w,2666
10169
10171
  simo/core/templates/core/icon_acutocomplete_select_item.html,sha256=D7aWefAJjrDqyMcwt4vtuwkruklJ1aSjCTi99HLrQUY,768
10170
10172
  simo/core/templates/core/object_acutocomplete_select_item.html,sha256=pS8APlv1IdhfttONh3npzQNfrOhj63YC7837tnOfSHk,465
10171
10173
  simo/core/templates/core/openvpn_client.conf,sha256=z1838G8v8vmIiQKyfE8URCCMpLsges5jbX3hDJkztF4,249
@@ -10336,8 +10338,8 @@ simo/generic/app_widgets.py,sha256=vwYYVRKzKZ9XTvWTfEbaH4zpoHiDIHP6qFTNgZI-xvY,9
10336
10338
  simo/generic/base_types.py,sha256=Bvf3lv6PXx_SwtwBH7qpkwysWuloNcKNRh3LiuZf-Dc,359
10337
10339
  simo/generic/controllers.py,sha256=Xo0ZYQZfhDAwLq9H3uTrHWLj-HeLlxdXJ71dUESd41Y,49263
10338
10340
  simo/generic/forms.py,sha256=nDrvNGbWTE_MSZmSXrKj1bSn-Ylo4w7Y1z-SZRKRYW8,30840
10339
- simo/generic/gateways.py,sha256=n7r0-frVzBw0vmXBQXaaq4TfdaJmUhaAstcIIBls3xM,15129
10340
- simo/generic/models.py,sha256=YEAFfkARsAellfDwmmqGSx7nKkEF5XngciRB4qP1MKk,7596
10341
+ simo/generic/gateways.py,sha256=dUzRBxVDdsx70mrCvxSQwhJr0ydQ5NtoLHoYeVLJmtA,15224
10342
+ simo/generic/models.py,sha256=Adq7ipWK-renxJlNW-SZnAq2oGEOwKx8EdUWaKnfcVQ,7597
10341
10343
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
10342
10344
  simo/generic/socket_consumers.py,sha256=K2OjphIhKJH48BvfFfoCOyCQZ1NmXb_phs6y1IP-qaQ,1757
10343
10345
  simo/generic/__pycache__/__init__.cpython-38.pyc,sha256=mLu54WS9KIl-pHwVCBKpsDFIlOqml--JsOVzAUHg6cU,161
@@ -10345,16 +10347,16 @@ simo/generic/__pycache__/app_widgets.cpython-38.pyc,sha256=dt7fSf38eDA5hVUvVfpyt
10345
10347
  simo/generic/__pycache__/base_types.cpython-38.pyc,sha256=8YDxrsRFGqaeBfSF3Y1WmIGDRHGH1Ww7dSBkxRxkKyc,511
10346
10348
  simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=HBZDEFhJAwd6YFWul_sX4OoA1r1m0DK1MLxJk9u70rk,32674
10347
10349
  simo/generic/__pycache__/forms.cpython-38.pyc,sha256=JM1UN13391udDpBvNsbZURX5onDhLrOLIun-kISmGac,22078
10348
- simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=_TW6l2HyTBH5e_m_r6yGYcPfuULyE4XuVCFLS7upOWA,11544
10349
- simo/generic/__pycache__/models.cpython-38.pyc,sha256=ES8wXkdKn0m-yaJlvhyaIOSppuX9Ckz-bOs9DCpVvaQ,5825
10350
+ simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=IazhRBe-YZ9t7_wq1fULoyLnxn3frR967lAN9D7MbKY,11583
10351
+ simo/generic/__pycache__/models.cpython-38.pyc,sha256=MZpum7syAFxuulf47K7gtUlJJ7xRD-IBUBAwUM1ZRnw,5825
10350
10352
  simo/generic/__pycache__/routing.cpython-38.pyc,sha256=xtxTUTBTdivzFyA5Wh7k-hUj1WDO_FiRq6HYXdbr9Ks,382
10351
10353
  simo/generic/__pycache__/socket_consumers.cpython-38.pyc,sha256=qJO5kvQLWhsQDOr1AtAtsAybuRWioxSkQei3Pc7rdP0,1737
10352
10354
  simo/generic/scripting/__init__.py,sha256=aZZvNBae7unnux_zGHCIWCV2z47hVJc-DIL72Hqfkeo,600
10353
- simo/generic/scripting/example.py,sha256=2maqEIFYgWHSSPdBfYidlNCUEH1fcxUztcjUk5fdqUg,2306
10355
+ simo/generic/scripting/example.py,sha256=zj1puyzc9v4HNR0MTha2_1h7tkBvmVyu_drR4e-3qC0,2277
10354
10356
  simo/generic/scripting/helpers.py,sha256=Zt8Mx5AXIggzYk0e7jn-xQNR_NOqzolAReLkrmDJzVQ,3042
10355
10357
  simo/generic/scripting/serializers.py,sha256=PjyFrjdPK1mBsgbNhyqMi9SWzcymqTa742ipy0LhAN4,1996
10356
10358
  simo/generic/scripting/__pycache__/__init__.cpython-38.pyc,sha256=eHncoNpv5dy35IO1_htWd8CK0sHFBnU_WJ0hl5TKOHQ,794
10357
- simo/generic/scripting/__pycache__/helpers.cpython-38.pyc,sha256=JPBjYr6K6DbXBx82FOvQ8cRNy4zm_g160MrTvA12cNQ,2124
10359
+ simo/generic/scripting/__pycache__/helpers.cpython-38.pyc,sha256=34sa3L2cK1Aw636PCaoCYIWUBIE1h6XmbgDIto9cLeo,2757
10358
10360
  simo/generic/scripting/__pycache__/serializers.cpython-38.pyc,sha256=JD9KCNO27H18mkFaeSMdybTMdTvodqcZSLNbC3pheHU,3412
10359
10361
  simo/generic/static/weather_icons/01d@2x.png,sha256=TZfWi6Rfddb2P-oldWWcjUiuCHiU9Yrc5hyrQAhF26I,948
10360
10362
  simo/generic/static/weather_icons/01n@2x.png,sha256=e9RleTa0T7To9Wi2wJ-9waeTbfHOsUB_xGwkx-89eEg,945
@@ -10412,17 +10414,17 @@ simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-38.pyc,sh
10412
10414
  simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-38.pyc,sha256=tX6x1gNeVcUHcCFvisP9Z2jPBE029TJG632fvtvUjV8,892
10413
10415
  simo/multimedia/migrations/__pycache__/__init__.cpython-38.pyc,sha256=mCgSiQBphL85imdWyTi9-4zBDYF6HfXbhB0ycSPVVuA,175
10414
10416
  simo/notifications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10415
- simo/notifications/admin.py,sha256=y_gmHYXbDh98LUUa-lp9DilTIgM6-pIujWPQPLQsJo8,835
10417
+ simo/notifications/admin.py,sha256=hB9M_gIHx6RFB693mbOENRQR0kZhiUCrPFrakn78Y1s,949
10416
10418
  simo/notifications/api.py,sha256=GXQpq68ULBaJpU8w3SJKaCKuxYGWYehKnGeocGB1RVc,1783
10417
10419
  simo/notifications/models.py,sha256=VZcvweii59j89nPKlWeUSJ44Qz3ZLjJ6mXN6uB9F1Sw,2506
10418
10420
  simo/notifications/serializers.py,sha256=altDEAPWwOhxRcEzE9-34jL8EFpyf3vPoEdAPoVLfGc,523
10419
10421
  simo/notifications/utils.py,sha256=uBl-Y7WGu00iaGM5rrdogcq0OMRVtyVfJF39-mdB3_k,1853
10420
10422
  simo/notifications/__pycache__/__init__.cpython-38.pyc,sha256=YvucUfu98XFvEEg1LYFMlOZJpo_jSGxTVrM-ylAFLOg,167
10421
- simo/notifications/__pycache__/admin.cpython-38.pyc,sha256=Fl4crSZTFQOTYQioV6ff9fBRV4MhNiwQgMS2VnmCI4M,1632
10423
+ simo/notifications/__pycache__/admin.cpython-38.pyc,sha256=cMa2NAu5NZUE5IOL5w2--SHdlCyAeboUu4RrZk26UJc,1704
10422
10424
  simo/notifications/__pycache__/api.cpython-38.pyc,sha256=ys6E4AFghX6bq-rQ0gtA9s0Y2Hh-ypsWH8-Yz4edMrc,2073
10423
10425
  simo/notifications/__pycache__/models.cpython-38.pyc,sha256=rrYjYOEzDZ3Eos2O7aof5wuIo0VUgGt6LLzhXwORDuc,2559
10424
10426
  simo/notifications/__pycache__/serializers.cpython-38.pyc,sha256=7-eRGKYuQ4g1SpKOMpz17SIiu1HmaMoYv-cJbaO9QGA,1028
10425
- simo/notifications/__pycache__/utils.cpython-38.pyc,sha256=yqxzplE-_9khsyMvMpXe8nk4eJAwk_62GUV0sCtfY7k,1460
10427
+ simo/notifications/__pycache__/utils.cpython-38.pyc,sha256=6Tq7VkW-pZLzWzcxPtBU9MDFZLO7iLY8-ygyefoJ5OQ,1529
10426
10428
  simo/notifications/migrations/0001_initial.py,sha256=Zh69AQ-EKlQKfqfnMDVRcxvo1MxRY-TFLCdnNcgqi6g,2003
10427
10429
  simo/notifications/migrations/0002_notification_instance.py,sha256=B3msbMeKvsuq-V7gvRADRjj5PFLayhi3pQvHZjqzO5g,563
10428
10430
  simo/notifications/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -10431,14 +10433,14 @@ simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.
10431
10433
  simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=YMBRHVon2nWDtIUbghckjnC12sIg_ykPWhV5aM0tto4,178
10432
10434
  simo/users/__init__.py,sha256=6a7uBpCWB_DR7p54rbHusc0xvi1qfT1ZCCQGb6TiBh8,52
10433
10435
  simo/users/admin.py,sha256=Xr7faGeupUKkpo1QLRm84OS63u-5Rf2ir_nVEaAPBZw,6839
10434
- simo/users/api.py,sha256=2AOt-IoG2MaOnq9XgWBpeT0ViszKZXKGUb-VmPdX7uI,12141
10436
+ simo/users/api.py,sha256=JIjSCg_VOkYRYoKJrc9svJ1NpTuQjONX_sGnZ-am1sQ,12825
10435
10437
  simo/users/apps.py,sha256=cq0A8-U1HALEwev0TicgFhr4CAu7Icz8rwq0HfOaL4E,207
10436
10438
  simo/users/auth_backends.py,sha256=bBSNXQJ88TRXaQxyh1aETfmOIfiDr08Jnj8rSY9sHDk,4074
10437
10439
  simo/users/auto_urls.py,sha256=lcJvteBsbHQMJieZpDz-63tDYejLApqsW3CUnDakd7k,272
10438
10440
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
10439
10441
  simo/users/managers.py,sha256=Fajwpm3wdMES73iPqoa_66J8g13bvUhjUtrexLKIcIU,312
10440
10442
  simo/users/middleware.py,sha256=GMCrnWSc_2qCleyQIkfQGdL-pU-UTEcSg1wPvIKZ9uk,1210
10441
- simo/users/models.py,sha256=X6xrCbsS22N_bWwTNH4r-zXQV0MoVzcthz3b8KlyQdw,19185
10443
+ simo/users/models.py,sha256=jq0045_J846w7aiTA6jqb0jliX_gHZaUuBZYsSUXa9o,19218
10442
10444
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
10443
10445
  simo/users/serializers.py,sha256=zzw1KONTnaTNBaU0r4rNVxJ827KzD6Z5LuQt27ZsQ98,2516
10444
10446
  simo/users/sso_urls.py,sha256=gQOaPvGMYFD0NCVSwyoWO-mTEHe5j9sbzV_RK7kdvp0,251
@@ -10448,14 +10450,14 @@ simo/users/utils.py,sha256=1HGSZyHRqQvdJ4RtAiZDg1juvgG8aOlrGXR7CcvsyQc,1886
10448
10450
  simo/users/views.py,sha256=dOQVvmlHG7ihWKJLFUBcqKOA0UDctlMKR0pTc36JZqg,3487
10449
10451
  simo/users/__pycache__/__init__.cpython-38.pyc,sha256=VFoDJE_SKKaPqqYaaBYd1Ndb1hjakkTo_u0EG_XJ1GM,211
10450
10452
  simo/users/__pycache__/admin.cpython-38.pyc,sha256=tL8b3f181AjcN2dSsDUPkqjpZziEOtVzI535SbnbDzc,7793
10451
- simo/users/__pycache__/api.cpython-38.pyc,sha256=lXK7f-8loDkhuppb1RAWyKxV6-jRE-ZvCyqJDu4Hgug,10224
10453
+ simo/users/__pycache__/api.cpython-38.pyc,sha256=M49GlN1f-IMXKpokLJVxcfVmXYxPneXQ9z9v0RFysQk,10411
10452
10454
  simo/users/__pycache__/apps.cpython-38.pyc,sha256=dgbWL8CxzzISJQTmq_4IztPJ2UzykNVdqA2Ae1PmeGk,605
10453
10455
  simo/users/__pycache__/auth_backends.cpython-38.pyc,sha256=n5nx2QSXNj2idzRcGE6bAagMN-8qxoCs580H1EFZXls,3105
10454
10456
  simo/users/__pycache__/auto_urls.cpython-38.pyc,sha256=K-3sz2h-cEitoflSmZk1t0eUg5mQMMGLNZFREVwG7_o,430
10455
10457
  simo/users/__pycache__/dynamic_settings.cpython-38.pyc,sha256=6F8JBjZkHykySnmZjNEzjS0ijbmPdcp9yUAZ5kqq_Fo,864
10456
10458
  simo/users/__pycache__/managers.cpython-38.pyc,sha256=8NvEXbI795f-BXs6CvE_Kp0PpWfYmEJIZ8Bh8H6S2PQ,705
10457
10459
  simo/users/__pycache__/middleware.cpython-38.pyc,sha256=Tj4nVEAvxEW3xA63fBRiJWRJpz_M848ZOqbHioc_IPE,1149
10458
- simo/users/__pycache__/models.cpython-38.pyc,sha256=kqpXK10DZ7C4UrR_LblK5Y1y8Mp3-0mNo6-IZSF6I9w,17844
10460
+ simo/users/__pycache__/models.cpython-38.pyc,sha256=bEyKyFodxErPeXSPvGHroYl4BKjDgLQY_4Pr_YTwLow,17859
10459
10461
  simo/users/__pycache__/permissions.cpython-38.pyc,sha256=ez5NxoL_JUeeH6GsKhvFreuA3FCBgGf9floSypdXUtM,633
10460
10462
  simo/users/__pycache__/serializers.cpython-38.pyc,sha256=Dy8RAcwNkNSXoJHvLp8fozURyHCtucqpSPyqZtbnMZc,3732
10461
10463
  simo/users/__pycache__/sso_urls.cpython-38.pyc,sha256=uAwDozpOmrhUald-8tOHANILXkH7-TI8fNYXOtPkSY8,402
@@ -10549,9 +10551,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10549
10551
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10550
10552
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10551
10553
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10552
- simo-2.5.4.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10553
- simo-2.5.4.dist-info/METADATA,sha256=3NOTH7yR5Q9wTFLJjHqlmikVEEvUeoSlSB8XFcl-fMI,1923
10554
- simo-2.5.4.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10555
- simo-2.5.4.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10556
- simo-2.5.4.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10557
- simo-2.5.4.dist-info/RECORD,,
10554
+ simo-2.5.5.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10555
+ simo-2.5.5.dist-info/METADATA,sha256=DQfobm2LHYKsXxNe8CJcy_auAd59Ox-Uym_vPMW-MCc,1923
10556
+ simo-2.5.5.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10557
+ simo-2.5.5.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10558
+ simo-2.5.5.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10559
+ simo-2.5.5.dist-info/RECORD,,
File without changes