simo 2.6.7__py3-none-any.whl → 2.6.9__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 (34) hide show
  1. simo/automation/__pycache__/controllers.cpython-38.pyc +0 -0
  2. simo/automation/__pycache__/forms.cpython-38.pyc +0 -0
  3. simo/automation/__pycache__/gateways.cpython-38.pyc +0 -0
  4. simo/automation/controllers.py +12 -5
  5. simo/automation/forms.py +7 -1
  6. simo/automation/gateways.py +1 -0
  7. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  8. simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
  9. simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
  10. simo/core/__pycache__/gateways.cpython-38.pyc +0 -0
  11. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  12. simo/core/api.py +37 -0
  13. simo/core/api_meta.py +3 -20
  14. simo/core/controllers.py +25 -9
  15. simo/core/gateways.py +7 -1
  16. simo/core/serializers.py +13 -8
  17. simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
  18. simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
  19. simo/fleet/__pycache__/gateways.cpython-38.pyc +0 -0
  20. simo/fleet/controllers.py +8 -30
  21. simo/fleet/forms.py +1 -1
  22. simo/fleet/gateways.py +2 -0
  23. simo/fleet/migrations/0043_auto_20241203_0930.py +28 -0
  24. simo/fleet/migrations/__pycache__/0043_auto_20241203_0930.cpython-38.pyc +0 -0
  25. simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
  26. simo/generic/gateways.py +5 -0
  27. simo/users/migrations/0039_auto_20241117_1039.py +25 -24
  28. simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-38.pyc +0 -0
  29. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/METADATA +1 -1
  30. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/RECORD +34 -32
  31. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/LICENSE.md +0 -0
  32. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/WHEEL +0 -0
  33. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/entry_points.txt +0 -0
  34. {simo-2.6.7.dist-info → simo-2.6.9.dist-info}/top_level.txt +0 -0
@@ -156,6 +156,11 @@ class PresenceLighting(Script):
156
156
  ).first()
157
157
  if comp:
158
158
  condition['component'] = comp
159
+ condition['condition_value'] = \
160
+ comp.controller._string_to_vals(condition['value'])
161
+ if condition['op'] != 'in':
162
+ condition['condition_value'] = \
163
+ condition['condition_value'][0]
159
164
  self.conditions.append(condition)
160
165
  comp.on_change(self._on_condition)
161
166
  self.condition_comps[comp.id] = comp
@@ -193,6 +198,9 @@ class PresenceLighting(Script):
193
198
  if must_on and on_sensor:
194
199
  print("Presence detected!")
195
200
 
201
+ if must_on:
202
+ self.last_presence = 0
203
+
196
204
  additional_conditions_met = True
197
205
  for condition in self.conditions:
198
206
 
@@ -203,25 +211,24 @@ class PresenceLighting(Script):
203
211
  continue
204
212
 
205
213
  if condition['op'] == 'in':
206
- if comp.value not in self._string_to_vals(condition['value']):
214
+ if comp.value not in condition['condition_value']:
207
215
  if must_on and on_sensor:
208
216
  print(
209
217
  f"Condition not met: [{comp} value:{comp.value} "
210
- f"{condition['op']} {condition['value']}]"
218
+ f"{condition['op']} {condition['condition_value']}]"
211
219
  )
212
220
  additional_conditions_met = False
213
221
  break
214
222
 
215
- if not op(comp.value, condition['value']):
223
+ if not op(comp.value, condition['condition_value']):
216
224
  if must_on and on_sensor:
217
225
  print(
218
226
  f"Condition not met: [{comp} value:{comp.value} "
219
- f"{condition['op']} {condition['value']}]"
227
+ f"{condition['op']} {condition['condition_value']}]"
220
228
  )
221
229
  additional_conditions_met = False
222
230
  break
223
231
 
224
-
225
232
  if not self.is_on:
226
233
  if not must_on:
227
234
  return
simo/automation/forms.py CHANGED
@@ -150,7 +150,7 @@ class ConditionForm(forms.Form):
150
150
  for val in values:
151
151
  val = val.strip()
152
152
  if controller_val_type == bool:
153
- if val.lower() in ('0', 'false', 'none', 'null'):
153
+ if val.lower() in ('0', 'false', 'none', 'null', 'off'):
154
154
  final_val = False
155
155
  else:
156
156
  final_val = True
@@ -169,6 +169,12 @@ class ConditionForm(forms.Form):
169
169
  'value', f"{val} is not compatible with selected component."
170
170
  )
171
171
  continue
172
+
173
+ if final_val == True:
174
+ final_val = 'ON'
175
+ elif final_val == False:
176
+ final_val = 'OFF'
177
+
172
178
  final_values.append(final_val)
173
179
 
174
180
  if self.cleaned_data['op'] == 'in':
@@ -80,6 +80,7 @@ class ScriptRunHandler(multiprocessing.Process):
80
80
  class AutomationsGatewayHandler(BaseObjectCommandsGatewayHandler):
81
81
  name = "Automation"
82
82
  config_form = BaseGatewayForm
83
+ info = "Provides various types of automation capabilities"
83
84
 
84
85
  running_scripts = {}
85
86
  periodic_tasks = (
Binary file
simo/core/api.py CHANGED
@@ -716,6 +716,7 @@ class StatesViewSet(InstanceMixin, viewsets.GenericViewSet):
716
716
  })
717
717
 
718
718
 
719
+ # Legacy.
719
720
  class ControllerTypes(InstanceMixin, viewsets.GenericViewSet):
720
721
  url = 'core/controller-types'
721
722
  basename = 'controller-types'
@@ -733,7 +734,43 @@ class ControllerTypes(InstanceMixin, viewsets.GenericViewSet):
733
734
  for uid, cls in get_controller_types_map(user=request.user).items():
734
735
  if cls.gateway_class.name not in data:
735
736
  data[cls.gateway_class.name] = []
