simo 2.5.25__py3-none-any.whl → 2.5.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of simo might be problematic. Click here for more details.

simo/core/middleware.py CHANGED
@@ -25,6 +25,12 @@ def introduce_instance(instance, request=None):
25
25
  request.instance = instance
26
26
 
27
27
 
28
+ def drop_current_instance(request=None):
29
+ if request and 'instance_id' in request.session:
30
+ request.session.pop('instance_id')
31
+ _thread_locals.instance = None
32
+
33
+
28
34
  def get_current_instance(request=None):
29
35
  from simo.core.models import Instance
30
36
  if request and request.session.get('instance_id'):
@@ -33,7 +39,8 @@ def get_current_instance(request=None):
33
39
  ).first()
34
40
  if not instance:
35
41
  del request.session['instance_id']
36
- introduce_instance(instance, request)
42
+ else:
43
+ introduce_instance(instance, request)
37
44
 
38
45
  instance = getattr(_thread_locals, 'instance', None)
39
46
 
simo/core/tasks.py CHANGED
@@ -231,7 +231,7 @@ def sync_with_remote():
231
231
  weather_component.save()
232
232
 
233
233
  if new_instance:
234
- print(f"NEW INSTANCE: {instance}")
234
+ print(f"NEW INSTANCE: {instance}")
235
235
  print(f"Users data: {users_data}")
236
236
 
237
237
 
@@ -295,10 +295,6 @@ def sync_with_remote():
295
295
  user.avatar_last_change = timezone.now()
296
296
  user.save()
297
297
 
298
- Instance.objects.all().exclude(
299
- uid__in=instance_uids
300
- ).update(is_active=False)
301
-
302
298
 
303
299
 
304
300
  @celery_app.task
simo/fleet/forms.py CHANGED
@@ -1175,6 +1175,11 @@ class BlindsConfigForm(ColonelComponentForm):
1175
1175
  "to go from fully closed to the start of open movement. <br>"
1176
1176
  "Usually it's in between of 1 - 3 seconds."
1177
1177
  )
1178
+ retain_angle = forms.BooleanField(
1179
+ required=False, initial=True,
1180
+ help_text="Retain blinds angle after adjusting it's "
1181
+ "position using physical buttons."
1182
+ )
1178
1183
  control_mode = forms.ChoiceField(
1179
1184
  label="App control mode", required=True, choices=(
1180
1185
  ('click', "Click"), ('hold', "Hold"), ('slide', "Slide")
@@ -1186,6 +1191,10 @@ class BlindsConfigForm(ColonelComponentForm):
1186
1191
  )
1187
1192
  )
1188
1193
 
1194
+ def __init__(self, *args, **kwargs):
1195
+ self.basic_fields.append('retain_angle')
1196
+ return super().__init__(*args, **kwargs)
1197
+
1189
1198
  def clean(self):
1190
1199
  super().clean()
1191
1200
 
simo/fleet/models.py CHANGED
@@ -275,7 +275,7 @@ def after_colonel_save(sender, instance, created, *args, **kwargs):
275
275
  if instance.type == 'game-changer':
276
276
  # occupy ports immediately
277
277
  Interface.objects.create(colonel=instance, no=1, type='i2c')
278
- Interface.objects.create(colonel=instance, no=2, type='dali')
278
+ Interface.objects.create(colonel=instance, no=2)
279
279
  elif instance.type == 'game-changer-mini':
280
280
  # only create interfaces, but do not ocuupy ports
281
281
  Interface.objects.create(colonel=instance, no=1)
@@ -13,7 +13,7 @@ import paho.mqtt.client as mqtt
13
13
  from channels.generic.websocket import AsyncWebsocketConsumer
14
14
  from asgiref.sync import sync_to_async
15
15
  from simo.core.utils.model_helpers import get_log_file_path
16
- from simo.core.middleware import introduce_instance
16
+ from simo.core.middleware import introduce_instance, drop_current_instance
17
17
  from simo.core.utils.logs import capture_socket_errors
18
18
  from simo.core.events import GatewayObjectCommand, get_event_obj
