simo 2.10.1__py3-none-any.whl → 2.10.3__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/tasks.py CHANGED
@@ -227,16 +227,20 @@ def sync_with_remote():
227
227
  instance.is_active = True
228
228
  instance.save()
229
229
 
230
- if weather:
231
- from simo.generic.controllers import Weather
232
- weather_component = Component.objects.filter(
233
- zone__instance=instance,
234
- controller_uid=Weather.uid
235
- ).first()
236
- if weather_component:
230
+ from simo.generic.controllers import Weather
231
+ weather_component = Component.objects.filter(
232
+ zone__instance=instance,
233
+ controller_uid=Weather.uid
234
+ ).first()
235
+ if weather_component:
236
+ if weather:
237
237
  weather_component.track_history = False
238
+ weather_component.alive = True
238
239
  weather_component.controller.set(weather)
239
240
  weather_component.save()
241
+ else:
242
+ weather_component.alive = False
243
+ weather_component.save()
240
244
 
241
245
  if new_instance:
242
246
  print(f"NEW INSTANCE: {instance}")
@@ -76,7 +76,7 @@ class Thermostat(ControllerBase):
76
76
  min = 40
77
77
  max = 95
78
78
  return {
79
- 'temperature_sensor': 0, 'heater': 0, 'cooler': 0,
79
+ 'temperature_sensor': 0, 'heaters': [], 'coolers': [],
80
80
  'engagement': 'dynamic','reaction_difference': 2,
81
81
  'min': min, 'max': max,
82
82
  'has_real_feel': False,
@@ -164,21 +164,35 @@ class Thermostat(ControllerBase):
164
164
  tz = pytz.timezone(self.component.zone.instance.timezone)
165
165
  timezone.activate(tz)
166
166
  temperature_sensor = Component.objects.filter(
167
- pk=self.component.config.get('temperature_sensor')
167
+ pk=self.component.config.get('temperature_sensor'),
168
+ alive=True
168
169
  ).first()
169
170
  heaters = Component.objects.filter(
170
- pk__in=self.component.config.get('heater')
171
+ pk__in=self.component.config.get('heaters', []),
172
+ alive=True
171
173
  )
172
174
  coolers = Component.objects.filter(
173
- pk__in=self.component.config.get('cooler')
175
+ pk__in=self.component.config.get('coolers', []),
176
+ alive=True
174
177
  )
175
178
 
179
+ if not heaters and not coolers:
180
+ self.component.error_msg = "No heaters/coolers"
181
+ self.component.alive = False
182
+ self.component.save()
183
+ return
184
+
176
185
  if not temperature_sensor or not temperature_sensor.alive:
177
186
  self.component.error_msg = "No temperature sensor"
178
187
  self.component.alive = False
179
188
  self.component.save()
180
189
  return
181
190
 
191
+ if self.component.error_msg or not self.component.alive:
192
+ self.component.error_msg = None
193
+ self.component.alive = True
194
+ self.component.save()
195
+
182
196
  current_temp = temperature_sensor.value
183
197
  if temperature_sensor.base_type == MultiSensor.base_type:
184
198
  value_dict = {}
@@ -191,6 +205,23 @@ class Thermostat(ControllerBase):
191
205
 
192
206
  target_temp = self.get_current_target_temperature()
193
207
  mode = self.component.config['user_config'].get('mode', 'auto')
208
+ prefer_heating = True
209
+
210
+ weather = Component.objects.filter(
211
+ zone__instance=self.component.zone.instance,
212
+ controller_uid=Weather.uid, alive=True
213
+ ).first()
214
+ if weather:
215
+ try:
216
+ feels_like = weather.value['main']['feels_like']
217
+ if feels_like:
218
+ instance = get_current_instance()
219
+ if instance.units_of_measure == 'imperial':
220
+ feels_like = round((feels_like * 9 / 5) + 32, 1)
221
+ if target_temp < feels_like:
222
+ prefer_heating = False
223
+ except:
224
+ pass
194
225
 
195
226
  low = target_temp - self.component.config['reaction_difference']
196
227
  high = target_temp + self.component.config['reaction_difference']
@@ -198,57 +229,37 @@ class Thermostat(ControllerBase):
198
229
  heating = False
199
230
  cooling = False
200
231
 
201
- if self.component.config.get('engagement', 'static'):
202
- if heaters:
203
- for heater in heaters:
204
- if current_temp < low:
205
- if heater.base_type == 'dimmer':
206
- heater.max_out()
207
- else:
208
- heater.turn_on()
209
- heating = True
210
- elif current_temp > high:
211
- heater.turn_off()
212
- heating = False
213
- else:
214
- if heater.value:
215
- heating = True
216
- break
217
-
218
- if coolers:
219
- for cooler in coolers:
220
- if heating: # Do not cool if heating!
221
- cooler.turn_off()
222
- else:
223
- if current_temp > high:
224
- if heater.base_type == 'dimmer':
225
- cooler.max_out()
226
- else:
227
- cooler.turn_on()
228
- cooling = True
229
- elif current_temp < low:
230
- if cooler.value:
231
- cooler.turn_off()
232
- cooling = False
233
- else:
234
- if cooler.value:
235
- cooling = True
236
- break
232
+ if self.component.config.get('engagement', 'static') == 'static':
233
+ if prefer_heating and heaters:
234
+ heating = self._engage_heating(
235
+ heaters, current_temp, low, high
236
+ )
237
+ if not heating:
238
+ cooling = self._engage_cooling(
239
+ coolers, current_temp, low, high
240
+ )
241
+ else:
242
+ cooling = self._engage_cooling(
243
+ coolers, current_temp, low, high
244
+ )
245
+ if not cooling:
246
+ heating = self._engage_heating(
247
+ heaters, current_temp, low, high
248
+ )
237
249
 
238
250
  else:
239
251
  window = high - low
240
- if heaters:
252
+ if prefer_heating and heaters:
241
253
  reach = high - current_temp
242
254
  reaction_force = self._get_reaction_force(window, reach)
243
255
  if reaction_force:
244
256
  heating = True
245
257
  self._engage_devices(heaters, reaction_force)
246
- if coolers:
247
- if heating: # Do not cool if heating!
248
- reaction_force = 0
249
- else:
250
- reach = current_temp - low
251
- reaction_force = self._get_reaction_force(window, reach)
258
+ elif coolers:
259
+ reach = current_temp - low
260
+ reaction_force = self._get_reaction_force(window, reach)
261
+ if reaction_force:
262
+ cooling = True
252
263
  self._engage_devices(coolers, reaction_force)
253
264
 
254
265
  self.component.set({
@@ -263,6 +274,45 @@ class Thermostat(ControllerBase):
263
274
  self.component.save()
264
275
 
265
276
 
277
+ def _engage_heating(self, heaters, current_temp, low, high):
278
+ heating = False
279
+ for heater in heaters:
280
+ if current_temp < low:
281
+ if heater.base_type == 'dimmer':
282
+ heater.max_out()
283
+ else:
284
+ heater.turn_on()
285
+ heating = True
286
+ elif current_temp > high:
287
+ heater.turn_off()
288
+ heating = False
289
+ else:
290
+ if heater.value:
291
+ heating = True
292
+ break
293
+ return heating
294
+
295
+
296
+ def _engage_cooling(self, coolers, current_temp, low, high):
297
+ cooling = False
298
+ for cooler in coolers:
299
+ if current_temp > high:
300
+ if cooler.base_type == 'dimmer':
301
+ cooler.max_out()
302
+ else:
303
+ cooler.turn_on()
304
+ cooling = True
305
+ elif current_temp < low:
306
+ if cooler.value:
307
+ cooler.turn_off()
308
+ cooling = False
309
+ else:
310
+ if cooler.value:
311
+ cooling = True
312
+ break
313
+ return cooling
314
+
315
+
266
316
  def _get_reaction_force(self, window, reach):
267
317
  if reach > window:
268
318
  reaction_force = 100
simo/generic/gateways.py CHANGED
@@ -439,7 +439,7 @@ class GenericGatewayHandler(
439
439
 
440
440
  step = 0
441
441
  while not exit.is_set():
442
- time.sleep(0.1)
442
+ time.sleep(0.25)
443
443
  step += 1
444
444
  remove_switches = []
445
445
  for id, data in self.pulsing_switches.items():
@@ -475,8 +475,8 @@ class GenericGatewayHandler(
475
475
  for id in remove_switches:
476
476
  del self.pulsing_switches[id]
477
477
 
478
- # Update with db every 5s just in case something is missed.
479
- if step < 50:
478
+ # Update with db every 10s just in case something is missed.
479
+ if step < 40:
480
480
  continue
481
481
  step = 0
482
482
 
Binary file
simo/users/api.py CHANGED
@@ -218,12 +218,15 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
218
218
  for speed in UserDeviceReportLog.objects.filter(
219
219
  user_device=user_device, instance=self.instance,
220
220
  datetime__lt=log_datetime - datetime.timedelta(seconds=3),
221
- datetime__gt=log_datetime - datetime.timedelta(seconds=30),
221
+ datetime__gt=log_datetime - datetime.timedelta(seconds=120),
222
222
  at_home=False, location__isnull=False
223
223
  ).values('speed_kmh',):
224
- sum += speed[0]
225
- sum += speed_kmh
226
- avg_speed_kmh = round(sum / (no_of_points + 1))
224
+ if speed:
225
+ sum += speed[0]
226
+ no_of_points += 1
227
+ if no_of_points > 2:
228
+ sum += speed_kmh
229
+ avg_speed_kmh = round(sum / (no_of_points + 1))
227
230
  else:
228
231
  location = self.instance.location
229
232
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simo
3
- Version: 2.10.1
3
+ Version: 2.10.3
4
4
  Summary: Smart Home Supremacy
5
5
  Author-email: Simanas Venčkauskas <simanas@simo.io>
6
6
  Project-URL: Homepage, https://simo.io
@@ -115,7 +115,7 @@ simo/core/serializers.py,sha256=Yeu6YRGMIZzAgnfIgm0_v4pWXDgsBCSlwWaDws_bMUg,2310
115
115
  simo/core/signal_receivers.py,sha256=PsAHAvdFKuNLjxNbb7UqjrX7VHtjdPAhP2y3vbhVGXs,7114
116
116
  simo/core/socket_consumers.py,sha256=UlxV9OvTUUXaoKKYT3-qf1TyGxyOPxIpFH5cPFepH1o,9584
117
117
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
118
- simo/core/tasks.py,sha256=Y9gXMd1QBjpO_4EAOuMSoHfK4H4qVcsg-36mPcx2sPU,17322
118
+ simo/core/tasks.py,sha256=usYjpNewy7uL7vIXtG1qB8ZnhJr-Orl_kVtKyR0GOjM,17456
119
119
  simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
120
120
  simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
121
121
  simo/core/views.py,sha256=BBh8U2P3rS_WccKN9hN6dhtiyXIfCX9I80zNwejqfe4,3666
@@ -176,7 +176,7 @@ simo/core/__pycache__/socket_consumers.cpython-312.pyc,sha256=Yph9SQTj6c3xr2HXKn
176
176
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=Mr1-x-vGjBNffbz0S6AKpJCuzHJgRm8kXefv3qVVY_E,8397
177
177
  simo/core/__pycache__/storage.cpython-312.pyc,sha256=VOD9via7BtpTbXe2jWsRovCIkeJofoX7Ts_Eyl9I_a4,934
178
178
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
179
- simo/core/__pycache__/tasks.cpython-312.pyc,sha256=YNRlJSItp3_hbF6uhcksjS3Px1LQOVbjkAaAXRu1Znw,22818
179
+ simo/core/__pycache__/tasks.cpython-312.pyc,sha256=0dDydxJ-M_he3dSQfL2Oaw_IJC5n4Ya7XOSu-heKCYM,22918
180
180
  simo/core/__pycache__/tasks.cpython-38.pyc,sha256=-J2is-l5XsfhamreN2TPQDTK-Jw6XGYL81bcVfjXsU8,11213
181
181
  simo/core/__pycache__/todos.cpython-312.pyc,sha256=bqguSv-oCCdlvzbMsm-7jAB-g0AvMFux1GL97XNJjyk,263
182
182
  simo/core/__pycache__/todos.cpython-38.pyc,sha256=lOqGZ58siHM3isoJV4r7sg8igrfE9fFd-jSfeBa0AQI,253
@@ -10606,9 +10606,9 @@ simo/fleet/templates/fleet/controllers_info/RoomZonePresenceSensor.md,sha256=Nun
10606
10606
  simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10607
10607
  simo/generic/app_widgets.py,sha256=y8W3jR76Hh26O9pPQyg2SophMbYIOtAWD33MPKbB8Mg,856
10608
10608
  simo/generic/base_types.py,sha256=u3SlfpNYaCwkVBwomWgso4ODzL71ay9MhiAW-bxgnDU,341
10609
- simo/generic/controllers.py,sha256=mtMkWH-76KlmXNwzHSfgbCEuvK1D4S9R1yvIdkjtl4E,48202
10609
+ simo/generic/controllers.py,sha256=SkXedPGmW17sErob2pyTj2xSq7FwVZXHAxBhZX8CKbc,49699
10610
10610
  simo/generic/forms.py,sha256=dItnnUTwc5EtTfDAHcL8Ihy_b9DVVA5ajFd8FXpA_dQ,26568
10611
- simo/generic/gateways.py,sha256=Vth-jSq1i81cm5G7cbuOlFJ4xKjmjLtvo2hn_djfPR4,19445
10611
+ simo/generic/gateways.py,sha256=oJ4VLaL0nMB6hnTMEpZasc4OTf8m1HWRWJMhUjHbeIU,19447
10612
10612
  simo/generic/models.py,sha256=59fkYowOX0imviIhA6uwupvuharrpBykmBm674rJNoI,7279
10613
10613
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
10614
10614
  simo/generic/socket_consumers.py,sha256=qesKZVhI56Kh7vdIUDD3hzDUi0FcXwIfcmE_a3YS6JQ,1772
@@ -10619,11 +10619,11 @@ simo/generic/__pycache__/app_widgets.cpython-312.pyc,sha256=ywoKk91YSEZxpyt9haG5
10619
10619
  simo/generic/__pycache__/app_widgets.cpython-38.pyc,sha256=D9b13pbMlirgHmjDnQhfLIDGSVINoSouHb4SWOeCRrs,1642
10620
10620
  simo/generic/__pycache__/base_types.cpython-312.pyc,sha256=h8Mwu49i-zmwTbL33JaLJfRDGOgkQh2_VqrfzEc4UQ4,616
10621
10621
  simo/generic/__pycache__/base_types.cpython-38.pyc,sha256=aV5NdIuvXR-ItKpI__MwcyPZHD6Z882TFdgYkPCkr1I,493
10622
- simo/generic/__pycache__/controllers.cpython-312.pyc,sha256=mPRJKmyjAiayb9ccDF1Wdm7-yI1q5DPvgqAdVGv1pf0,54042
10622
+ simo/generic/__pycache__/controllers.cpython-312.pyc,sha256=PJtqjFFJBh1UuKy7tVuAmnlhOKw4sv64akb-9zrBbU4,55883
10623
10623
  simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=jJjwKVaDYyazrRGNjUFoY74nr_jX_DEnsC9KjyxZCgc,30427
10624
10624
  simo/generic/__pycache__/forms.cpython-312.pyc,sha256=kjg_rV74sV2V3qg5qYuAPRySVHLbHrJeLQzlAIgajNs,35047
10625
10625
  simo/generic/__pycache__/forms.cpython-38.pyc,sha256=k8lz3taXdWAg5P9jcnw66mWH51pCc4SOsg32kVEtBCg,19416
10626
- simo/generic/__pycache__/gateways.cpython-312.pyc,sha256=naa_lnv2qQO9EALDYGajGAdU0wPqnaKjWE0ZKFjYJKQ,23195
10626
+ simo/generic/__pycache__/gateways.cpython-312.pyc,sha256=lg1j7spkhmGa5f4C49EKRXHHM2BrOJralhrsKXIsdYA,23196
10627
10627
  simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=GIeMT51oZU2OCFD4eUDFdSRRYE0Qf14AcOr_gdUqG94,12705
10628
10628
  simo/generic/__pycache__/models.cpython-312.pyc,sha256=ggaeX6BQa-0-KG50HadpRCWeW84Fbog0muT2gBkqLNQ,10190
10629
10629
  simo/generic/__pycache__/models.cpython-38.pyc,sha256=MZpum7syAFxuulf47K7gtUlJJ7xRD-IBUBAwUM1ZRnw,5825
@@ -10754,7 +10754,7 @@ simo/notifications/migrations/__pycache__/__init__.cpython-312.pyc,sha256=YMFc4Q
10754
10754
  simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=YMBRHVon2nWDtIUbghckjnC12sIg_ykPWhV5aM0tto4,178
10755
10755
  simo/users/__init__.py,sha256=6a7uBpCWB_DR7p54rbHusc0xvi1qfT1ZCCQGb6TiBh8,52
10756
10756
  simo/users/admin.py,sha256=2J_ZwrwAPw03Stb6msx5GvRpGCsDSC39RPpYBLGf8UY,7441
10757
- simo/users/api.py,sha256=K0hGtuHkjwlLiWjne6jruI-lfswHrPXfCHSLP-xqOfY,15050
10757
+ simo/users/api.py,sha256=V_LCUOV3p1_Z47CpQ5C-hNH4gUNuCkLRo5szGU1K6bs,15160
10758
10758
  simo/users/apps.py,sha256=cq0A8-U1HALEwev0TicgFhr4CAu7Icz8rwq0HfOaL4E,207
10759
10759
  simo/users/auth_backends.py,sha256=HxRp9iFvU1KqUhE7pA9YKEjqtBCJDbDqk_UMCD2Dwww,4361
10760
10760
  simo/users/auto_urls.py,sha256=RSUW3ai5LbMTknS8M7M5aOnG_YlFOVQrnNVNH-fkwlg,357
@@ -10773,7 +10773,7 @@ simo/users/__pycache__/__init__.cpython-312.pyc,sha256=n0GE5zxjujBUkv1t1CswZ9Gby
10773
10773
  simo/users/__pycache__/__init__.cpython-38.pyc,sha256=VFoDJE_SKKaPqqYaaBYd1Ndb1hjakkTo_u0EG_XJ1GM,211
10774
10774
  simo/users/__pycache__/admin.cpython-312.pyc,sha256=lTVuZQwkuw1bzSn0A0kt-8H6ruKas_YPb_61AxSYSoo,11465
10775
10775
  simo/users/__pycache__/admin.cpython-38.pyc,sha256=uL8TwAipkatZxanvQtBKKcOv8Fm3UvinBxsP0okrOZg,8443
10776
- simo/users/__pycache__/api.cpython-312.pyc,sha256=UxOSngKsHG8FD0d0BE0734v_uj9Ynz5kL9j5zXB91Vs,19424
10776
+ simo/users/__pycache__/api.cpython-312.pyc,sha256=iCQPIgjuhtRlpbNHx1Jnib9oDImPXYGyswiZCXLQshA,19476
10777
10777
  simo/users/__pycache__/api.cpython-38.pyc,sha256=zZ4DfNktgeVvLAtMpaPUv7AoAgbKr7SCt-4ghJk1zp4,10386
10778
10778
  simo/users/__pycache__/apps.cpython-312.pyc,sha256=6KefztC11cSg6VHJ7-sVDvOA-oq_jNMB8jMvmhcVZD4,707
10779
10779
  simo/users/__pycache__/apps.cpython-38.pyc,sha256=dgbWL8CxzzISJQTmq_4IztPJ2UzykNVdqA2Ae1PmeGk,605
@@ -10945,9 +10945,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10945
10945
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10946
10946
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10947
10947
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10948
- simo-2.10.1.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10949
- simo-2.10.1.dist-info/METADATA,sha256=9c6MSVrGuXjWD5IIrfhZ5CDlKqLEoZFxAnC20XDyNEg,2028
10950
- simo-2.10.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10951
- simo-2.10.1.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10952
- simo-2.10.1.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10953
- simo-2.10.1.dist-info/RECORD,,
10948
+ simo-2.10.3.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10949
+ simo-2.10.3.dist-info/METADATA,sha256=fE9OwAouErDLI5Gwxrsn2VlxlFHlNHtRH1RBO_ICaws,2028
10950
+ simo-2.10.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
10951
+ simo-2.10.3.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10952
+ simo-2.10.3.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10953
+ simo-2.10.3.dist-info/RECORD,,
File without changes