737
+ if not cls.manual_add:
738
+ continue
736
739
  data[cls.gateway_class.name].append({
740
+ 'uid': uid,
741
+ 'name': cls.name,
742
+ 'is_discoverable': cls.is_discoverable,
743
+ 'discovery_msg': cls.discovery_msg,
744
+ 'info': cls.info(cls)
745
+ })
746
+
747
+ return RESTResponse(data)
748
+
749
+
750
+ class GWControllerTypes(InstanceMixin, viewsets.GenericViewSet):
751
+ url = 'core/gw-controller-types'
752
+ basename = 'gw-controller-types'
753
+ queryset = []
754
+
755
+ def get_permissions(self):
756
+ permissions = super().get_permissions()
757
+ permissions.append(IsInstanceSuperuser())
758
+ return permissions
759
+
760
+ def list(self, request, *args, **kwargs):
761
+ from .utils.type_constants import get_controller_types_map
762
+ data = {}
763
+
764
+ for uid, cls in get_controller_types_map(user=request.user).items():
765
+ if cls.gateway_class.uid not in data:
766
+ data[cls.gateway_class.uid] = {
767
+ 'name': cls.gateway_class.name,
768
+ 'info': cls.gateway_class.info,
769
+ 'controllers': []
770
+ }
771
+ if not cls.manual_add:
772
+ continue
773
+ data[cls.gateway_class.uid]['controllers'].append({
737
774
  'uid': uid,
738
775
  'name': cls.name,
739
776
  'is_discoverable': cls.is_discoverable,
simo/core/api_meta.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from collections import OrderedDict
2
2
  from django.urls import reverse
3
3
  from django.utils.encoding import force_str
4
- from django.forms.utils import pretty_name
5
4
  from rest_framework.metadata import SimpleMetadata
6
5
  from rest_framework import serializers
7
6
  from rest_framework.utils.field_mapping import ClassLookupDict
@@ -97,7 +96,7 @@ class SIMOAPIMetadata(SimpleMetadata):
97
96
  field_info['child'] = self.get_field_info(field.child)
98
97
  elif getattr(field, 'fields', None):
99
98
  field.Meta.form = form_field.formset_cls.form
100
- field_info['children'] = self.get_formset_serializer_info(field)
99
+ field_info['children'] = self.get_serializer_info(field)
101
100
 
102
101
  if form_field and hasattr(form_field, 'queryset'):
103
102
  if form_field.queryset.model == Icon:
@@ -116,7 +115,7 @@ class SIMOAPIMetadata(SimpleMetadata):
116
115
  zone__instance=self.instance
117
116
  )
118
117
 
119
- if not field_info.get('read_only') and hasattr(field, 'choices'):
118
+ if not field_info.get('read_only') and hasattr(field, 'choices'):# and not hasattr(form_field, 'forward'):
120
119
  field_info['choices'] = [
121
120
  {
122
121
  'value': choice_value,
@@ -125,20 +124,4 @@ class SIMOAPIMetadata(SimpleMetadata):
125
124
  for choice_value, choice_name in field.choices.items()
126
125
  ]
127
126
 
128
- return field_info
129
-
130
-
131
- def get_formset_serializer_info(self, serializer):
132
- """
133
- Given an instance of a serializer, return a dictionary of metadata
134
- about its fields.
135
- """
136
- if hasattr(serializer, 'child'):
137
- # If this is a `ListSerializer` then we want to examine the
138
- # underlying child serializer instance instead.
139
- serializer = serializer.child
140
- return OrderedDict([
141
- (field_name, self.get_field_info(field))
142
- for field_name, field in serializer.get_fields().items()
143
- if not isinstance(field, serializers.HiddenField)
144
- ])
127
+ return field_info
simo/core/controllers.py CHANGED
@@ -40,6 +40,7 @@ class ControllerBase(ABC):
40
40
  manual_add = True # Can be added manually
41
41
  family = None
42
42
  masters_only = False # component can be created/modified by hub masters only
43
+ info_template_path = None
43
44
 
44
45
  @property
45
46
  @abstractmethod
@@ -76,11 +77,6 @@ class ControllerBase(ABC):
76
77
  :return: Default value of this base component type
77
78
  """
78
79
 
79
- @property
80
- def info_template_path(self) -> str:
81
- return f"{self.__class__.__module__.split('.')[-2]}/" \
82
- f"controllers_info/{self.__class__.__name__}.md"
83
-
84
80
  @abstractmethod
85
81
  def _validate_val(self, value, occasion=None):
86
82
  """
@@ -121,7 +117,8 @@ class ControllerBase(ABC):
121
117
  cls, '_process_discovery'
122
118
  )
123
119
 
124
- def info(self):
120
+ @classmethod
121
+ def info(cls, component=None):
125
122
  '''
126
123
  Override this to give users help on how to use this component type,
127
124
  after you do that, include any component instance specific information
@@ -130,10 +127,13 @@ class ControllerBase(ABC):
130
127
  along with any other relative information,
131
128
  regarding this particular component instance
132
129
  '''
130
+ if not cls.info_template_path:
131
+ cls.info_template_path = f"{cls.__module__.split('.')[-2]}/" \
132
+ f"controllers_info/{cls.__name__}.md"
133
133
  try:
134
134
  return render_to_string(
135
- self.info_template_path, {
136
- 'component': self.component if hasattr(self, 'component') else None
135
+ cls.info_template_path, {
136
+ 'component': component
137
137
  }
138
138
  )
139
139
  except:
@@ -214,7 +214,23 @@ class ControllerBase(ABC):
214
214
  '''
215
215
  val_type = type(self.default_value)
216
216
  v = str(v).strip('(').strip('[').rstrip(')').rstrip(']')
217
- return [val_type(val.strip()) for val in v.split(',')]
217
+ vals = []
218
+ for val in v.split(','):
219
+ val = val.strip()
220
+ if val.lower() in ('none', 'null'):
221
+ val = None
222
+ elif val_type == bool:
223
+ if val.lower() in ('0', 'false', 'off'):
224
+ val = False
225
+ else:
226
+ val = True
227
+ else:
228
+ try:
229
+ val = val_type(val)
230
+ except:
231
+ continue
232
+ vals.append(val)
233
+ return vals
218
234
 
219
235
  def send(self, value):
220
236
  self.component.refresh_from_db()
simo/core/gateways.py CHANGED
@@ -3,7 +3,7 @@ import time
3
3
  import json
4
4
  import paho.mqtt.client as mqtt
5
5
  from django.conf import settings
6
- from django.db import close_old_connections
6
+ from django.template.loader import render_to_string
7
7
  from abc import ABC, abstractmethod
8
8
  from simo.core.utils.helpers import classproperty
9
9
  from simo.core.events import GatewayObjectCommand, get_event_obj
@@ -33,6 +33,12 @@ class BaseGatewayHandler(ABC):
33
33
  def uid(cls):
34
34
  return ".".join([cls.__module__, cls.__name__])
35
35
 
36
+
37
+ @classproperty
38
+ @classmethod
39
+ def info(cls):
40
+ return
41
+
36
42
  def __init__(self, gateway_instance):
37
43
  self.gateway_instance = gateway_instance
38
44
  super().__init__()
simo/core/serializers.py CHANGED
@@ -131,7 +131,6 @@ class ComponentManyToManyRelatedField(serializers.Field):
131
131
  return self.queryset.filter(pk__in=data)
132
132
 
133
133
 
134
-
135
134
  class ComponentFormsetField(FormSerializer):
136
135
 
137
136
  class Meta:
@@ -152,9 +151,20 @@ class ComponentFormsetField(FormSerializer):
152
151
  }
153
152
 
154
153
  def __init__(self, formset_field, *args, **kwargs):
155
- self.Meta.form = formset_field.formset_cls.form
154
+ self.form = formset_field.formset_cls.form
156
155
  super().__init__(*args, **kwargs)
157
156
 
157
+ def get_form(self, data=None, **kwargs):
158
+ form_cls = self.form
159
+ instance = form_cls(data=data, **kwargs)
160
+ # Handle partial validation on the form side
161
+ if self.partial:
162
+ set_form_partial_validation(
163
+ instance, self.Meta.minimum_required
164
+ )
165
+ instance.prefix = ''
166
+ return instance
167
+
158
168
  def get_fields(self):
159
169
  ret = super(FormSerializerBase, self).get_fields()
160
170
 
@@ -164,7 +174,7 @@ class ComponentFormsetField(FormSerializer):
164
174
  FORM_SERIALIZER_FIELD_MAPPING
165
175
  )
166
176
 
167
- form = self.Meta.form
177
+ form = self.form
168
178
  for field_name, form_field in getattr(form, 'all_base_fields', form.base_fields).items():
169
179
 
170
180
  if field_name in getattr(self.Meta, 'exclude', []):
@@ -249,11 +259,6 @@ class ComponentFormsetField(FormSerializer):
249
259
 
250
260
  return ret
251
261
 
252
- def get_form(self, data=None, **kwargs):
253
- form = super().get_form(data=data, **kwargs)
254
- form.prefix = ''
255
- return form
256
-
257
262
  def create(self, validated_data):
258
263
  return validated_data
259
264
 
Binary file
simo/fleet/controllers.py CHANGED
@@ -25,7 +25,7 @@ from .forms import (
25
25
  ColonelSwitchConfigForm, ColonelPWMOutputConfigForm, DCDriverConfigForm,
26
26
  ColonelNumericSensorConfigForm, ColonelRGBLightConfigForm,
27
27
  ColonelDHTSensorConfigForm, DS18B20SensorConfigForm,
28
- BME680SensorConfigForm, MPC9808SensorConfigForm, ENS160SensorConfigForm,
28
+ BME680SensorConfigForm, MCP9808SensorConfigForm, ENS160SensorConfigForm,
29
29
  DualMotorValveForm, BlindsConfigForm, GateConfigForm,
30
30
  BurglarSmokeDetectorConfigForm,
31
31
  TTLockConfigForm, DALIDeviceConfigForm, DaliLampForm, DaliGearGroupForm,
@@ -100,36 +100,21 @@ class BurglarSmokeDetector(BinarySensor):
100
100
  ]
101
101
 
102
102
 
103
- # class AnalogSensor(FleeDeviceMixin, BasicSensorMixin, BaseNumericSensor):
104
- # config_form = ColonelNumericSensorConfigForm
105
- # name = "Analog sensor"
106
- #
107
- # def _get_occupied_pins(self):
108
- # return [
109
- # self.component.config['pin_no'],
110
- # ]
111
-
112
-
113
103
  class DS18B20Sensor(FleeDeviceMixin, BasicSensorMixin, BaseNumericSensor):
114
104
  config_form = DS18B20SensorConfigForm
115
105
  name = "DS18B20 Temperature sensor"
116
106
 
117
107
 
118
-
119
- # TODO: need to change this to {
120
- # 'temp': self.sensor.temperature, 'hum': self.sensor.humidity,
121
- # 'pressure': self.sensor.pressure, 'gas': self.sensor.gas
122
- # }
123
- # which is used by BME680Sensor
124
-
125
- class BaseClimateSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
108
+ class DHTSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
109
+ config_form = ColonelDHTSensorConfigForm
110
+ name = "DHT climate sensor"
126
111
  app_widget = NumericSensorWidget
127
112
 
128
113
  def __init__(self, *args, **kwargs):
129
114
  super().__init__(*args, **kwargs)
130
115
  self.sys_temp_units = 'C'
131
116
  if hasattr(self.component, 'zone') \
132
- and self.component.zone.instance.units_of_measure == 'imperial':
117
+ and self.component.zone.instance.units_of_measure == 'imperial':
133
118
  self.sys_temp_units = 'F'
134
119
 
135
120
  @property
@@ -164,23 +149,16 @@ class BaseClimateSensor(FleeDeviceMixin, BasicSensorMixin, BaseMultiSensor):
164
149
  return new_val
165
150
 
166
151
 
167
-
168
-
169
- class DHTSensor(BaseClimateSensor):
170
- config_form = ColonelDHTSensorConfigForm
171
- name = "DHT climate sensor"
172
-
173
-
174
152
  class BME680Sensor(FleeDeviceMixin, BaseMultiSensor):
175
153
  gateway_class = FleetGatewayHandler
176
154
  config_form = BME680SensorConfigForm
177
155
  name = "BME680 Climate Sensor (I2C)"
178
156
 
179
157
 
180
- class MPC9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
158
+ class MCP9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
181
159
  gateway_class = FleetGatewayHandler
182
- config_form = MPC9808SensorConfigForm
183
- name = "MPC9808 Temperature Sensor (I2C)"
160
+ config_form = MCP9808SensorConfigForm
161
+ name = "MCP9808 Temperature Sensor (I2C)"
184
162
 
185
163
  @property
186
164
  def default_value_units(self):
simo/fleet/forms.py CHANGED
@@ -501,7 +501,7 @@ class BME680SensorConfigForm(ColonelComponentForm):
501
501
  return super().save(commit=commit)
502
502
 
503
503
 
504
- class MPC9808SensorConfigForm(ColonelComponentForm):
504
+ class MCP9808SensorConfigForm(ColonelComponentForm):
505
505
  interface = Select2ModelChoiceField(
506
506
  queryset=Interface.objects.filter(type='i2c'),
507
507
  url='autocomplete-interfaces',
simo/fleet/gateways.py CHANGED
@@ -14,6 +14,8 @@ from simo.core.utils.serialization import deserialize_form_data
14
14
  class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
15
15
  name = "SIMO.io Fleet"
16
16
  config_form = BaseGatewayForm
17
+ info = "Provides components that run on SIMO.io colonel boards " \
18
+ "like The Game Changer"
17
19
 
18
20
  periodic_tasks = (
19
21
  ('look_for_updates', 600),
@@ -0,0 +1,28 @@
1
+ # Generated by Django 4.2.10 on 2024-12-03 09:30
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ def forwards_func(apps, schema_editor):
7
+ Component = apps.get_model("core", "Component")
8
+
9
+ for comp in Component.objects.filter(
10
+ controller_uid='simo.fleet.controllers.MPC9808TempSensor'
11
+ ):
12
+ comp.controller_uid = 'simo.fleet.controllers.MCP9808TempSensor'
13
+ comp.save()
14
+
15
+
16
+ def reverse_func(apps, schema_editor):
17
+ pass
18
+
19
+
20
+ class Migration(migrations.Migration):
21
+
22
+ dependencies = [
23
+ ('fleet', '0042_auto_20241120_1028'),
24
+ ]
25
+
26
+ operations = [
27
+ migrations.RunPython(forwards_func, reverse_func, elidable=True),
28
+ ]
simo/generic/gateways.py CHANGED
@@ -62,6 +62,9 @@ class CameraWatcher(threading.Thread):
62
62
  class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
63
63
  name = "Generic"
64
64
  config_form = BaseGatewayForm
65
+ info = "Provides generic type components which use other components to operate like " \
66
+ "thermostats, alarm groups, watering programs, alarm clocks," \
67
+ "etc. "
65
68
 
66
69
  running_scripts = {}
67
70
  periodic_tasks = (
@@ -242,6 +245,8 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
242
245
  class DummyGatewayHandler(BaseObjectCommandsGatewayHandler):
243
246
  name = "Dummy"
244
247
  config_form = BaseGatewayForm
248
+ info = "Provides dummy components that do absolutely anything, " \
249
+ "but comes in super handy when configuring custom automations."
245
250
 
246
251
  def perform_value_send(self, component, value):
247
252
  component.controller.set(value)
@@ -4,30 +4,31 @@ from django.db import migrations
4
4
 
5
5
 
6
6
  def forwards_func(apps, schema_editor):
7
- from simo.generic.scripting.helpers import haversine_distance
8
- UserDeviceReportLog = apps.get_model("users", "UserDeviceReportLog")
9
-
10
- logs = UserDeviceReportLog.objects.filter(
11
- instance__isnull=False
12
- ).select_related('instance')
13
-
14
- print("Calculate at_home on UserDeviceReportLog's!")
15
-
16
- bulk_update = []
17
- for log in tqdm(logs, total=logs.count()):
18
- log.at_home = False
19
- if not log.relay:
20
- log.at_home = True
21
- elif log.location:
22
- log.at_home = haversine_distance(
23
- log.instance.location, log.location
24
- ) < 250
25
- if log.at_home:
26
- bulk_update.append(log)
27
- if len(bulk_update) > 1000:
28
- UserDeviceReportLog.objects.bulk_update(bulk_update, ["at_home"])
29
- bulk_update = []
30
- UserDeviceReportLog.objects.bulk_update(bulk_update, ["at_home"])
7
+ pass
8
+ # from simo.automation.helpers import haversine_distance
9
+ # UserDeviceReportLog = apps.get_model("users", "UserDeviceReportLog")
10
+ #
11
+ # logs = UserDeviceReportLog.objects.filter(
12
+ # instance__isnull=False
13
+ # ).select_related('instance')
14
+ #
15
+ # print("Calculate at_home on UserDeviceReportLog's!")
16
+ #
17
+ # bulk_update = []
18
+ # for log in tqdm(logs, total=logs.count()):
19
+ # log.at_home = False
20
+ # if not log.relay:
21
+ # log.at_home = True
22
+ # elif log.location:
23
+ # log.at_home = haversine_distance(
24
+ # log.instance.location, log.location
25
+ # ) < 250
26
+ # if log.at_home:
27
+ # bulk_update.append(log)
28
+ # if len(bulk_update) > 1000:
29
+ # UserDeviceReportLog.objects.bulk_update(bulk_update, ["at_home"])
30
+ # bulk_update = []
31
+ # UserDeviceReportLog.objects.bulk_update(bulk_update, ["at_home"])
31
32
 
32
33
 
33
34
  def reverse_func(apps, schema_editor):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.6.7
3
+ Version: 2.6.9
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
@@ -13,18 +13,18 @@ simo/__pycache__/urls.cpython-38.pyc,sha256=u0x6EqT8S1YfDOSPgbI8Kf-RDlveY9OV-EDX
13
13
  simo/__pycache__/wsgi.cpython-38.pyc,sha256=TpRxO7VM_ql31hbKphVdanydC5RI1nHB4l0QA2pdWxo,322
14
14
  simo/automation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  simo/automation/app_widgets.py,sha256=gaqImMZjuMHm7nIb9a4D-Y3qipz_WhSPAHXcwGx4Uzs,199
16
- simo/automation/controllers.py,sha256=Py62mo8boFsreiGVAnalJt_1SJePxD67aCGma6zGjWg,10206
17
- simo/automation/forms.py,sha256=wJMaXE5ngO_o60jqxnf4Om09q48yXpWwRna0FkQCZYs,10081
18
- simo/automation/gateways.py,sha256=7r33NOAiRd_RGMMm44i0KYzuAuweQnEF4HxLo-Rpexs,9408
16
+ simo/automation/controllers.py,sha256=cgTuS9Gwi9R94FTi4kbN9VG74HhddHxEqlCZEbvE-jY,10553
17
+ simo/automation/forms.py,sha256=UWnkxw8pILPK0smRPTo4SLgsZl78zOySx7JIc30Bgtk,10228
18
+ simo/automation/gateways.py,sha256=wElqHHyNd2jdpWuhO9DQ0yORIrObSzJsgZ-4dlKCLo4,9471
19
19
  simo/automation/helpers.py,sha256=iP-fxxB8HsFQy3k2CjFubu86aMqvWgmh-p24DiyOrek,4330
20
20
  simo/automation/models.py,sha256=l45FHgeKGsfpLtd1X1PVFpIjB5JI4BlvKkodpcxm6aE,927
21
21
  simo/automation/serializers.py,sha256=PjyFrjdPK1mBsgbNhyqMi9SWzcymqTa742ipy0LhAN4,1996
22
22
  simo/automation/state.py,sha256=aZZvNBae7unnux_zGHCIWCV2z47hVJc-DIL72Hqfkeo,600
23
23
  simo/automation/__pycache__/__init__.cpython-38.pyc,sha256=YmP0xAD-mxpQHgdTZeC64sXChA8TriMZD1jckNYi3xg,164
24
24
  simo/automation/__pycache__/app_widgets.cpython-38.pyc,sha256=7DfUA9V_1MiwrOe_ta-ts8dYY8xXb9UMg2_9A3XoRcs,523
25
- simo/automation/__pycache__/controllers.cpython-38.pyc,sha256=s9YqMUTCzjIxNVrk36SrIvGrXWYLc9DR80Sa3orpg1o,7936
26
- simo/automation/__pycache__/forms.cpython-38.pyc,sha256=qxQZeTafJOT_lrXOKY6134XjIrx5OzABAZdncNnRV4E,7720
27
- simo/automation/__pycache__/gateways.cpython-38.pyc,sha256=W6OrugOLOGaYbibEWSs-zBZc8jQpNlO_NmJU-rmd6fU,7558
25
+ simo/automation/__pycache__/controllers.cpython-38.pyc,sha256=K0cTMm42Ia4k0p2ZLQOU8aiJjZh32Ku965QfqSR7Vsw,8038
26
+ simo/automation/__pycache__/forms.cpython-38.pyc,sha256=cpA5hA2Iz3JsPC0Dq01ki1I7S9c5DKRcXveHApI1dJo,7772
27
+ simo/automation/__pycache__/gateways.cpython-38.pyc,sha256=4gDB7AeKwumAty-1x1Uyh1dEckw-kntBafMNvayH-PA,7621
28
28
  simo/automation/__pycache__/helpers.cpython-38.pyc,sha256=4VSSarOFnUk_KExWwvDlx5dEhv8aHUCHMZDtGG--pUY,3627
29
29
  simo/automation/__pycache__/models.cpython-38.pyc,sha256=6gXdIMcrWaGACal2omj-b2if5JW8QvLIrtRfYVpDRQU,1230
30
30
  simo/automation/__pycache__/serializers.cpython-38.pyc,sha256=gWgcuPE8aY-TmuRLXCuSR74mvtKerpZ04m0MfPfw0AI,3405
@@ -61,29 +61,29 @@ simo/backups/migrations/__pycache__/0004_alter_backup_options_alter_backuplog_op
61
61
  simo/backups/migrations/__pycache__/__init__.cpython-38.pyc,sha256=Lz1fs6V05h2AoxTOLNye0do9bEMnyuaXB_hHOjG5-HU,172
62
62
  simo/core/__init__.py,sha256=_s2TjJfQImsMrTIxqLAx9AZie1Ojmm6sCHASdl3WLGU,50
63
63
  simo/core/admin.py,sha256=nmFDO57D5hXHDfl0wjJ9J5jBxyCqW4Gp_uqHhpS2uuw,18564
64
- simo/core/api.py,sha256=HWyzmFGbULndSaW3sdrQa_kw2zfjd7yzfYxErAij7cY,29070
64
+ simo/core/api.py,sha256=eJCV5kScDWfVUa7RprMWvu8PQlGX2T3vCGIhIl4Z6Jw,30306
65
65
  simo/core/api_auth.py,sha256=vCxvczA8aWNcW0VyKs5WlC_ytlqeGP_H_hkKUNVkCwM,1247
66
- simo/core/api_meta.py,sha256=7yvarprPAHV2VP7AZV8wOqmeWsJ_UInrzKMakkeXsXU,5686
66
+ simo/core/api_meta.py,sha256=e9iqVv-3d651lMvZY-ILG4F35Puh2XunnwykiBUbl5E,5055
67
67
  simo/core/app_widgets.py,sha256=VxZzapuc-a29wBH7JzpvNF2SK1ECrgNUySId5ke1ffc,2509
68
68
  simo/core/apps.py,sha256=CsqpiQerhmrMsH-wGiG-gQgXd9qEkIi-LUaA9cXpKSw,425
69
69
  simo/core/auto_urls.py,sha256=FBDclIeRp5UVWomIUbRzUgY-AoMk-r2qC2htlwKD4Lo,1106
70
70
  simo/core/autocomplete_views.py,sha256=sQbT2g1Y9HGLLKazKaNfnZmwa6RJlTek9XzkGQcx4P8,4363
71
71
  simo/core/base_types.py,sha256=WypW8hTfzveuTQtruGjLYAGQZIuczxTlW-SdRk3iQug,666
72
72
  simo/core/context.py,sha256=LKw1I4iIRnlnzoTCuSLLqDX7crHdBnMo3hjqYvVmzFc,1557
73
- simo/core/controllers.py,sha256=vAZwtwPb259Bw-3dPSXuDxIcErMnQ6YBpBaUh4HWghM,35656
73
+ simo/core/controllers.py,sha256=xqEtTWkIJSpgez2OmsLoYImR4ZPSzY20xR-qe8eMQpo,36129
74
74
  simo/core/dynamic_settings.py,sha256=bUs58XEZOCIEhg1TigR3LmYggli13KMryBZ9pC7ugAQ,1872
75
75
  simo/core/events.py,sha256=1_KIk5pJqdLPRQlCQ9xSyALst2Cn0b2lAEAJ3QjwIjE,4801
76
76
  simo/core/filters.py,sha256=6wbn8C2WvKTTjtfMwwLBp2Fib1V0-DMpS4iqJd6jJQo,2540
77
77
  simo/core/form_fields.py,sha256=wowWocYgxkKBr0WYzpKn4UvH4ScnImus56Tg2G8OPBc,2274
78
78
  simo/core/forms.py,sha256=CCKypzX32-Mp8LpyO0ffiPcwIitaw0F03e8A9ZL0Mhw,21586
79
- simo/core/gateways.py,sha256=m0eS3XjVe34Dge6xtoCq16kFWCKJcdQrT0JW0REqoq8,3715
79
+ simo/core/gateways.py,sha256=7SvBKuVwdYYLRoAP8FXT2qz63FBpns21vlSMW1bCDFg,3795
80
80
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
81
81
  simo/core/managers.py,sha256=n-b3I4uXzfHKTeB1VMjSaMsDUxp8FegFJwnbV1IsWQ4,3019
82
82
  simo/core/middleware.py,sha256=eUFf6iP-Snx_0TE3MoXsSwqrd5IjlukqZk2GQGStRCo,3385
83
83
  simo/core/models.py,sha256=QNVTnWeHAW6LVrs3eaR7WNMhwjICuQpXZ8vyH_2qCBo,22834
84
84
  simo/core/permissions.py,sha256=2YNRot2qoHjHKWPGOpO4PBseecctPbTlUQpepnFkCRs,3027
85
85
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
86
- simo/core/serializers.py,sha256=JN1B2IcLkjZB3XiAetxK8Awx9WNHPOFwrCOrGqTLdbE,22118
86
+ simo/core/serializers.py,sha256=OvwFIIKHJtBuAJPhILPLx-9ENADBSz5T6dHOuKKtC3g,22326
87
87
  simo/core/signal_receivers.py,sha256=xUnQrWFBMF0Uasj6PzpERPr6h6BR-ZjUb1NSakRSzQo,9458
88
88
  simo/core/socket_consumers.py,sha256=trRZvBGTJ7xIbfdmVvn7zoiWp_qssSkMZykDrI5YQyE,9783
89
89
  simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
@@ -94,29 +94,29 @@ simo/core/views.py,sha256=yx9I0byeVUa-LAOnklpWIYwpNNOf5m9fyjKBvj4YCh4,2475
94
94
  simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
95
95
  simo/core/__pycache__/__init__.cpython-38.pyc,sha256=ZJFM_XN0RmJMULQulgA_wFiOnEtsMoedcOWnXjH-Y8o,208
96
96
  simo/core/__pycache__/admin.cpython-38.pyc,sha256=WAfdq_hAdkW-_QwJ0E7NSd25yxnPRi_HjJ-uKFMJzcg,14146
97
- simo/core/__pycache__/api.cpython-38.pyc,sha256=0kALbhViLcVqxcxzc_mmT9TzZcONc0ZNzZCWscbxjWE,22459
97
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=uSPeR38cxPN2H875ky5tDlF_tkkuInzB92qaK4lQWUA,23249
98
98
  simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=mi3mu5qEKio_PvfQEvr3Q6AhdPLAHxzxAxrMbAz_pKU,1712
99
- simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=CpiIoUPpQkX8db8o150LtGo79nHnBoEWKeRF8NoY69o,4391
99
+ simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=PrJrXcjbhXQkYrvEVG9jpRzkB8XYBMRQuKjXrgU9POA,3742
100
100
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=oN657XMMZ6GYN9nblv7fX3kdnTEzSP9XV6PXM6Z0wl4,4358
101
101
  simo/core/__pycache__/apps.cpython-38.pyc,sha256=JL0BEqgXcSQvMlcK48PBpPfyDEkPMdO1Y0teqMRGirs,713
102
102
  simo/core/__pycache__/auto_urls.cpython-38.pyc,sha256=ib_ns5Ko8ybfrdJJWYVV1jevihxOFs39aBF4bez6Lzs,874
103
103
  simo/core/__pycache__/autocomplete_views.cpython-38.pyc,sha256=Er4fS5KhE2FB9g7-ckjS_RIWOv7qysuzdt1Ab7HUL5Q,4318
104
104
  simo/core/__pycache__/base_types.cpython-38.pyc,sha256=CX-qlF7CefRi_mCE954wYa9rUFR88mOl6g7fybDRu7g,803
105
105
  simo/core/__pycache__/context.cpython-38.pyc,sha256=NlTHt2GvXxA21AhBkeyOLfRFUuXw7wmwqyNhhcDl2cw,1373
106
- simo/core/__pycache__/controllers.cpython-38.pyc,sha256=Lt9JDheLB3qgaZZ9NACAEeg43IY9XxZHN3Y0c5JavMo,30710
106
+ simo/core/__pycache__/controllers.cpython-38.pyc,sha256=X9Dd2zKebwG_I93H63uYyS1WtqZRrjX8z7dqngtbSlM,30610
107
107
  simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=wGpnscX1DxFpRl54MQURhjz2aD3NJohSzw9JCFnzh2Y,2384
108
108
  simo/core/__pycache__/events.cpython-38.pyc,sha256=1y8YaZsiDkBOeIWzH7SQz4holmMG_RLlMWi8kuSZcoE,5280
109
109
  simo/core/__pycache__/filters.cpython-38.pyc,sha256=WBBDwcDQwOmgbrRhyUxenSN80rU4Eq9jQ6RcrRGCP_o,2440
110
110
  simo/core/__pycache__/form_fields.cpython-38.pyc,sha256=phMdhDFRmaFDhJSnasAg8VKNP6PxkPjFqkLwEuWicIs,3465
111
111
  simo/core/__pycache__/forms.cpython-38.pyc,sha256=9ogrGIBTmPWXUD3qgICo2oA-pBlgO2Bqg9hRv_-IUdE,17571
112
- simo/core/__pycache__/gateways.cpython-38.pyc,sha256=D1ooHL-iSpQrxnD8uAl4xWFJmm-QWZfbkLiLlFOMtdU,4553
112
+ simo/core/__pycache__/gateways.cpython-38.pyc,sha256=MG7VHsx0DcfjTqi9efDEomnp_oz7eOC0rLdyzUw4-Wk,4694
113
113
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
114
114
  simo/core/__pycache__/managers.cpython-38.pyc,sha256=6RTIxyjOgpQGtAqcUyE2vFPS09w1V5Wmd_vOV7rHRRI,3370
115
115
  simo/core/__pycache__/middleware.cpython-38.pyc,sha256=g3d4L2PwxFyRKIPMP9Hkdjk1PL9NarQd4hSHS55I8n8,2649
116
116
  simo/core/__pycache__/models.cpython-38.pyc,sha256=po4B4bMyA-KDBu8qbVwGjrpUZJQPVBB6dkfncEBKYnM,18554
117
117
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=UdtxCTXPEbe99vgZOfRz9wfKSYvUn9hSRbpIV9CJSyI,2988
118
118
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
119
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=xSz0o7EROKp4eKbMmTwm37j9jbAuTcN8PMqluRjZucQ,19551
119
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=SK8uPWorFZujwL4vBeLarwS5hPknoqREmDSGhX5bWO8,19616
120
120
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=h0AsNC33oLoADJlwUVfPB1suUYovfzjfc0SE41-3MjY,6778
121
121
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=KqbO1cOewodVPcy0-htVefyUjCuELKV0o7fOfYqfgPc,8490
122
122
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
@@ -10253,9 +10253,9 @@ simo/fleet/api.py,sha256=rJwAYJvp0uslW7O6Q4XOpOa8hfCdy3keUD7b3UNL43E,3424
10253
10253
  simo/fleet/auto_urls.py,sha256=UX66eR2ykMqFgfIllW-RTdjup5-FieCWl_BVm3CcXKg,702
10254
10254
  simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
10255
10255
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10256
- simo/fleet/controllers.py,sha256=w2Zf-hFXyaaekoHbar7pIfE0iGN0S__79rANFm23hW8,29157
10257
- simo/fleet/forms.py,sha256=S0OsfQ6VOm6lox2gSTKjRrIH0mlPcsAUhaplm6Wsiuw,64772
10258
- simo/fleet/gateways.py,sha256=lKEJW0MgaOEiNnijH50DNSVChvaUT3TA3UurcI57P8k,5677
10256
+ simo/fleet/controllers.py,sha256=PezfOT-1N_UONSsbyTXEIyGO6Po57KdEBRv4yzk_sw0,28605
10257
+ simo/fleet/forms.py,sha256=2pbX1otTb1HqJ3aksRWz-FbsJ3YIyx6weV_tMFonecY,64772
10258
+ simo/fleet/gateways.py,sha256=C7dyapWDlJ5erYPNLkSoH50I8kj0lIXicSno0_CrdXc,5783
10259
10259
  simo/fleet/managers.py,sha256=ZNeHFSkF5kzsl9E1DCBevOW6kXJlD6kw0LU4B-JMOG8,828
10260
10260
  simo/fleet/models.py,sha256=zPplx_v64nfKBmb-nCb74aCVtEeY3m3SjEy-VhbnydU,17511
10261
10261
  simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
@@ -10270,9 +10270,9 @@ simo/fleet/__pycache__/api.cpython-38.pyc,sha256=rZ1mkfkaMBEXhi9sw_jTKdk2CPJhBNx
10270
10270
  simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=Tc6a6BCXHjijP8U2jE2ghlJwnSNrGm59-hW5t-80wF0,689
10271
10271
  simo/fleet/__pycache__/base_types.cpython-38.pyc,sha256=deyPwjpT6xZiFxBGFnj5b7R-lbdOTh2krgpJhrcGVhc,274
10272
10272
  simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
10273
- simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=jpXIYOPPQyumLwiO-PbgB8L5WYKkvd5T5GlAFnBKHp8,24906
10274
- simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=yyRnT_AU1kCLo3ISyuXonzP8hoiu8SAvRxhu9WQPIoc,43550
10275
- simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=0RKVn0ndreVKhsrukqeLPSdMnRrsQ_W7yeVeBkRLfIk,5058
10273
+ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=UtuihR455FLsHFAtMBh6haJzypp_HTyo3o8kPH02gnI,24739
10274
+ simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=VQqXDYGpTMMOrV3PGXFbWD_49XjglqJO2LWIHidMom0,43550
10275
+ simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=MIpXuGWitGNdsxJ99fWvMXJ6sVE96ac7iR4K4aM4Sds,5148
10276
10276
  simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=Vmm23zoQnS3-uS5_WJt2n3wtjhLiEhLWaYxXJCU6Gts,1339
10277
10277
  simo/fleet/__pycache__/models.cpython-38.pyc,sha256=WUahZgETWlem5rVXlJ_vINFRM7OZWp5xpWXGMoeBXsM,14131
10278
10278
  simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
@@ -10323,6 +10323,7 @@ simo/fleet/migrations/0039_auto_20241016_1047.py,sha256=c75iDlPH9NPQohkNBt58NPl3
10323
10323
  simo/fleet/migrations/0040_alter_colonel_pwm_frequency.py,sha256=AiiYeLXEmBAFj1O3WdJB0xQy1KqfiErYR8yPpL8W7e4,498
10324
10324
  simo/fleet/migrations/0041_alter_colonel_instance_and_more.py,sha256=r3PzZERt4kM0ul_TFl-i7qS7n0ht0G8jS83nucMxZfQ,1181
10325
10325
  simo/fleet/migrations/0042_auto_20241120_1028.py,sha256=nXyOXyTqhYfR2IDpIX0E3oIhKI7ShI7TGZ0Uf1CzR1U,715
10326
+ simo/fleet/migrations/0043_auto_20241203_0930.py,sha256=wYfYEBurHB5pGOgL6M-z9EoOZGhW9glhT3BpNiMDoH4,651
10326
10327
  simo/fleet/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10327
10328
  simo/fleet/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=9kc1UyMEYkRNVnZ7iwZbiW1t3qWXROvWrI2G1BdzIaA,1250
10328
10329
  simo/fleet/migrations/__pycache__/0002_auto_20220422_0743.cpython-38.pyc,sha256=8oxhGb7rL8QYKlBLU3pOYcd8aHeQWDB9I8awkK04mXg,841
@@ -10366,6 +10367,7 @@ simo/fleet/migrations/__pycache__/0039_auto_20241016_1047.cpython-38.pyc,sha256=
10366
10367
  simo/fleet/migrations/__pycache__/0040_alter_colonel_pwm_frequency.cpython-38.pyc,sha256=o_trHQUyQfYzWO_iWmZpvzc-uVJlBjK-GfyKhPOVSjc,736
10367
10368
  simo/fleet/migrations/__pycache__/0041_alter_colonel_instance_and_more.cpython-38.pyc,sha256=76yu9gz3pcAq5IYbNeZIoOSgdi0HVqTvc3EdXLGriQI,1178
10368
10369
  simo/fleet/migrations/__pycache__/0042_auto_20241120_1028.cpython-38.pyc,sha256=yK2HRc7MYMc4i9ev7FaguBdnXUnUmpFn8E8JOP_yluA,1030
10370
+ simo/fleet/migrations/__pycache__/0043_auto_20241203_0930.cpython-38.pyc,sha256=0QWVIvorcCuhfuGFu0fMdu5vkxcQSosxjt8KT6Ld07E,980
10369
10371
  simo/fleet/migrations/__pycache__/__init__.cpython-38.pyc,sha256=5k1KW0jeSDzw6RnVPRq4CaO13Lg7M0F-pxA_gqqZ6Mg,170
10370
10372
  simo/fleet/templates/fleet/controllers_info/Button.md,sha256=GIuxqG617174NEtpPeCGVocxO4YMe7-CacgVSu_L5-E,739
10371
10373
  simo/fleet/templates/fleet/controllers_info/ENS160AirQualitySensor.md,sha256=3LSTY9YPFuVPIbVsYCAifcotrXJcOXl2k774_vo6nAE,770
@@ -10374,7 +10376,7 @@ simo/generic/app_widgets.py,sha256=y8W3jR76Hh26O9pPQyg2SophMbYIOtAWD33MPKbB8Mg,8
10374
10376
  simo/generic/base_types.py,sha256=u3SlfpNYaCwkVBwomWgso4ODzL71ay9MhiAW-bxgnDU,341
10375
10377
  simo/generic/controllers.py,sha256=9u6Z_69t1Pkfmbsepx4AOj3cJKrZhik2elVuZjuBYGA,41722
10376
10378
  simo/generic/forms.py,sha256=i1TDb8pvFBws2COlmLCH12dTY4MKElFlQoSu5pwdw_w,18967
10377
- simo/generic/gateways.py,sha256=apT1PxvTiciOMhAQMfIMZJJCI9r1Ke-zgoUhclqDCcA,8790
10379
+ simo/generic/gateways.py,sha256=3gvBoT4a5NuzdOX1GyzG8M462I1ScbhL8LmShcK-Vcc,9122
10378
10380
  simo/generic/models.py,sha256=Adq7ipWK-renxJlNW-SZnAq2oGEOwKx8EdUWaKnfcVQ,7597
10379
10381
  simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
10380
10382
  simo/generic/socket_consumers.py,sha256=K2OjphIhKJH48BvfFfoCOyCQZ1NmXb_phs6y1IP-qaQ,1757
@@ -10383,7 +10385,7 @@ simo/generic/__pycache__/app_widgets.cpython-38.pyc,sha256=D9b13pbMlirgHmjDnQhfL
10383
10385
  simo/generic/__pycache__/base_types.cpython-38.pyc,sha256=aV5NdIuvXR-ItKpI__MwcyPZHD6Z882TFdgYkPCkr1I,493
10384
10386
  simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=_JsNQrL8iR-SY3MlrGJqguoAYaDGg2KGL7IwA0jl3w4,27025
10385
10387
  simo/generic/__pycache__/forms.cpython-38.pyc,sha256=fm8tOkr4t0VUiwAOjibvRdh7FPPL2VNH2w78DZsMYW4,14380
10386
- simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=iTIYK_K-08-MFvz5qX1u5ITfXqopP9QkRnVdVHqE12M,7224
10388
+ simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=-sdbyRuRpngSIORp3Y94hoLzIL4nrj52HGbcDy4heSA,7507
10387
10389
  simo/generic/__pycache__/models.cpython-38.pyc,sha256=MZpum7syAFxuulf47K7gtUlJJ7xRD-IBUBAwUM1ZRnw,5825
10388
10390
  simo/generic/__pycache__/routing.cpython-38.pyc,sha256=xtxTUTBTdivzFyA5Wh7k-hUj1WDO_FiRq6HYXdbr9Ks,382
10389
10391
  simo/generic/__pycache__/socket_consumers.cpython-38.pyc,sha256=qJO5kvQLWhsQDOr1AtAtsAybuRWioxSkQei3Pc7rdP0,1737
@@ -10539,7 +10541,7 @@ simo/users/migrations/0035_instanceuser_last_seen_speed_kmh_and_more.py,sha256=l
10539
10541
  simo/users/migrations/0036_instanceuser_phone_on_charge_user_phone_on_charge.py,sha256=uHXLRmFAASdB9sPivYkRu7WV4rxZDI3RaEwl2i7U_xg,615
10540
10542
  simo/users/migrations/0037_rename_last_seen_location_datetime_instanceuser_last_seen_and_more.py,sha256=8f_7fC7k0Dm-0gGVHMI9_490BbEC_SfuAPrAADrZ7BA,1543
10541
10543
  simo/users/migrations/0038_userdevicereportlog_at_home_and_more.py,sha256=qL1ZjUJDiSrJat59ToqpNBwnMMPb3Q5mwHq-qd1eFcI,691
10542
- simo/users/migrations/0039_auto_20241117_1039.py,sha256=e64AJM2ZId516Px-gmAxkp2NmSC5Vjo_BBTGbYrFuKY,1310
10544
+ simo/users/migrations/0039_auto_20241117_1039.py,sha256=BCIIDfvRzIHaP3SM-Df1XYjWzVLugFqAYGcFofaQepE,1369
10543
10545
  simo/users/migrations/0040_userdevicereportlog_location_smoothed_and_more.py,sha256=umGDjQGpCrQocNxaCvwdTsOmSxcRC61NcUdHGUczoc4,855
10544
10546
  simo/users/migrations/0041_userdevicereportlog_speed_kmh_received.py,sha256=WoJ-ImX1lNIl7CKO_HMt3jbFjoenFGBUm9HZWidb-eA,433
10545
10547
  simo/users/migrations/0042_remove_userdevicereportlog_location_smoothed_and_more.py,sha256=p-GFu6qjkxqeA0TI8aaIum0k6fQfc39RIKbfGPSf0Yk,499
@@ -10585,7 +10587,7 @@ simo/users/migrations/__pycache__/0035_instanceuser_last_seen_speed_kmh_and_more
10585
10587
  simo/users/migrations/__pycache__/0036_instanceuser_phone_on_charge_user_phone_on_charge.cpython-38.pyc,sha256=y1ZDJ8VM5_vJOxTPRERjwukiGXJ89UhDc4bHiHZwQ_w,723
10586
10588
  simo/users/migrations/__pycache__/0037_rename_last_seen_location_datetime_instanceuser_last_seen_and_more.cpython-38.pyc,sha256=W4Rc6SRNNJ_yAYrEyoklD5LFmQPAL9mTDrXHMfP8R4I,1162
10587
10589
  simo/users/migrations/__pycache__/0038_userdevicereportlog_at_home_and_more.cpython-38.pyc,sha256=khDSeTH3-jJ4yO1D6-i3Pm_NekJkVwBSUJ-rAxu0cr4,836
10588
- simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-38.pyc,sha256=IEOIfvnUiV-GX9VI4W2UKJugC3nfwKfy7QdmS3pW6Ss,1377
10590
+ simo/users/migrations/__pycache__/0039_auto_20241117_1039.cpython-38.pyc,sha256=2Qi46pncWXhcy6EaqXdLuynw3nCxqDC_KtS_3MToH1g,798
10589
10591
  simo/users/migrations/__pycache__/0040_userdevicereportlog_location_smoothed_and_more.cpython-38.pyc,sha256=I0W00mt73gjKunnwAyf3kz1FKfgm2HRwCJY_ogATSS0,918
10590
10592
  simo/users/migrations/__pycache__/0041_userdevicereportlog_speed_kmh_received.cpython-38.pyc,sha256=XWC9Emcc1Bm498UZ-6Lo7-i2Vq77vndjMA9xRdJbdfU,676
10591
10593
  simo/users/migrations/__pycache__/0042_remove_userdevicereportlog_location_smoothed_and_more.cpython-38.pyc,sha256=sSnWjU7rg5LXlRCxUFb_m2lUIcB4EHgtAnl-C9MMJvE,656
@@ -10599,9 +10601,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10599
10601
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10600
10602
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10601
10603
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10602
- simo-2.6.7.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10603
- simo-2.6.7.dist-info/METADATA,sha256=Jar59TxU2gPodg0J4-1cPqMgEgAOOSb_Bfh9Hs_Qxuk,1952
10604
- simo-2.6.7.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10605
- simo-2.6.7.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10606
- simo-2.6.7.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10607
- simo-2.6.7.dist-info/RECORD,,
10604
+ simo-2.6.9.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10605
+ simo-2.6.9.dist-info/METADATA,sha256=cCWJSmJj43zsbyPzT4tUyfvv4mU2nbkwzh0nTHzyJdk,1952
10606
+ simo-2.6.9.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10607
+ simo-2.6.9.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
10608
+ simo-2.6.9.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10609
+ simo-2.6.9.dist-info/RECORD,,
File without changes