19
19
  from simo.core.models import Gateway, Instance, Component
@@ -87,8 +87,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
87
87
  tz = await sync_to_async(get_tz, thread_sensitive=True)()
88
88
  timezone.activate(tz)
89
89
 
90
- introduce_instance(self.instance)
91
-
92
90
  def get_colonel():
93
91
  defaults={
94
92
  'instance': self.instance,
@@ -240,7 +238,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
240
238
  }
241
239
 
242
240
  def get_components(colonel):
243
- introduce_instance(self.instance)
244
241
  return list(
245
242
  colonel.components.all().prefetch_related('slaves')
246
243
  )
@@ -299,6 +296,7 @@ class FleetConsumer(AsyncWebsocketConsumer):
299
296
  return config_data
300
297
 
301
298
  def on_mqtt_message(self, client, userdata, msg):
299
+ drop_current_instance()
302
300
  try:
303
301
  payload = json.loads(msg.payload)
304
302
 
@@ -366,7 +364,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
366
364
 
367
365
  async def receive(self, text_data=None, bytes_data=None):
368
366
  try:
369
- introduce_instance(self.instance)
370
367
  if text_data:
371
368
  print(f"{self.colonel}: {text_data}")
372
369
  data = json.loads(text_data)
simo/generic/forms.py CHANGED
@@ -371,7 +371,7 @@ class ThermostatConfigForm(BaseComponentForm):
371
371
  'temperature_sensor'
372
372
  ].base_type == MultiSensor.base_type else False
373
373
  self.instance.config['user_config']['use_real_feel'] = \
374
- self.cleaned_data['use_real_feel']
374
+ self.cleaned_data.get('use_real_feel', False)
375
375
  return super().save(commit)
376
376
 
377
377
 
simo/generic/gateways.py CHANGED
@@ -12,7 +12,7 @@ from django.db import connection as db_connection
12
12
  from django.db.models import Q
13
13
  import paho.mqtt.client as mqtt
14
14
  from simo.core.models import Component
15
- from simo.core.middleware import introduce_instance
15
+ from simo.core.middleware import introduce_instance, drop_current_instance
16
16
  from simo.core.gateways import BaseObjectCommandsGatewayHandler
17
17
  from simo.core.forms import BaseGatewayForm
18
18
  from simo.core.utils.logs import StreamToLogger
@@ -132,6 +132,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
132
132
 
133
133
  def watch_thermostats(self):
134
134
  from .controllers import Thermostat
135
+ drop_current_instance()
135
136
  for thermostat in Component.objects.filter(
136
137
  controller_uid=Thermostat.uid
137
138
  ):
@@ -141,15 +142,18 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
141
142
 
142
143
  def watch_alarm_clocks(self):
143
144
  from .controllers import AlarmClock
145
+ drop_current_instance()
144
146
  for alarm_clock in Component.objects.filter(
145
147
  controller_uid=AlarmClock.uid
146
148
  ):
149
+ introduce_instance(alarm_clock.zone.instance)
147
150
  tz = pytz.timezone(alarm_clock.zone.instance.timezone)
148
151
  timezone.activate(tz)
149
152
  alarm_clock.tick()
150
153
 
151
154
  def watch_scripts(self):
152
155
  # observe running scripts and drop the ones that are no longer alive
156
+ drop_current_instance()
153
157
  dead_processes = []
154
158
  for id, process in self.running_scripts.items():
155
159
  if process.is_alive():
@@ -183,8 +187,10 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
183
187
  self.start_script(script)
184
188
 
185
189
  def watch_watering(self):
190
+ drop_current_instance()
186
191
  from .controllers import Watering
187
192
  for watering in Component.objects.filter(controller_uid=Watering.uid):
193
+ introduce_instance(watering.zone.instance)
188
194
  tz = pytz.timezone(watering.zone.instance.timezone)
189
195
  timezone.activate(tz)
190
196
  if watering.value['status'] == 'running_program':
@@ -195,6 +201,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
195
201
  watering.controller._perform_schedule()
196
202
 
197
203
  def run(self, exit):
204
+ drop_current_instance()
198
205
  self.exit = exit
