simo 2.1.14__py3-none-any.whl → 2.2.2__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/controllers.py CHANGED
@@ -78,7 +78,7 @@ class ControllerBase(ABC):
78
78
  @property
79
79
  def info_template_path(self) -> str:
80
80
  return f"{self.__class__.__module__.split('.')[-2]}/" \
81
- f"controllers_info/{self.__class__.__name__.lower()}.md"
81
+ f"controllers_info/{self.__class__.__name__}.md"
82
82
 
83
83
  @abstractmethod
84
84
  def _validate_val(self, value, occasion=None):
Binary file
simo/fleet/controllers.py CHANGED
@@ -25,7 +25,7 @@ from .forms import (
25
25
  ColonelSwitchConfigForm, ColonelPWMOutputConfigForm,
26
26
  ColonelNumericSensorConfigForm, ColonelRGBLightConfigForm,
27
27
  ColonelDHTSensorConfigForm, DS18B20SensorConfigForm,
28
- BME680SensorConfigForm, MPC9808SensorConfigForm,
28
+ BME680SensorConfigForm, MPC9808SensorConfigForm, ENS160SensorConfigForm,
29
29
  DualMotorValveForm, BlindsConfigForm, BurglarSmokeDetectorConfigForm,
30
30
  TTLockConfigForm, DALIDeviceConfigForm, DaliLampForm, DaliGearGroupForm,
31
31
  DaliSwitchConfigForm,
@@ -210,6 +210,41 @@ class MPC9808TempSensor(FleeDeviceMixin, BaseNumericSensor):
210
210
  name = "MPC9808 Temperature Sensor (I2C)"
211
211
 
212
212
 
213
+ class ENS160AirQualitySensor(FleeDeviceMixin, BaseMultiSensor):
214
+ gateway_class = FleetGatewayHandler
215
+ config_form = ENS160SensorConfigForm
216
+ name = "ENS160 Air Quality Sensor (I2C)"
217
+
218
+ default_value = [
219
+ ["CO2", 0, "ppm"],
220
+ ["TVOC", 0, "ppb"],
221
+ ["AQI (UBA)", 0, ""]
222
+ ]
223
+
224
+ def get_co2(self):
225
+ try:
226
+ for entry in self.component.value:
227
+ if entry[0] == 'CO2':
228
+ return entry[1]
229
+ except:
230
+ return
231
+
232
+ def get_tvoc(self):
233
+ try:
234
+ for entry in self.component.value:
235
+ if entry[0] == 'TVOC':
236
+ return entry[1]
237
+ except:
238
+ return
239
+
240
+ def get_aqi(self):
241
+ try:
242
+ for entry in self.component.value:
243
+ if entry[0] == 'AQI (UBA)':
244
+ return entry[1]
245
+ except:
246
+ return
247
+
213
248
 
214
249
  class BasicOutputMixin:
215
250
  gateway_class = FleetGatewayHandler
simo/fleet/forms.py CHANGED
@@ -462,9 +462,9 @@ class BME680SensorConfigForm(ColonelComponentForm):
462
462
  ]
463
463
  )
464
464
  )
465
- i2c_address = forms.IntegerField(
466
- min_value=0, max_value=127, initial=118,
467
- help_text="Integer: 0 - 127. Dafault: 118"
465
+ i2c_address = forms.TypedChoiceField(
466
+ coerce=int, initial=118,
467
+ choices=((118, "0x76"), (119, "0x77")),
468
468
  )
469
469
  read_frequency_s = forms.IntegerField(
470
470
  initial=60, min_value=1, max_value=60*60*24,
@@ -482,6 +482,13 @@ class BME680SensorConfigForm(ColonelComponentForm):
482
482
  f"This interface is on {self.cleaned_data['interface'].colonel}, "
483
483
  f"however we need an interface from {self.cleaned_data['colonel']}."
484
484
  )
485
+ other_comp = Component.objects.filter(
486
+ config__colonel=self.cleaned_data['colonel'].id,
487
+ config__interface=self.cleaned_data['interface'].id,
488
+ config__i2c_address=self.cleaned_data['i2c_address']
489
+ ).exclude(id=self.instance.id).first()
490
+ if other_comp:
491
+ self.add_error('i2c_address', f'Already occupied by {other_comp}!')
485
492
  return self.cleaned_data
486
493
 
487
494
  def save(self, commit=True):
@@ -504,9 +511,14 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
504
511
  ]
505
512
  )
506
513
  )
