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 +1 -1
- simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
- simo/fleet/controllers.py +36 -1
- simo/fleet/forms.py +76 -6
- simo/fleet/templates/fleet/controllers_info/ENS160AirQualitySensor.md +15 -0
- simo/generic/controllers.py +4 -4
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/METADATA +1 -1
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/RECORD +14 -13
- /simo/fleet/templates/fleet/controllers_info/{button.md → Button.md} +0 -0
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/LICENSE.md +0 -0
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/WHEEL +0 -0
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/entry_points.txt +0 -0
- {simo-2.1.14.dist-info → simo-2.2.2.dist-info}/top_level.txt +0 -0
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__
|
|
81
|
+
f"controllers_info/{self.__class__.__name__}.md"
|
|
82
82
|
|
|
83
83
|
@abstractmethod
|
|
84
84
|
def _validate_val(self, value, occasion=None):
|
|
Binary file
|
|
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.
|
|
466
|
-
|
|
467
|
-
|
|
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.
|
|
508
|
-
|
|
509
|
-
|
|
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.
|
simo/generic/controllers.py
CHANGED
|
@@ -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.
|
|
1052
|
-
self.component.
|
|
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.
|
|
1069
|
-
self.component.
|
|
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
|
|
|
@@ -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=
|
|
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=
|
|
10195
|
-
simo/fleet/forms.py,sha256=
|
|
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=
|
|
10212
|
-
simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=
|
|
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/
|
|
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=
|
|
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.
|
|
10508
|
-
simo-2.
|
|
10509
|
-
simo-2.
|
|
10510
|
-
simo-2.
|
|
10511
|
-
simo-2.
|
|
10512
|
-
simo-2.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|