199
206
  self.logger = get_gw_logger(self.gateway_instance.id)
200
207
  for task, period in self.periodic_tasks:
@@ -261,9 +268,11 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
261
268
  Script, AlarmGroup
262
269
  )
263
270
  payload = json.loads(msg.payload)
271
+ drop_current_instance()
264
272
  component = get_event_obj(payload, Component)
265
273
  if not component:
266
274
  return
275
+ introduce_instance(component.zone.instance)
267
276
  try:
268
277
  if isinstance(component.controller, Script):
269
278
  if payload.get('set_val') == 'start':
@@ -373,6 +382,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
373
382
 
374
383
  def watch_alarm_events(self):
375
384
  from .controllers import AlarmGroup
385
+ drop_current_instance()
376
386
  for alarm in Component.objects.filter(
377
387
  controller_uid=AlarmGroup.uid, value='breached',
378
388
  meta__breach_start__gt=0
@@ -393,6 +403,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
393
403
  alarm.save(update_fields=['meta'])
394
404
 
395
405
  def watch_timers(self):
406
+ drop_current_instance()
396
407
  for component in Component.objects.filter(
397
408
  meta__timer_to__gt=0
398
409
  ).filter(meta__timer_to__lt=time.time()):
@@ -99,13 +99,17 @@ class SSOBackend(ModelBackend):
99
99
  user=user, instance=invitation.instance,
100
100
  defaults={'role': invitation.role}
101
101
  )
102
- user.is_active = True
102
+ if not user.is_active:
103
+ user.is_active = True
104
+ user.save()
103
105
 
104
106
  if not user.is_active:
105
107
  return
106
108
 
107
109
  if user_data.get('name'):
108
- user.name = user_data['name']
110
+ if user_data['name'] != user.name:
111
+ user.name = user_data['name']
112
+ user.save()
109
113
  if user_data.get('avatar_url') \
110
114
  and user.avatar_url != user_data.get('avatar_url'):
111
115
  user.avatar_url = user_data.get('avatar_url')
@@ -113,7 +117,5 @@ class SSOBackend(ModelBackend):
113
117
  user.avatar.save(
114
118
  os.path.basename(user.avatar_url), io.BytesIO(resp.content)
115
119
  )
116
- if user.get_dirty_fields():
117
- user.save()
118
120
 
119
121
  return user
simo/users/models.py CHANGED
@@ -154,7 +154,10 @@ def post_instance_user_save(sender, instance, created, **kwargs):
154
154
  dynamic_settings['core__needs_mqtt_acls_rebuild'] = True
155
155
 
156
156
 
157
- class User(DirtyFieldsMixin, AbstractBaseUser, SimoAdminMixin):
157
+ # DirtyFieldsMixin does not work with AbstractBaseUser model!!!
158
+ # goes in to RecursionError: maximum recursion depth exceeded
159
+ # when saving, so do not ever use it!!!!
160
+ class User(AbstractBaseUser, SimoAdminMixin):
158
161
  name = models.CharField(_('name'), max_length=150)
159
162
  email = models.EmailField(_('email address'), unique=True)