507
- i2c_address = forms.IntegerField(
508
- min_value=0, max_value=127, initial=24,
509
- help_text="Integer: 0 - 127. Default: 24",
514
+ i2c_address = forms.TypedChoiceField(
515
+ coerce=int, initial=24,
516
+ choices=(
517
+ (24, "Default"),
518
+ (25, "AD0"), (25, "AD1"), (28, "AD2"),
519
+ (27, "AD0 + AD1"), (29, "AD0 + AD2"), (30, "AD1 + AD2"),
520
+ (31, "AD0 + AD1 + AD2")
521
+ ),
510
522
  )
511
523
  read_frequency_s = forms.IntegerField(
512
524
  initial=60, min_value=1, max_value=60 * 60 * 24,
@@ -524,6 +536,14 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
524
536
  f"This interface is on {self.cleaned_data['interface'].colonel}, "
525
537
  f"however we need an interface from {self.cleaned_data['colonel']}."
526
538
  )
539
+
540
+ other_comp = Component.objects.filter(
541
+ config__colonel=self.cleaned_data['colonel'].id,
542
+ config__interface=self.cleaned_data['interface'].id,
543
+ config__i2c_address=self.cleaned_data['i2c_address']
544
+ ).exclude(id=self.instance.id).first()
545
+ if other_comp:
546
+ self.add_error('i2c_address', f'Already occupied by {other_comp}!')
527
547
  return self.cleaned_data
528
548
 
529
549
  def save(self, commit=True):
@@ -532,6 +552,56 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
532
552
  return super().save(commit=commit)
533
553
 
534
554
 
555
+ class ENS160SensorConfigForm(ColonelComponentForm):
556
+ interface = ColonelInterfacesChoiceField(
557
+ queryset=Interface.objects.filter(type='i2c'),
558
+ widget=autocomplete.ListSelect2(
559
+ url='autocomplete-interfaces',
560
+ forward=[
561
+ forward.Self(),
562
+ forward.Field('colonel'),
563
+ forward.Const(
564
+ {'type': 'i2c'}, 'filters'
565
+ )
566
+ ]
567
+ )
568
+ )
569
+ i2c_address = forms.TypedChoiceField(
570
+ coerce=int, initial=83,
571
+ choices=((82, "0x52"), (83, "0x53")),
572
+ )
573
+ read_frequency_s = forms.IntegerField(
574
+ initial=10, min_value=1, max_value=60 * 60 * 24,
575
+ help_text='read and report air quality values every s. '
576
+ 'Can not be less than 1s.'
577
+
578
+ )
579
+
580
+ def clean(self):
581
+ if not self.cleaned_data.get('colonel'):
582
+ return self.cleaned_data
583
+ if self.cleaned_data['interface'].colonel != self.cleaned_data['colonel']:
584
+ self.add_error(
585
+ 'interface',
586
+ f"This interface is on {self.cleaned_data['interface'].colonel}, "
587
+ f"however we need an interface from {self.cleaned_data['colonel']}."
588
+ )
589
+ other_comp = Component.objects.filter(
590
+ config__colonel=self.cleaned_data['colonel'].id,
591
+ config__interface=self.cleaned_data['interface'].id,
592
+ config__i2c_address=self.cleaned_data['i2c_address']
593
+ ).exclude(id=self.instance.id).first()
594
+ if other_comp:
595
+ self.add_error('i2c_address', f'Already occupied by {other_comp}!')
596
+ return self.cleaned_data
597
+
598
+ def save(self, commit=True):
599
+ if 'interface' in self.cleaned_data:
600
+ self.instance.config['i2c_interface'] = \
601
+ self.cleaned_data['interface'].no
602
+ return super().save(commit=commit)
603
+
604
+
535
605
  class ColonelTouchSensorConfigForm(ColonelComponentForm):
536
606
  pin = ColonelPinChoiceField(
537
607
  label="Port",
@@ -0,0 +1,15 @@
1
+ ### Initial Start-Up
2
+
3
+ Initial Start-Up is the time the ENS160 needs to exhibit reasonable air quality readings after
4
+ its first ever power-on.
5
+ The ENS160 sensor raw resistance signals and sensitivities will change upon first power-on.
6
+ The change in resistance is greatest in the first 48 hours of operation. Therefore, the ENS160
7
+ employs a start-up algorithm, allowing eCO2-, TVOC- and AQI-output signals to be used from
8
+ first power-on after 1 hour of operation.
9
+
10
+ ### Warm-Up
11
+
12
+ Further to “Initial Start-Up” the conditioning or “Warm-Up” period is the time required to
13
+ achieve adequate sensor stability before measuring VOCs after idle periods or power-off.
14
+ Typically, the ENS160 requires 1 minute of warm-up before reasonable air quality readings
15
+ can be expected.
@@ -1048,8 +1048,8 @@ class Watering(ControllerBase):
1048
1048
  def _perform_schedule(self):
1049
1049
  self.component.refresh_from_db()
1050
1050
  next_run = self._get_next_run()
1051
- if self.component.config['next_run'] != next_run:
1052
- self.component.config['next_run'] = next_run
1051
+ if self.component.meta['next_run'] != next_run:
1052
+ self.component.meta['next_run'] = next_run
1053
1053
  self.component.save()
1054
1054
 
1055
1055
  if self.component.value['status'] == 'running_program':
@@ -1065,8 +1065,8 @@ class Watering(ControllerBase):
1065
1065
  str(localtime.weekday() + 1)
1066
1066
  ]
1067
1067
  if not times_to_start:
1068
- if self.component.config.get('next_run'):
1069
- self.component.config['next_run'] = None
1068
+ if self.component.meta.get('next_run'):
1069
+ self.component.meta['next_run'] = None
1070
1070
  self.component.save()
1071
1071
  return
1072
1072
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.1.14
3
+ Version: 2.2.2
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
@@ -23,7 +23,7 @@ simo/core/auto_urls.py,sha256=nNXEgLAAAQAhRWQDA9AbDtw-zcPKmu_pufJaSa8g818,1102
23
23
  simo/core/autocomplete_views.py,sha256=JT5LA2_Wtr60XYSAIqaXFKFYPjrmkEf6yunXD9y2zco,4022
24
24
  simo/core/base_types.py,sha256=qVh6MrXZEfN7bFOyFftC7u0yyz0PkvpsjllLBc6SCp4,616
25
25
  simo/core/context.py,sha256=98PXAMie43faRVBFkOG22uNpvGRNprcGhzjBFkrxaRY,1367
26
- simo/core/controllers.py,sha256=2XqqnpZy1nYwowflIKI4lcNMbotERf_YkbY0ztExfbY,29529
26
+ simo/core/controllers.py,sha256=y6nB_iv1KxsyNutGRYZIBAHua2BHuV7OMRBD9nJXFbg,29521
27
27
  simo/core/dynamic_settings.py,sha256=U9pY7p_hoeD1LxobIvxZqQ7Zn_4MhYMqZvsr4O0PAYs,1871
28
28
  simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
29
29
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
@@ -10191,8 +10191,8 @@ simo/fleet/api.py,sha256=Hxn84xI-Q77HxjINgRbjSJQOv9jii4OL20LxK0VSrS8,2499
10191
10191
  simo/fleet/auto_urls.py,sha256=UX66eR2ykMqFgfIllW-RTdjup5-FieCWl_BVm3CcXKg,702
10192
10192
  simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
10193
10193
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10194
- simo/fleet/controllers.py,sha256=ounEUw51X6EYA8xDcGNIik1bDbw4JR3DOGr1FKo4hHs,28829
10195
- simo/fleet/forms.py,sha256=CbrLN_gMCTo8u6fg0ovztkhdYEjHZmSr_3gzsDRMP84,54425
10194
+ simo/fleet/controllers.py,sha256=mASn88pUAFnkmd0UreXh2M0amZpjbv3xMghfTC8OB94,29744
10195
+ simo/fleet/forms.py,sha256=gp95NiQl6Lik-FzY6pSXNAa85VN-HeSOe5vr8Lc2pVc,57219
10196
10196
  simo/fleet/gateways.py,sha256=lKEJW0MgaOEiNnijH50DNSVChvaUT3TA3UurcI57P8k,5677
10197
10197
  simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
10198
10198
  simo/fleet/models.py,sha256=t_oi6EYSkg8Y5p3trJPv4MqW6AyUcylge9Bfw83mWCg,16462
@@ -10208,8 +10208,8 @@ simo/fleet/__pycache__/api.cpython-38.pyc,sha256=rL9fb7cCQatyFvXyKmlNOKmxVo8vHYe
10208
10208
  simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=Tc6a6BCXHjijP8U2jE2ghlJwnSNrGm59-hW5t-80wF0,689
10209
10209
  simo/fleet/__pycache__/base_types.cpython-38.pyc,sha256=deyPwjpT6xZiFxBGFnj5b7R-lbdOTh2krgpJhrcGVhc,274
10210
10210
  simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
10211
- simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=61dvQDl2nIuB4iaCzdBMwQnly_m0OvI7zteRS6sIm5U,23831
10212
- simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=7B6NZnY6yS8qrmv5zlTa07iUYmdv4nW7PTpOVfRn3OY,37436
10211
+ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=CagiILAhdfOsckuO6nh5ukKjAqke4O1m4LSHbAQru5I,24830
10212
+ simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=bdJgWyMfvGtnQiord-SawX8it5OVqJdY21hH5qkPjOQ,38820
10213
10213
  simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=0RKVn0ndreVKhsrukqeLPSdMnRrsQ_W7yeVeBkRLfIk,5058
10214
10214
  simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
10215
10215
  simo/fleet/__pycache__/models.cpython-38.pyc,sha256=GZ01BjdvTn6_XJBfV8VrSldJ67X06ne-xW4CsQ6N6Wc,13756
@@ -10295,11 +10295,12 @@ simo/fleet/migrations/__pycache__/0035_auto_20240514_0855.cpython-38.pyc,sha256=
10295
10295
  simo/fleet/migrations/__pycache__/0036_auto_20240605_0702.cpython-38.pyc,sha256=SDGibhEg0SYDF6fCte8l8NLChvHKn1qhLIrNZ_WoZQk,1654
10296
10296
  simo/fleet/migrations/__pycache__/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.cpython-38.pyc,sha256=ZappGrTStz3EIHlQ94y5ieXI-SkM9J1ashPey13ncFA,955
10297
10297
  simo/fleet/migrations/__pycache__/__init__.cpython-38.pyc,sha256=5k1KW0jeSDzw6RnVPRq4CaO13Lg7M0F-pxA_gqqZ6Mg,170
10298
- simo/fleet/templates/fleet/controllers_info/button.md,sha256=GIuxqG617174NEtpPeCGVocxO4YMe7-CacgVSu_L5-E,739
10298
+ simo/fleet/templates/fleet/controllers_info/Button.md,sha256=GIuxqG617174NEtpPeCGVocxO4YMe7-CacgVSu_L5-E,739
10299
+ simo/fleet/templates/fleet/controllers_info/ENS160AirQualitySensor.md,sha256=3LSTY9YPFuVPIbVsYCAifcotrXJcOXl2k774_vo6nAE,770
10299
10300
  simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10300
10301
  simo/generic/app_widgets.py,sha256=E_pnpA1hxMIhenRCrHoQ5cik06jm2BAHCkl_eo-OudU,1264
10301
10302
  simo/generic/base_types.py,sha256=djymox_boXTHX1BTTCLXrCH7ED-uAsV_idhaDOc3OLI,409
10302
- simo/generic/controllers.py,sha256=gojeCP_vSyLTaP4h56LqqLDykny5lEG-nLclieyVrRg,58292
10303
+ simo/generic/controllers.py,sha256=lnojSqDQ-1FArF2wH_c11y0qd906Wog-qrSG1DoqeXc,58284
10303
10304
  simo/generic/forms.py,sha256=IAfDtmEk1-CP0JBoetOD_ahLm64nK41GOUXjmbUzNtY,29550
10304
10305
  simo/generic/gateways.py,sha256=cc_q_g2HsI2_rWmr8yZ3spnMPwsgoYS5ApWRimc11wU,18831
10305
10306
  simo/generic/models.py,sha256=flpK2jsBFghrvRHzl6IKT-t3WZ-hNOj4ZP2vmBzx0K8,7657
@@ -10504,9 +10505,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10504
10505
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10505
10506
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10506
10507
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10507
- simo-2.1.14.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10508
- simo-2.1.14.dist-info/METADATA,sha256=ciR_wlaOnCRk7dYaoHrnRJHcDnBiH7rv14fZdxxT3A8,1848
10509
- simo-2.1.14.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
10510
- simo-2.1.14.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10511
- simo-2.1.14.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10512
- simo-2.1.14.dist-info/RECORD,,
10508
+ simo-2.2.2.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10509
+ simo-2.2.2.dist-info/METADATA,sha256=Ru0FCahOkylESH_ERFdMhvY_J5YwYXMmIBsjAZvsdKY,1847
10510
+ simo-2.2.2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
10511
+ simo-2.2.2.dist-info/entry_points.txt,sha256=SJBxiDpH7noO0STxVI_eRIsGR-nLgdXXeqCDe8cXlbM,65
10512
+ simo-2.2.2.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10513
+ simo-2.2.2.dist-info/RECORD,,
File without changes