simo 2.0.24__py3-none-any.whl → 2.0.26__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/__pycache__/admin.cpython-38.pyc +0 -0
- simo/core/__pycache__/api.cpython-38.pyc +0 -0
- simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/core/__pycache__/forms.cpython-38.pyc +0 -0
- simo/core/__pycache__/middleware.cpython-38.pyc +0 -0
- simo/core/__pycache__/models.cpython-38.pyc +0 -0
- simo/core/__pycache__/permissions.cpython-38.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/core/admin.py +1 -0
- simo/core/api.py +35 -20
- simo/core/controllers.py +5 -1
- simo/core/forms.py +29 -1
- simo/core/middleware.py +1 -0
- simo/core/migrations/0032_auto_20240506_0834.py +24 -0
- simo/core/migrations/__pycache__/0032_auto_20240506_0834.cpython-38.pyc +0 -0
- simo/core/models.py +4 -2
- simo/core/permissions.py +9 -3
- simo/core/serializers.py +20 -3
- simo/core/utils/__pycache__/json.cpython-38.pyc +0 -0
- simo/core/utils/json.py +20 -0
- simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
- simo/fleet/forms.py +123 -174
- simo/generic/__pycache__/forms.cpython-38.pyc +0 -0
- simo/generic/forms.py +24 -25
- simo/users/__pycache__/admin.cpython-38.pyc +0 -0
- simo/users/__pycache__/models.cpython-38.pyc +0 -0
- simo/users/admin.py +0 -5
- simo/users/migrations/0027_permissionsrole_can_manage_components.py +18 -0
- simo/users/migrations/0028_auto_20240506_1146.py +22 -0
- simo/users/migrations/__pycache__/0027_permissionsrole_can_manage_components.cpython-38.pyc +0 -0
- simo/users/migrations/__pycache__/0028_auto_20240506_1146.cpython-38.pyc +0 -0
- simo/users/models.py +7 -6
- {simo-2.0.24.dist-info → simo-2.0.26.dist-info}/METADATA +1 -1
- {simo-2.0.24.dist-info → simo-2.0.26.dist-info}/RECORD +37 -29
- {simo-2.0.24.dist-info → simo-2.0.26.dist-info}/LICENSE.md +0 -0
- {simo-2.0.24.dist-info → simo-2.0.26.dist-info}/WHEEL +0 -0
- {simo-2.0.24.dist-info → simo-2.0.26.dist-info}/top_level.txt +0 -0
simo/fleet/forms.py
CHANGED
|
@@ -91,13 +91,16 @@ class ColonelComponentForm(BaseComponentForm):
|
|
|
91
91
|
def clean_colonel(self):
|
|
92
92
|
if not self.instance.pk:
|
|
93
93
|
return self.cleaned_data['colonel']
|
|
94
|
+
colonel = self.cleaned_data.get('colonel')
|
|
95
|
+
if not colonel:
|
|
96
|
+
return
|
|
94
97
|
org = self.instance.config.get('colonel')
|
|
95
|
-
if org and org !=
|
|
98
|
+
if org and org != colonel.id:
|
|
96
99
|
raise forms.ValidationError(
|
|
97
100
|
"Changing colonel after component is created "
|
|
98
101
|
"it is not allowed!"
|
|
99
102
|
)
|
|
100
|
-
return
|
|
103
|
+
return colonel
|
|
101
104
|
|
|
102
105
|
def _clean_pin(self, field_name):
|
|
103
106
|
if self.cleaned_data[field_name].colonel != self.cleaned_data['colonel']:
|
|
@@ -153,7 +156,7 @@ class ColonelComponentForm(BaseComponentForm):
|
|
|
153
156
|
|
|
154
157
|
def save(self, commit=True):
|
|
155
158
|
obj = super().save(commit)
|
|
156
|
-
if commit:
|
|
159
|
+
if commit and 'colonel' in self.cleaned_data:
|
|
157
160
|
self.cleaned_data['colonel'].components.add(obj)
|
|
158
161
|
self.cleaned_data['colonel'].rebuild_occupied_pins()
|
|
159
162
|
self.cleaned_data['colonel'].save()
|
|
@@ -211,7 +214,7 @@ class ColonelBinarySensorConfigForm(ColonelComponentForm):
|
|
|
211
214
|
|
|
212
215
|
def clean(self):
|
|
213
216
|
super().clean()
|
|
214
|
-
if not self.cleaned_data
|
|
217
|
+
if 'colonel' not in self.cleaned_data:
|
|
215
218
|
return self.cleaned_data
|
|
216
219
|
if 'pin' not in self.cleaned_data:
|
|
217
220
|
return self.cleaned_data
|
|
@@ -251,7 +254,8 @@ class ColonelBinarySensorConfigForm(ColonelComponentForm):
|
|
|
251
254
|
|
|
252
255
|
|
|
253
256
|
def save(self, commit=True):
|
|
254
|
-
|
|
257
|
+
if 'pin' in self.cleaned_data:
|
|
258
|
+
self.instance.config['pin_no'] = self.cleaned_data['pin'].no
|
|
255
259
|
return super().save(commit=commit)
|
|
256
260
|
|
|
257
261
|
|
|
@@ -291,7 +295,7 @@ class ColonelNumericSensorConfigForm(ColonelComponentForm, NumericSensorForm):
|
|
|
291
295
|
|
|
292
296
|
def clean(self):
|
|
293
297
|
super().clean()
|
|
294
|
-
if not self.cleaned_data
|
|
298
|
+
if 'colonel' not in self.cleaned_data:
|
|
295
299
|
return self.cleaned_data
|
|
296
300
|
if 'pin' not in self.cleaned_data:
|
|
297
301
|
return self.cleaned_data
|
|
@@ -302,7 +306,8 @@ class ColonelNumericSensorConfigForm(ColonelComponentForm, NumericSensorForm):
|
|
|
302
306
|
|
|
303
307
|
|
|
304
308
|
def save(self, commit=True):
|
|
305
|
-
|
|
309
|
+
if 'pin' in self.cleaned_data:
|
|
310
|
+
self.instance.config['pin_no'] = self.cleaned_data['pin'].no
|
|
306
311
|
return super().save(commit=commit)
|
|
307
312
|
|
|
308
313
|
|
|
@@ -329,7 +334,7 @@ class DS18B20SensorConfigForm(ColonelComponentForm, NumericSensorForm):
|
|
|
329
334
|
|
|
330
335
|
def clean(self):
|
|
331
336
|
super().clean()
|
|
332
|
-
if not self.cleaned_data
|
|
337
|
+
if 'colonel' not in self.cleaned_data:
|
|
333
338
|
return self.cleaned_data
|
|
334
339
|
if 'pin' not in self.cleaned_data:
|
|
335
340
|
return self.cleaned_data
|
|
@@ -339,7 +344,8 @@ class DS18B20SensorConfigForm(ColonelComponentForm, NumericSensorForm):
|
|
|
339
344
|
return self.cleaned_data
|
|
340
345
|
|
|
341
346
|
def save(self, commit=True):
|
|
342
|
-
|
|
347
|
+
if 'pin' in self.cleaned_data:
|
|
348
|
+
self.instance.config['pin_no'] = self.cleaned_data['pin'].no
|
|
343
349
|
return super().save(commit=commit)
|
|
344
350
|
|
|
345
351
|
|
|
@@ -385,7 +391,8 @@ class ColonelDHTSensorConfigForm(ColonelComponentForm):
|
|
|
385
391
|
return self.cleaned_data
|
|
386
392
|
|
|
387
393
|
def save(self, commit=True):
|
|
388
|
-
|
|
394
|
+
if 'pin' in self.cleaned_data:
|
|
395
|
+
self.instance.config['pin_no'] = self.cleaned_data['pin'].no
|
|
389
396
|
return super().save(commit=commit)
|
|
390
397
|
|
|
391
398
|
|
|
@@ -415,7 +422,8 @@ class BME680SensorConfigForm(ColonelComponentForm):
|
|
|
415
422
|
)
|
|
416
423
|
|
|
417
424
|
def save(self, commit=True):
|
|
418
|
-
|
|
425
|
+
if 'interface' in self.cleaned_data:
|
|
426
|
+
self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
|
|
419
427
|
return super().save(commit=commit)
|
|
420
428
|
|
|
421
429
|
|
|
@@ -445,7 +453,8 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
|
|
|
445
453
|
)
|
|
446
454
|
|
|
447
455
|
def save(self, commit=True):
|
|
448
|
-
|
|
456
|
+
if 'interface' in self.cleaned_data:
|
|
457
|
+
self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
|
|
449
458
|
return super().save(commit=commit)
|
|
450
459
|
|
|
451
460
|
|
|
@@ -472,7 +481,7 @@ class ColonelTouchSensorConfigForm(ColonelComponentForm):
|
|
|
472
481
|
|
|
473
482
|
def clean(self):
|
|
474
483
|
super().clean()
|
|
475
|
-
if not self.cleaned_data
|
|
484
|
+
if 'colonel' not in self.cleaned_data:
|
|
476
485
|
return self.cleaned_data
|
|
477
486
|
if 'pin' not in self.cleaned_data:
|
|
478
487
|
return self.cleaned_data
|
|
@@ -483,7 +492,8 @@ class ColonelTouchSensorConfigForm(ColonelComponentForm):
|
|
|
483
492
|
|
|
484
493
|
|
|
485
494
|
def save(self, commit=True):
|
|
486
|
-
|
|
495
|
+
if 'pin' in self.cleaned_data:
|
|
496
|
+
self.instance.config['pin_no'] = self.cleaned_data['pin'].no
|
|
487
497
|
return super().save(commit=commit)
|
|
488
498
|
|
|
489
499
|
|
|
@@ -528,35 +538,33 @@ class ColonelSwitchConfigForm(ColonelComponentForm):
|
|
|
528
538
|
|
|
529
539
|
def __init__(self, *args, **kwargs):
|
|
530
540
|
super().__init__(*args, **kwargs)
|
|
531
|
-
|
|
541
|
+
self.basic_fields.append('auto_off')
|
|
542
|
+
if self.instance.pk and 'slaves' in self.fields:
|
|
532
543
|
self.fields['slaves'].initial = self.instance.slaves.all()
|
|
533
544
|
|
|
534
545
|
def clean_slaves(self):
|
|
546
|
+
if 'slaves' not in self.cleaned_data:
|
|
547
|
+
return
|
|
535
548
|
if not self.cleaned_data['slaves'] or not self.instance:
|
|
536
549
|
return self.cleaned_data['slaves']
|
|
537
550
|
return validate_slaves(self.cleaned_data['slaves'], self.instance)
|
|
538
551
|
|
|
539
552
|
def clean(self):
|
|
540
553
|
super().clean()
|
|
541
|
-
if not self.cleaned_data.get('colonel'):
|
|
542
|
-
return self.cleaned_data
|
|
543
|
-
if not self.cleaned_data.get('output_pin'):
|
|
544
|
-
return self.cleaned_data
|
|
545
|
-
|
|
546
|
-
self._clean_pin('output_pin')
|
|
547
|
-
|
|
548
|
-
if not self.cleaned_data.get('controls'):
|
|
549
|
-
return self.cleaned_data
|
|
550
554
|
|
|
551
|
-
self.
|
|
555
|
+
if self.cleaned_data.get('output_pin'):
|
|
556
|
+
self._clean_pin('output_pin')
|
|
557
|
+
if self.cleaned_data.get('controls'):
|
|
558
|
+
self._clean_controls()
|
|
552
559
|
|
|
553
560
|
return self.cleaned_data
|
|
554
561
|
|
|
555
562
|
|
|
556
563
|
def save(self, commit=True):
|
|
557
|
-
|
|
564
|
+
if 'output_pin' in self.cleaned_data:
|
|
565
|
+
self.instance.config['output_pin_no'] = self.cleaned_data['output_pin'].no
|
|
558
566
|
obj = super().save(commit=commit)
|
|
559
|
-
if commit:
|
|
567
|
+
if commit and 'slaves' in self.cleaned_data:
|
|
560
568
|
obj.slaves.set(self.cleaned_data['slaves'])
|
|
561
569
|
return obj
|
|
562
570
|
|
|
@@ -628,7 +636,8 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
|
|
|
628
636
|
|
|
629
637
|
def __init__(self, *args, **kwargs):
|
|
630
638
|
super().__init__(*args, **kwargs)
|
|
631
|
-
|
|
639
|
+
self.basic_fields.extend(['turn_on_time', 'turn_off_time', 'skew'])
|
|
640
|
+
if self.instance.pk and 'slaves' in self.fields:
|
|
632
641
|
self.fields['slaves'].initial = self.instance.slaves.all()
|
|
633
642
|
|
|
634
643
|
def clean_slaves(self):
|
|
@@ -638,25 +647,18 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
|
|
|
638
647
|
|
|
639
648
|
def clean(self):
|
|
640
649
|
super().clean()
|
|
641
|
-
if
|
|
642
|
-
|
|
643
|
-
if
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
self._clean_pin('output_pin')
|
|
647
|
-
|
|
648
|
-
if not self.cleaned_data.get('controls'):
|
|
649
|
-
return self.cleaned_data
|
|
650
|
-
|
|
651
|
-
self._clean_controls()
|
|
652
|
-
|
|
650
|
+
if self.cleaned_data.get('output_pin'):
|
|
651
|
+
self._clean_pin('output_pin')
|
|
652
|
+
if self.cleaned_data.get('controls'):
|
|
653
|
+
self._clean_controls()
|
|
653
654
|
return self.cleaned_data
|
|
654
655
|
|
|
655
656
|
|
|
656
657
|
def save(self, commit=True):
|
|
657
|
-
|
|
658
|
+
if 'output_pin' in self.cleaned_data:
|
|
659
|
+
self.instance.config['output_pin_no'] = self.cleaned_data['output_pin'].no
|
|
658
660
|
obj = super().save(commit=commit)
|
|
659
|
-
if commit:
|
|
661
|
+
if commit and 'slaves' in self.cleaned_data:
|
|
660
662
|
obj.slaves.set(self.cleaned_data['slaves'])
|
|
661
663
|
return obj
|
|
662
664
|
|
|
@@ -716,7 +718,9 @@ class ColonelRGBLightConfigForm(ColonelComponentForm):
|
|
|
716
718
|
)
|
|
717
719
|
|
|
718
720
|
def save(self, commit=True):
|
|
719
|
-
|
|
721
|
+
if 'output_pin' in self.cleaned_data:
|
|
722
|
+
self.instance.config['output_pin_no'] = \
|
|
723
|
+
self.cleaned_data['output_pin'].no
|
|
720
724
|
return super().save(commit)
|
|
721
725
|
|
|
722
726
|
def clean_custom_timing(self):
|
|
@@ -740,31 +744,25 @@ class ColonelRGBLightConfigForm(ColonelComponentForm):
|
|
|
740
744
|
|
|
741
745
|
def clean(self):
|
|
742
746
|
super().clean()
|
|
743
|
-
if not self.cleaned_data.get('colonel'):
|
|
744
|
-
return self.cleaned_data
|
|
745
|
-
if not self.cleaned_data.get('output_pin'):
|
|
746
|
-
return self.cleaned_data
|
|
747
|
-
|
|
748
|
-
if self.cleaned_data.get('color_order'):
|
|
749
|
-
if self.cleaned_data['has_white']:
|
|
750
|
-
if len(self.cleaned_data['color_order']) != 4:
|
|
751
|
-
self.add_error(
|
|
752
|
-
"color_order",
|
|
753
|
-
_("4 colors expected for stripes with dedicated White led.")
|
|
754
|
-
)
|
|
755
|
-
else:
|
|
756
|
-
if len(self.cleaned_data['color_order']) != 3:
|
|
757
|
-
self.add_error(
|
|
758
|
-
"color_order",
|
|
759
|
-
_("3 colors expected for stripes without dedicated White led.")
|
|
760
|
-
)
|
|
761
747
|
|
|
762
748
|
self._clean_pin('output_pin')
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
749
|
+
if self.cleaned_data.get('controls'):
|
|
750
|
+
self._clean_controls()
|
|
751
|
+
|
|
752
|
+
if 'color_order' in self.cleaned_data:
|
|
753
|
+
if self.cleaned_data.get('color_order'):
|
|
754
|
+
if self.cleaned_data['has_white']:
|
|
755
|
+
if len(self.cleaned_data['color_order']) != 4:
|
|
756
|
+
self.add_error(
|
|
757
|
+
"color_order",
|
|
758
|
+
_("4 colors expected for stripes with dedicated White led.")
|
|
759
|
+
)
|
|
760
|
+
else:
|
|
761
|
+
if len(self.cleaned_data['color_order']) != 3:
|
|
762
|
+
self.add_error(
|
|
763
|
+
"color_order",
|
|
764
|
+
_("3 colors expected for stripes without dedicated White led.")
|
|
765
|
+
)
|
|
768
766
|
|
|
769
767
|
return self.cleaned_data
|
|
770
768
|
|
|
@@ -787,7 +785,7 @@ class DualMotorValveForm(ColonelComponentForm):
|
|
|
787
785
|
)
|
|
788
786
|
open_duration = forms.FloatField(
|
|
789
787
|
required=True, min_value=0.01, max_value=1000000000,
|
|
790
|
-
help_text="Time in seconds to open."
|
|
788
|
+
initial=2, help_text="Time in seconds to open."
|
|
791
789
|
)
|
|
792
790
|
close_pin = ColonelPinChoiceField(
|
|
793
791
|
queryset=ColonelPin.objects.filter(output=True),
|
|
@@ -805,27 +803,25 @@ class DualMotorValveForm(ColonelComponentForm):
|
|
|
805
803
|
)
|
|
806
804
|
close_duration = forms.FloatField(
|
|
807
805
|
required=True, min_value=0.01, max_value=1000000000,
|
|
808
|
-
help_text="Time in seconds to close."
|
|
806
|
+
initial=10, help_text="Time in seconds to close."
|
|
809
807
|
)
|
|
810
808
|
|
|
811
809
|
|
|
812
810
|
def clean(self):
|
|
813
811
|
super().clean()
|
|
814
|
-
if
|
|
815
|
-
|
|
816
|
-
if
|
|
817
|
-
|
|
818
|
-
if not self.cleaned_data.get('close_pin'):
|
|
819
|
-
return self.cleaned_data
|
|
820
|
-
|
|
821
|
-
self._clean_pin('open_pin')
|
|
822
|
-
self._clean_pin('close_pin')
|
|
823
|
-
|
|
812
|
+
if self.cleaned_data.get('open_pin'):
|
|
813
|
+
self._clean_pin('open_pin')
|
|
814
|
+
if self.cleaned_data.get('close_pin'):
|
|
815
|
+
self._clean_pin('close_pin')
|
|
824
816
|
return self.cleaned_data
|
|
825
817
|
|
|
826
818
|
def save(self, commit=True):
|
|
827
|
-
|
|
828
|
-
|
|
819
|
+
if 'open_pin' in self.cleaned_data:
|
|
820
|
+
self.instance.config['open_pin_no'] = \
|
|
821
|
+
self.cleaned_data['open_pin'].no
|
|
822
|
+
if 'close_pin' in self.cleaned_data:
|
|
823
|
+
self.instance.config['close_pin_no'] = \
|
|
824
|
+
self.cleaned_data['close_pin'].no
|
|
829
825
|
return super().save(commit=commit)
|
|
830
826
|
|
|
831
827
|
|
|
@@ -903,40 +899,37 @@ class BlindsConfigForm(ColonelComponentForm):
|
|
|
903
899
|
|
|
904
900
|
def clean(self):
|
|
905
901
|
super().clean()
|
|
906
|
-
if not self.cleaned_data.get('colonel'):
|
|
907
|
-
return self.cleaned_data
|
|
908
|
-
if not self.cleaned_data.get('open_pin'):
|
|
909
|
-
return self.cleaned_data
|
|
910
|
-
if not self.cleaned_data.get('close_pin'):
|
|
911
|
-
return self.cleaned_data
|
|
912
|
-
|
|
913
|
-
self._clean_pin('open_pin')
|
|
914
|
-
self._clean_pin('close_pin')
|
|
915
|
-
|
|
916
|
-
if 'controls' not in self.cleaned_data:
|
|
917
|
-
return self.cleaned_data
|
|
918
|
-
|
|
919
|
-
if len(self.cleaned_data['controls']) not in (0, 2):
|
|
920
|
-
self.add_error('controls', "Must have 0 or 2 controls")
|
|
921
|
-
return self.cleaned_data
|
|
922
|
-
|
|
923
|
-
if len(self.cleaned_data['controls']) == 2:
|
|
924
|
-
method = None
|
|
925
|
-
for c in self.cleaned_data['controls']:
|
|
926
|
-
if not method:
|
|
927
|
-
method = c['method']
|
|
928
|
-
else:
|
|
929
|
-
if c['method'] != method:
|
|
930
|
-
self.add_error('controls', "Both must use the same control method.")
|
|
931
|
-
return self.cleaned_data
|
|
932
|
-
|
|
933
|
-
self._clean_controls()
|
|
934
902
|
|
|
903
|
+
if self.cleaned_data.get('open_pin'):
|
|
904
|
+
self._clean_pin('open_pin')
|
|
905
|
+
if self.cleaned_data.get('close_pin'):
|
|
906
|
+
self._clean_pin('close_pin')
|
|
907
|
+
|
|
908
|
+
if 'controls' in self.cleaned_data:
|
|
909
|
+
if len(self.cleaned_data['controls']) not in (0, 2):
|
|
910
|
+
self.add_error('controls', "Must have 0 or 2 controls")
|
|
911
|
+
return self.cleaned_data
|
|
912
|
+
|
|
913
|
+
if len(self.cleaned_data['controls']) == 2:
|
|
914
|
+
method = None
|
|
915
|
+
for c in self.cleaned_data['controls']:
|
|
916
|
+
if not method:
|
|
917
|
+
method = c['method']
|
|
918
|
+
else:
|
|
919
|
+
if c['method'] != method:
|
|
920
|
+
self.add_error('controls', "Both must use the same control method.")
|
|
921
|
+
return self.cleaned_data
|
|
922
|
+
|
|
923
|
+
self._clean_controls()
|
|
935
924
|
return self.cleaned_data
|
|
936
925
|
|
|
937
926
|
def save(self, commit=True):
|
|
938
|
-
|
|
939
|
-
|
|
927
|
+
if 'open_pin' in self.cleaned_data:
|
|
928
|
+
self.instance.config['open_pin_no'] = \
|
|
929
|
+
self.cleaned_data['open_pin'].no
|
|
930
|
+
if 'close_pin' in self.cleaned_data:
|
|
931
|
+
self.instance.config['close_pin_no'] = \
|
|
932
|
+
self.cleaned_data['close_pin'].no
|
|
940
933
|
return super().save(commit=commit)
|
|
941
934
|
|
|
942
935
|
|
|
@@ -952,9 +945,6 @@ class BurglarSmokeDetectorConfigForm(ColonelComponentForm):
|
|
|
952
945
|
]
|
|
953
946
|
)
|
|
954
947
|
)
|
|
955
|
-
power_action = forms.ChoiceField(
|
|
956
|
-
choices=(('HIGH', "HIGH"), ('LOW', "LOW")),
|
|
957
|
-
)
|
|
958
948
|
sensor_pin = ColonelPinChoiceField(
|
|
959
949
|
queryset=ColonelPin.objects.filter(input=True),
|
|
960
950
|
widget=autocomplete.ListSelect2(
|
|
@@ -966,67 +956,28 @@ class BurglarSmokeDetectorConfigForm(ColonelComponentForm):
|
|
|
966
956
|
]
|
|
967
957
|
)
|
|
968
958
|
)
|
|
969
|
-
sensor_pull = forms.ChoiceField(
|
|
970
|
-
choices=(
|
|
971
|
-
('HIGH', "HIGH"), ('LOW', "LOW"), ("FLOATING", "leave floating"),
|
|
972
|
-
),
|
|
973
|
-
help_text="If you are not sure what is this all about, "
|
|
974
|
-
"you are most definitely want to pull this HIGH or LOW "
|
|
975
|
-
"but not leave it floating!"
|
|
976
|
-
)
|
|
977
959
|
sensor_inverse = forms.TypedChoiceField(
|
|
978
|
-
choices=((
|
|
979
|
-
help_text="Hint: Set
|
|
960
|
+
choices=((0, "No"), (1, "Yes")), coerce=int, initial=0,
|
|
961
|
+
help_text="Hint: Set to Yes, to get ON signal when "
|
|
980
962
|
"you deliver GND to the pin and OFF when you cut it out."
|
|
981
963
|
)
|
|
982
964
|
|
|
983
|
-
|
|
984
965
|
def clean(self):
|
|
985
966
|
super().clean()
|
|
986
|
-
if
|
|
987
|
-
|
|
988
|
-
if '
|
|
989
|
-
|
|
990
|
-
if 'power_pin' not in self.cleaned_data:
|
|
991
|
-
return self.cleaned_data
|
|
992
|
-
|
|
993
|
-
self._clean_pin('sensor_pin')
|
|
994
|
-
self._clean_pin('power_pin')
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
if self.cleaned_data['sensor_pin'].no > 100:
|
|
998
|
-
if self.cleaned_data['sensor_pin'].no < 126:
|
|
999
|
-
if self.cleaned_data.get('sensor_pull') == 'HIGH':
|
|
1000
|
-
self.add_error(
|
|
1001
|
-
'sensor_pull',
|
|
1002
|
-
"Sorry, but this pin is already pulled LOW and "
|
|
1003
|
-
"it can not be changed by this setting. "
|
|
1004
|
-
"Please use 5kohm resistor to physically pull it HIGH "
|
|
1005
|
-
"if that's what you want to do."
|
|
1006
|
-
)
|
|
1007
|
-
else:
|
|
1008
|
-
if self.cleaned_data.get('sensor_pull') == 'LOW':
|
|
1009
|
-
self.add_error(
|
|
1010
|
-
'sensor_pull',
|
|
1011
|
-
"Sorry, but this pin is already pulled HIGH and "
|
|
1012
|
-
"it can not be changed by this setting. "
|
|
1013
|
-
"Please use 5kohm resistor to physically pull it LOW "
|
|
1014
|
-
"if that's what you want to do."
|
|
1015
|
-
)
|
|
1016
|
-
elif self.cleaned_data.get('sensor_pull') != 'FLOATING':
|
|
1017
|
-
if not self.cleaned_data['sensor_pin'].output:
|
|
1018
|
-
self.add_error(
|
|
1019
|
-
'sensor_pin',
|
|
1020
|
-
f"Sorry, but {self.cleaned_data['sensor_pin']} "
|
|
1021
|
-
f"does not have internal pull HIGH/LOW"
|
|
1022
|
-
" resistance capability"
|
|
1023
|
-
)
|
|
967
|
+
if 'sensor_pin' in self.cleaned_data:
|
|
968
|
+
self._clean_pin('sensor_pin')
|
|
969
|
+
if 'power_pin' in self.cleaned_data:
|
|
970
|
+
self._clean_pin('power_pin')
|
|
1024
971
|
|
|
1025
972
|
return self.cleaned_data
|
|
1026
973
|
|
|
1027
974
|
def save(self, commit=True):
|
|
1028
|
-
|
|
1029
|
-
|
|
975
|
+
if 'sensor_pin' in self.cleaned_data:
|
|
976
|
+
self.instance.config['sensor_pin_no'] = \
|
|
977
|
+
self.cleaned_data['sensor_pin'].no
|
|
978
|
+
if 'power_pin' in self.cleaned_data:
|
|
979
|
+
self.instance.config['power_pin_no'] = \
|
|
980
|
+
self.cleaned_data['power_pin'].no
|
|
1030
981
|
return super().save(commit=commit)
|
|
1031
982
|
|
|
1032
983
|
|
|
@@ -1059,18 +1010,14 @@ class TTLockConfigForm(ColonelComponentForm):
|
|
|
1059
1010
|
|
|
1060
1011
|
def save(self, commit=True):
|
|
1061
1012
|
obj = super(ColonelComponentForm, self).save(commit)
|
|
1062
|
-
if commit:
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
self.instance.gateway, self.cleaned_data['door_sensor'],
|
|
1068
|
-
command='watch_lock_sensor'
|
|
1069
|
-
).publish()
|
|
1013
|
+
if commit and 'door_sensor' in self.cleaned_data:
|
|
1014
|
+
GatewayObjectCommand(
|
|
1015
|
+
self.instance.gateway, self.cleaned_data['door_sensor'],
|
|
1016
|
+
command='watch_lock_sensor'
|
|
1017
|
+
).publish()
|
|
1070
1018
|
return obj
|
|
1071
1019
|
|
|
1072
1020
|
|
|
1073
|
-
|
|
1074
1021
|
class DALIDeviceConfigForm(ColonelComponentForm):
|
|
1075
1022
|
interface = ColonelInterfacesChoiceField(
|
|
1076
1023
|
queryset=Interface.objects.filter(type='dali'),
|
|
@@ -1087,7 +1034,9 @@ class DALIDeviceConfigForm(ColonelComponentForm):
|
|
|
1087
1034
|
)
|
|
1088
1035
|
|
|
1089
1036
|
def save(self, commit=True):
|
|
1090
|
-
|
|
1037
|
+
if 'interface' in self.cleaned_data:
|
|
1038
|
+
self.instance.config['dali_interface'] = \
|
|
1039
|
+
self.cleaned_data['interface'].no
|
|
1091
1040
|
return super().save(commit=commit)
|
|
1092
1041
|
|
|
1093
1042
|
|
|
Binary file
|
simo/generic/forms.py
CHANGED
|
@@ -137,8 +137,6 @@ class ThermostatConfigForm(BaseComponentForm):
|
|
|
137
137
|
else:
|
|
138
138
|
self.fields['use_real_feel'].disabled = True
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
140
|
def save(self, commit=True):
|
|
143
141
|
self.instance.value_units = self.cleaned_data[
|
|
144
142
|
'temperature_sensor'
|
|
@@ -314,8 +312,9 @@ class AlarmGroupConfigForm(BaseComponentForm):
|
|
|
314
312
|
def save(self, *args, **kwargs):
|
|
315
313
|
self.instance.value_units = 'status'
|
|
316
314
|
from .controllers import AlarmGroup
|
|
317
|
-
if
|
|
318
|
-
self.
|
|
315
|
+
if 'is_main' in self.cleaned_data:
|
|
316
|
+
if self.fields['is_main'].widget.attrs.get('disabled'):
|
|
317
|
+
self.cleaned_data['is_main'] = self.fields['is_main'].initial
|
|
319
318
|
obj = super().save(*args, **kwargs)
|
|
320
319
|
if obj.config.get('is_main'):
|
|
321
320
|
for c in Component.objects.filter(
|
|
@@ -366,8 +365,9 @@ class WeatherForecastForm(BaseComponentForm):
|
|
|
366
365
|
def save(self, *args, **kwargs):
|
|
367
366
|
self.instance.value_units = 'status'
|
|
368
367
|
from .controllers import WeatherForecast
|
|
369
|
-
if self.fields
|
|
370
|
-
self.
|
|
368
|
+
if 'is_main' in self.fields and 'is_main' in self.cleaned_data:
|
|
369
|
+
if self.fields['is_main'].widget.attrs.get('disabled'):
|
|
370
|
+
self.cleaned_data['is_main'] = self.fields['is_main'].initial
|
|
371
371
|
obj = super().save(*args, **kwargs)
|
|
372
372
|
if obj.config.get('is_main'):
|
|
373
373
|
for c in Component.objects.filter(
|
|
@@ -541,11 +541,12 @@ class WateringConfigForm(BaseComponentForm):
|
|
|
541
541
|
return contours
|
|
542
542
|
|
|
543
543
|
def save(self, commit=True):
|
|
544
|
-
|
|
545
|
-
self.
|
|
546
|
-
|
|
544
|
+
if 'contours' in self.cleaned_data:
|
|
545
|
+
self.instance.config['program'] = self.controller._build_program(
|
|
546
|
+
self.cleaned_data['contours']
|
|
547
|
+
)
|
|
547
548
|
obj = super().save(commit=commit)
|
|
548
|
-
if commit:
|
|
549
|
+
if commit and 'contours' in self.cleaned_data:
|
|
549
550
|
obj.slaves.clear()
|
|
550
551
|
for contour in self.cleaned_data['contours']:
|
|
551
552
|
obj.slaves.add(
|
|
@@ -565,10 +566,6 @@ class StateForm(forms.Form):
|
|
|
565
566
|
help_text = forms.CharField(required=False, widget=forms.Textarea(attrs={'rows': 3}))
|
|
566
567
|
prefix = 'states'
|
|
567
568
|
|
|
568
|
-
def clean(self):
|
|
569
|
-
print("Let's clean the data! ", self.cleaned_data)
|
|
570
|
-
return self.cleaned_data
|
|
571
|
-
|
|
572
569
|
|
|
573
570
|
class StateSelectForm(BaseComponentForm):
|
|
574
571
|
states = FormsetField(
|
|
@@ -602,18 +599,20 @@ class AlarmClockEventForm(forms.Form):
|
|
|
602
599
|
if not self.cleaned_data.get('play_action'):
|
|
603
600
|
return self.cleaned_data
|
|
604
601
|
component = self.cleaned_data.get('component')
|
|
605
|
-
if
|
|
606
|
-
self.
|
|
607
|
-
'play_action',
|
|
608
|
-
f"{component} has no {self.cleaned_data['play_action']} action!"
|
|
609
|
-
)
|
|
610
|
-
if self.cleaned_data.get('reverse_action'):
|
|
611
|
-
if not hasattr(component, self.cleaned_data['reverse_action']):
|
|
602
|
+
if 'play_action' in self.cleaned_data:
|
|
603
|
+
if not hasattr(component, self.cleaned_data['play_action']):
|
|
612
604
|
self.add_error(
|
|
613
|
-
'
|
|
614
|
-
f"{component} has no "
|
|
615
|
-
f"{self.cleaned_data['reverse_action']} action!"
|
|
605
|
+
'play_action',
|
|
606
|
+
f"{component} has no {self.cleaned_data['play_action']} action!"
|
|
616
607
|
)
|
|
608
|
+
if 'reverse_action' in self.cleaned_data:
|
|
609
|
+
if self.cleaned_data.get('reverse_action'):
|
|
610
|
+
if not hasattr(component, self.cleaned_data['reverse_action']):
|
|
611
|
+
self.add_error(
|
|
612
|
+
'reverse_action',
|
|
613
|
+
f"{component} has no "
|
|
614
|
+
f"{self.cleaned_data['reverse_action']} action!"
|
|
615
|
+
)
|
|
617
616
|
return self.cleaned_data
|
|
618
617
|
|
|
619
618
|
|
|
@@ -633,7 +632,7 @@ class AlarmClockConfigForm(BaseComponentForm):
|
|
|
633
632
|
|
|
634
633
|
def save(self, commit=True):
|
|
635
634
|
obj = super().save(commit=commit)
|
|
636
|
-
if commit:
|
|
635
|
+
if commit and 'default_events' in self.cleaned_data:
|
|
637
636
|
obj.slaves.clear()
|
|
638
637
|
for comp in self.cleaned_data['default_events']:
|
|
639
638
|
c = Component.objects.filter(pk=comp['component']).first()
|
|
Binary file
|
|
Binary file
|
simo/users/admin.py
CHANGED
|
@@ -16,11 +16,6 @@ class ComponentPermissionInline(admin.TabularInline):
|
|
|
16
16
|
fields = 'component', 'read', 'write'
|
|
17
17
|
readonly_fields = 'component',
|
|
18
18
|
|
|
19
|
-
def get_queryset(self, request):
|
|
20
|
-
return super().get_queryset(request).filter(
|
|
21
|
-
component__show_in_app=True
|
|
22
|
-
)
|
|
23
|
-
|
|
24
19
|
def has_delete_permission(self, request, obj=None):
|
|
25
20
|
return False
|
|
26
21
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 3.2.9 on 2024-05-06 08:34
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('users', '0026_fingerprint_name'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='permissionsrole',
|
|
15
|
+
name='can_manage_components',
|
|
16
|
+
field=models.BooleanField(default=False, help_text='Can manage zones and basic component parameters via SIMO.io app.'),
|
|
17
|
+
),
|
|
18
|
+
]
|