160
163
  avatar = ThumbnailerImageField(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.5.25
3
+ Version: 2.5.27
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,7 +51,7 @@ simo/core/forms.py,sha256=O40apPH7a4qX4WdCc10A1aoAaGWOpKqmjB8d-OhEKCo,21523
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=hExD7Vmw7eitk0vAjOwKzkwrtuw8YxpflF92j_CA2YY,3193
54
+ simo/core/middleware.py,sha256=eUFf6iP-Snx_0TE3MoXsSwqrd5IjlukqZk2GQGStRCo,3385
55
55
  simo/core/models.py,sha256=DXJXTtNdpn9yC4VArHp0yrhpRb7vGpwH2c-JvqLE56M,22784
56
56
  simo/core/permissions.py,sha256=INQPrUAIM3WXCvd7e6cmYytKaak8fMEn7VooX-fIds0,3002
57
57
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
@@ -59,7 +59,7 @@ simo/core/serializers.py,sha256=WgksN1Ombv240nfQR_UtmKslTWM9vz9Y0yTdN5usiHU,2189
59
59
  simo/core/signal_receivers.py,sha256=WYBRCFJhP83Ukd-Ipc1HlNyTXdTHD1rl0tV3uOKnYWY,8861
60
60
  simo/core/socket_consumers.py,sha256=trRZvBGTJ7xIbfdmVvn7zoiWp_qssSkMZykDrI5YQyE,9783
61
61
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
62
- simo/core/tasks.py,sha256=KjRx7X948A7j-ZKZNU0LucV-HGRQnd4ai6ikb49yYb0,16517
62
+ simo/core/tasks.py,sha256=N0E9ps1n1d8xayYElGlm7GDudVEwpWfFjC8Aq9fP7TA,16407
63
63
  simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
64
64
  simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
65
65
  simo/core/views.py,sha256=3SRZr00fyLQf8ja3U-9eekKt-ld5TvU1WQqUWprXfQ4,2390
@@ -10224,13 +10224,13 @@ simo/fleet/auto_urls.py,sha256=UX66eR2ykMqFgfIllW-RTdjup5-FieCWl_BVm3CcXKg,702
10224
10224
  simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
10225
10225
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10226
10226
  simo/fleet/controllers.py,sha256=fjri1GtCnflkkDpNqhTwy6i9CK6RDEB0Q_BtADzcG8E,29156
10227
- simo/fleet/forms.py,sha256=LbYphCtfpSxK3GwzSrcbMkB_spcspsf5FzYQFE9n-Q4,62614
10227
+ simo/fleet/forms.py,sha256=dNyM0hAKR93DPeKs6NJnE42prAeCR4MoXjkv5mGeQ4g,62952
10228
10228
  simo/fleet/gateways.py,sha256=lKEJW0MgaOEiNnijH50DNSVChvaUT3TA3UurcI57P8k,5677
10229
10229
  simo/fleet/managers.py,sha256=ZNeHFSkF5kzsl9E1DCBevOW6kXJlD6kw0LU4B-JMOG8,828
10230
- simo/fleet/models.py,sha256=xAffeAh5hf8NC94B66ZqmYoF7qDN53wEQ1xE2E9D8Xc,17524
10230
+ simo/fleet/models.py,sha256=zPplx_v64nfKBmb-nCb74aCVtEeY3m3SjEy-VhbnydU,17511
10231
10231
  simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
10232
10232
  simo/fleet/serializers.py,sha256=X2M0DFKVaxM6JFGDsdg3S2nJlLIcBvbujidZdfxD88w,2169
10233
- simo/fleet/socket_consumers.py,sha256=nfwMAzHHDWrvmwOIfPJqYHgr2fF-OJ_l6gWOnljyFWI,18434
10233
+ simo/fleet/socket_consumers.py,sha256=PwxGOqstI5wzglBHTvxosa9mwg8n3tWDQEPLb1vbxlc,18354
10234
10234
  simo/fleet/tasks.py,sha256=AGq9BXFNAqkhOANsPvId8yjEbDtVCB3MRsi_AKDpgIM,821
10235
10235
  simo/fleet/utils.py,sha256=wNJvURzLP3-aho3D3rfg07N9kWCaMIw5gOsmeeO9Nlg,4740
10236
10236
  simo/fleet/views.py,sha256=jT3GcGv_JEj3dqyfHH2whCnGqwT8YEAuFxRgIX4Dk9w,3237
@@ -10341,8 +10341,8 @@ simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10341
10341
  simo/generic/app_widgets.py,sha256=TPRLj4hri2hBuY6mrdwBiv-01z2hDxZmsup-GDD9LrM,953
10342
10342
  simo/generic/base_types.py,sha256=u3SlfpNYaCwkVBwomWgso4ODzL71ay9MhiAW-bxgnDU,341
10343
10343
  simo/generic/controllers.py,sha256=i-xKQ5PrNKwCuO0dFaHHUaD5rF9lDnq18ziVSNBENao,50134
10344
- simo/generic/forms.py,sha256=H841-wbWltnZ2-RXQEM1G8H4kfOcl88Qhg7bxE4VCiQ,28993
10345
- simo/generic/gateways.py,sha256=sMedpxIfpxqTx746DdhsIu-pzTrqduOSIb7i7XDX9GU,15339
10344
+ simo/generic/forms.py,sha256=tCbIZtbruBHjZRzulGXJQOjmxaGJ2uoKqjT1scScdDQ,29004
10345
+ simo/generic/gateways.py,sha256=MxPQzgEnnXSG-t6rErHZQJACFWegCWGaME640UIGrA8,15783
10346
10346
  simo/generic/models.py,sha256=Adq7ipWK-renxJlNW-SZnAq2oGEOwKx8EdUWaKnfcVQ,7597
10347
10347
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
10348
10348
  simo/generic/socket_consumers.py,sha256=K2OjphIhKJH48BvfFfoCOyCQZ1NmXb_phs6y1IP-qaQ,1757
@@ -10445,12 +10445,12 @@ simo/users/__init__.py,sha256=6a7uBpCWB_DR7p54rbHusc0xvi1qfT1ZCCQGb6TiBh8,52
10445
10445
  simo/users/admin.py,sha256=9P0iIGAep2R1AUvZnROsRULbxwCYK9pCfSJ2X4aLLBg,6965
10446
10446
  simo/users/api.py,sha256=xe__HFxzOaKgrh75PFpP4nkSs5DvmJp8QvMDNhP5kLU,12127
10447
10447
  simo/users/apps.py,sha256=cq0A8-U1HALEwev0TicgFhr4CAu7Icz8rwq0HfOaL4E,207
10448
- simo/users/auth_backends.py,sha256=EErYrGti3TIlYH9Bxj0UFs5EKsbYMV4FP4wGfpdHtts,4165
10448
+ simo/users/auth_backends.py,sha256=KIw2AdjCUKfm_7Lql6aC4qdE6JznP0ECIMA5MVMLeiM,4251
10449
10449
  simo/users/auto_urls.py,sha256=lcJvteBsbHQMJieZpDz-63tDYejLApqsW3CUnDakd7k,272
10450
10450
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
10451
10451
  simo/users/managers.py,sha256=OHgEP85MBtdkdYxdstBd8RavTBT8F_2WyDxUJ9aCqqM,246
10452
10452
  simo/users/middleware.py,sha256=GMCrnWSc_2qCleyQIkfQGdL-pU-UTEcSg1wPvIKZ9uk,1210
10453
- simo/users/models.py,sha256=KcIanqB8xvgvTO_jAUJpoN6JSRJha_DhIDSs4lniFXA,19402
10453
+ simo/users/models.py,sha256=Ms5YiU_N1rDSxWMYErO1RnBiK7Jo8Ww_raYJZ5p4yL0,19551
10454
10454
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
10455
10455
  simo/users/serializers.py,sha256=zzw1KONTnaTNBaU0r4rNVxJ827KzD6Z5LuQt27ZsQ98,2516
10456
10456
  simo/users/sso_urls.py,sha256=gQOaPvGMYFD0NCVSwyoWO-mTEHe5j9sbzV_RK7kdvp0,251
@@ -10561,9 +10561,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10561
10561
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10562
10562
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10563
10563
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10564
- simo-2.5.25.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10565
- simo-2.5.25.dist-info/METADATA,sha256=0QbwBkQyX8aCdHsmCEsHZAP2gqvrBugk80H1VV06kRI,1924
10566
- simo-2.5.25.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10567
- simo-2.5.25.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10568
- simo-2.5.25.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10569
- simo-2.5.25.dist-info/RECORD,,
10564
+ simo-2.5.27.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10565
+ simo-2.5.27.dist-info/METADATA,sha256=iYNcZpbiLgJERBKWPk9fk0ZMXQqO7-pT2h-9B6N9YbE,1924
10566
+ simo-2.5.27.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10567
+ simo-2.5.27.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10568
+ simo-2.5.27.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10569
+ simo-2.5.27.dist-info/RECORD,,
File without changes