simo 2.0.6__py3-none-any.whl → 2.0.7__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 (45) hide show
  1. simo/core/__pycache__/admin.cpython-38.pyc +0 -0
  2. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  3. simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
  4. simo/core/__pycache__/forms.cpython-38.pyc +0 -0
  5. simo/core/__pycache__/models.cpython-38.pyc +0 -0
  6. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  7. simo/core/admin.py +4 -2
  8. simo/core/api.py +5 -3
  9. simo/core/controllers.py +1 -0
  10. simo/core/forms.py +1 -1
  11. simo/core/migrations/0030_alter_instance_timezone.py +18 -0
  12. simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-38.pyc +0 -0
  13. simo/core/models.py +1 -0
  14. simo/core/serializers.py +1 -1
  15. simo/core/utils/__pycache__/serialization.cpython-38.pyc +0 -0
  16. simo/core/utils/serialization.py +4 -2
  17. simo/fleet/__pycache__/admin.cpython-38.pyc +0 -0
  18. simo/fleet/__pycache__/auto_urls.cpython-38.pyc +0 -0
  19. simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
  20. simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
  21. simo/fleet/__pycache__/gateways.cpython-38.pyc +0 -0
  22. simo/fleet/__pycache__/managers.cpython-38.pyc +0 -0
  23. simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
  24. simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  25. simo/fleet/__pycache__/utils.cpython-38.pyc +0 -0
  26. simo/fleet/__pycache__/views.cpython-38.pyc +0 -0
  27. simo/fleet/admin.py +6 -6
  28. simo/fleet/auto_urls.py +4 -4
  29. simo/fleet/controllers.py +75 -2
  30. simo/fleet/forms.py +68 -33
  31. simo/fleet/gateways.py +7 -3
  32. simo/fleet/managers.py +4 -2
  33. simo/fleet/migrations/0032_auto_20240415_0736.py +33 -0
  34. simo/fleet/migrations/0033_auto_20240415_0736.py +28 -0
  35. simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-38.pyc +0 -0
  36. simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-38.pyc +0 -0
  37. simo/fleet/models.py +82 -14
  38. simo/fleet/socket_consumers.py +19 -12
  39. simo/fleet/utils.py +6 -1
  40. simo/fleet/views.py +10 -9
  41. {simo-2.0.6.dist-info → simo-2.0.7.dist-info}/METADATA +1 -1
  42. {simo-2.0.6.dist-info → simo-2.0.7.dist-info}/RECORD +45 -39
  43. {simo-2.0.6.dist-info → simo-2.0.7.dist-info}/LICENSE.md +0 -0
  44. {simo-2.0.6.dist-info → simo-2.0.7.dist-info}/WHEEL +0 -0
  45. {simo-2.0.6.dist-info → simo-2.0.7.dist-info}/top_level.txt +0 -0
Binary file
Binary file
Binary file
Binary file
simo/core/admin.py CHANGED
@@ -322,7 +322,7 @@ class ComponentAdmin(admin.ModelAdmin):
322
322
  if request.session.get('add_comp_type'):
323
323
  try:
324
324
  controller_cls = CONTROLLERS_BY_GATEWAY.get(
325
- gateway, {}
325
+ gateway.type, {}
326
326
  )[request.session['add_comp_type']]
327
327
  except:
328
328
  request.session.pop('add_comp_type')
@@ -355,6 +355,7 @@ class ComponentAdmin(admin.ModelAdmin):
355
355
  pop_fields_from_form(ctx['form'])
356
356
  if ctx['form'].is_valid():
357
357
  if ctx['form'].controller.is_discoverable:
358
+ print("INIT DISCOVERY!!!")
358
359
  ctx['form'].controller.init_discovery(
359
360
  ctx['form'].cleaned_data
360
361
  )
@@ -393,6 +394,7 @@ class ComponentAdmin(admin.ModelAdmin):
393
394
  if ctx['form'].is_valid():
394
395
  request.session['add_comp_type'] = \
395
396
  ctx['form'].cleaned_data['controller_type']
397
+ print("Session controller type: ", request.session['add_comp_type'])
396
398
  return redirect(request.path)
397
399
 
398
400
  else:
@@ -429,7 +431,7 @@ class ComponentAdmin(admin.ModelAdmin):
429
431
  if obj:
430
432
  try:
431
433
  self.form = CONTROLLERS_BY_GATEWAY.get(
432
- obj.gateway, {}
434
+ obj.gateway.type, {}
433
435
  )[obj.controller_uid].config_form
434
436
  except KeyError:
435
437
  pass
simo/core/api.py CHANGED
@@ -62,7 +62,7 @@ class IconViewSet(viewsets.ReadOnlyModelViewSet):
62
62
  if 'q' in self.request.GET:
63
63
  queryset = search_queryset(
64
64
  queryset, self.request.GET['q'], ['slug', 'keywords']
65
- )[:10]
65
+ )[:25]
66
66
  return queryset
67
67
 
68
68
  def get_view_name(self):
@@ -592,7 +592,8 @@ class ControllerTypes(InstanceMixin, viewsets.GenericViewSet):
592
592
  data[cls.gateway_class.name].append({
593
593
  'uid': uid,
594
594
  'name': cls.name,
595
- 'is_discoverable': cls.is_discoverable
595
+ 'is_discoverable': cls.is_discoverable,
596
+ 'manual_add': cls.manual_add
596
597
  })
597
598
 
598
599
  return RESTResponse(data)
@@ -603,7 +604,6 @@ class RunningDiscoveries(InstanceMixin, viewsets.GenericViewSet):
603
604
  basename = 'discoveries'
604
605
  queryset = []
605
606
 
606
-
607
607
  def get_permissions(self):
608
608
  permissions = super().get_permissions()
609
609
  permissions.append(IsInstanceSuperuser())
@@ -612,6 +612,8 @@ class RunningDiscoveries(InstanceMixin, viewsets.GenericViewSet):
612
612
  def get_data(self, gateways):
613
613
  data = []
614
614
  for gateway in gateways:
615
+ gateway.discovery['last_check'] = time.time()
616
+ gateway.save(update_fields=['discovery'])
615
617
  data.append({
616
618
  'gateway': gateway.id,
617
619
  'start': gateway.discovery['start'],
simo/core/controllers.py CHANGED
@@ -34,6 +34,7 @@ class ControllerBase(ABC):
34
34
  default_config = {}
35
35
  default_meta = {}
36
36
  discovery_msg = None
37
+ manual_add = True # Can be added manually
37
38
 
38
39
  @property
39
40
  @abstractmethod
simo/core/forms.py CHANGED
@@ -264,7 +264,7 @@ class CompTypeSelectForm(forms.Form):
264
264
  self.fields['controller_type'].choices = [
265
265
  (cls.uid, cls.name) for cls in CONTROLLERS_BY_GATEWAY.get(
266
266
  gateway.handler.uid, {}
267
- ).values()
267
+ ).values() if cls.manual_add
268
268
  ]
269
269
 
270
270
 
@@ -0,0 +1,18 @@
1
+ # Generated by Django 3.2.9 on 2024-04-15 11:08
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0029_auto_20240229_1331'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='instance',
15
+ name='timezone',
16
+ field=models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Asmera', 'Africa/Asmera'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Timbuktu', 'Africa/Timbuktu'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/ComodRivadavia', 'America/Argentina/ComodRivadavia'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Atka', 'America/Atka'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Buenos_Aires', 'America/Buenos_Aires'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Catamarca', 'America/Catamarca'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Coral_Harbour', 'America/Coral_Harbour'), ('America/Cordoba', 'America/Cordoba'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Ensenada', 'America/Ensenada'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fort_Wayne', 'America/Fort_Wayne'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Indianapolis', 'America/Indianapolis'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Jujuy', 'America/Jujuy'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Knox_IN', 'America/Knox_IN'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Louisville', 'America/Louisville'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Mendoza', 'America/Mendoza'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montreal', 'America/Montreal'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Acre', 'America/Porto_Acre'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Rosario', 'America/Rosario'), ('America/Santa_Isabel', 'America/Santa_Isabel'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Shiprock', 'America/Shiprock'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Virgin', 'America/Virgin'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/South_Pole', 'Antarctica/South_Pole'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Ashkhabad', 'Asia/Ashkhabad'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Calcutta', 'Asia/Calcutta'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Chongqing', 'Asia/Chongqing'), ('Asia/Chungking', 'Asia/Chungking'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Dacca', 'Asia/Dacca'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Harbin', 'Asia/Harbin'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Istanbul', 'Asia/Istanbul'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kashgar', 'Asia/Kashgar'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Katmandu', 'Asia/Katmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macao', 'Asia/Macao'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Rangoon', 'Asia/Rangoon'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Saigon', 'Asia/Saigon'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Tel_Aviv', 'Asia/Tel_Aviv'), ('Asia/Thimbu', 'Asia/Thimbu'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ujung_Pandang', 'Asia/Ujung_Pandang'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Ulan_Bator', 'Asia/Ulan_Bator'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faeroe', 'Atlantic/Faeroe'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Jan_Mayen', 'Atlantic/Jan_Mayen'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/ACT', 'Australia/ACT'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Canberra', 'Australia/Canberra'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/LHI', 'Australia/LHI'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/NSW', 'Australia/NSW'), ('Australia/North', 'Australia/North'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Queensland', 'Australia/Queensland'), ('Australia/South', 'Australia/South'), ('Australia/Sydney', 'Australia/Sydney'), ('Australia/Tasmania', 'Australia/Tasmania'), ('Australia/Victoria', 'Australia/Victoria'), ('Australia/West', 'Australia/West'), ('Australia/Yancowinna', 'Australia/Yancowinna'), ('Brazil/Acre', 'Brazil/Acre'), ('Brazil/DeNoronha', 'Brazil/DeNoronha'), ('Brazil/East', 'Brazil/East'), ('Brazil/West', 'Brazil/West'), ('CET', 'CET'), ('CST6CDT', 'CST6CDT'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Canada/Saskatchewan', 'Canada/Saskatchewan'), ('Canada/Yukon', 'Canada/Yukon'), ('Chile/Continental', 'Chile/Continental'), ('Chile/EasterIsland', 'Chile/EasterIsland'), ('Cuba', 'Cuba'), ('EET', 'EET'), ('EST', 'EST'), ('EST5EDT', 'EST5EDT'), ('Egypt', 'Egypt'), ('Eire', 'Eire'), ('Etc/GMT', 'Etc/GMT'), ('Etc/GMT+0', 'Etc/GMT+0'), ('Etc/GMT+1', 'Etc/GMT+1'), ('Etc/GMT+10', 'Etc/GMT+10'), ('Etc/GMT+11', 'Etc/GMT+11'), ('Etc/GMT+12', 'Etc/GMT+12'), ('Etc/GMT+2', 'Etc/GMT+2'), ('Etc/GMT+3', 'Etc/GMT+3'), ('Etc/GMT+4', 'Etc/GMT+4'), ('Etc/GMT+5', 'Etc/GMT+5'), ('Etc/GMT+6', 'Etc/GMT+6'), ('Etc/GMT+7', 'Etc/GMT+7'), ('Etc/GMT+8', 'Etc/GMT+8'), ('Etc/GMT+9', 'Etc/GMT+9'), ('Etc/GMT-0', 'Etc/GMT-0'), ('Etc/GMT-1', 'Etc/GMT-1'), ('Etc/GMT-10', 'Etc/GMT-10'), ('Etc/GMT-11', 'Etc/GMT-11'), ('Etc/GMT-12', 'Etc/GMT-12'), ('Etc/GMT-13', 'Etc/GMT-13'), ('Etc/GMT-14', 'Etc/GMT-14'), ('Etc/GMT-2', 'Etc/GMT-2'), ('Etc/GMT-3', 'Etc/GMT-3'), ('Etc/GMT-4', 'Etc/GMT-4'), ('Etc/GMT-5', 'Etc/GMT-5'), ('Etc/GMT-6', 'Etc/GMT-6'), ('Etc/GMT-7', 'Etc/GMT-7'), ('Etc/GMT-8', 'Etc/GMT-8'), ('Etc/GMT-9', 'Etc/GMT-9'), ('Etc/GMT0', 'Etc/GMT0'), ('Etc/Greenwich', 'Etc/Greenwich'), ('Etc/UCT', 'Etc/UCT'), ('Etc/UTC', 'Etc/UTC'), ('Etc/Universal', 'Etc/Universal'), ('Etc/Zulu', 'Etc/Zulu'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belfast', 'Europe/Belfast'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Nicosia', 'Europe/Nicosia'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Tiraspol', 'Europe/Tiraspol'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GB', 'GB'), ('GB-Eire', 'GB-Eire'), ('GMT', 'GMT'), ('GMT+0', 'GMT+0'), ('GMT-0', 'GMT-0'), ('GMT0', 'GMT0'), ('Greenwich', 'Greenwich'), ('HST', 'HST'), ('Hongkong', 'Hongkong'), ('Iceland', 'Iceland'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Iran', 'Iran'), ('Israel', 'Israel'), ('Jamaica', 'Jamaica'), ('Japan', 'Japan'), ('Kwajalein', 'Kwajalein'), ('Libya', 'Libya'), ('MET', 'MET'), ('MST', 'MST'), ('MST7MDT', 'MST7MDT'), ('Mexico/BajaNorte', 'Mexico/BajaNorte'), ('Mexico/BajaSur', 'Mexico/BajaSur'), ('Mexico/General', 'Mexico/General'), ('NZ', 'NZ'), ('NZ-CHAT', 'NZ-CHAT'), ('Navajo', 'Navajo'), ('PRC', 'PRC'), ('PST8PDT', 'PST8PDT'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Johnston', 'Pacific/Johnston'), ('Pacific/Kanton', 'Pacific/Kanton'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Ponape', 'Pacific/Ponape'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Samoa', 'Pacific/Samoa'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Truk', 'Pacific/Truk'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('Pacific/Yap', 'Pacific/Yap'), ('Poland', 'Poland'), ('Portugal', 'Portugal'), ('ROC', 'ROC'), ('ROK', 'ROK'), ('Singapore', 'Singapore'), ('Turkey', 'Turkey'), ('UCT', 'UCT'), ('US/Alaska', 'US/Alaska'), ('US/Aleutian', 'US/Aleutian'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/East-Indiana', 'US/East-Indiana'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Indiana-Starke', 'US/Indiana-Starke'), ('US/Michigan', 'US/Michigan'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('US/Samoa', 'US/Samoa'), ('UTC', 'UTC'), ('Universal', 'Universal'), ('W-SU', 'W-SU'), ('WET', 'WET'), ('Zulu', 'Zulu')], db_index=True, max_length=50),
17
+ ),
18
+ ]
simo/core/models.py CHANGED
@@ -278,6 +278,7 @@ class Gateway(DirtyFieldsMixin, models.Model, SimoAdminMixin):
278
278
  started_with=self.discovery['init_data'], data=data
279
279
  )
280
280
  if result:
281
+ self.refresh_from_db()
281
282
  if not isinstance(result, dict) and isinstance(result, Iterable):
282
283
  for res in result:
283
284
  if isinstance(res, models.Model):
simo/core/serializers.py CHANGED
@@ -293,7 +293,7 @@ class ComponentSerializer(FormSerializer):
293
293
  if controller:
294
294
  self.Meta.form = controller.add_form
295
295
  else:
296
- controller = controllers_map.get(
296
+ controller = CONTROLLER_TYPES_MAP.get(
297
297
  self.instance.controller_uid
298
298
  )
299
299
  if controller:
@@ -21,14 +21,14 @@ def serialize_form_data(data):
21
21
  serialized_data[field_name] = {
22
22
  'model': 'many',
23
23
  'val': json.loads(model_serializers.serialize(
24
- 'json', val
24
+ 'json', val, fields=['pk']
25
25
  ))
26
26
  }
27
27
  else:
28
28
  serialized_data[field_name] = {
29
29
  'model': 'single',
30
30
  'val': json.loads(model_serializers.serialize(
31
- 'json', [val]
31
+ 'json', [val], fields=['pk']
32
32
  ))
33
33
  }
34
34
  else:
@@ -46,11 +46,13 @@ def deserialize_form_data(data):
46
46
  if val['model'] == 'single':
47
47
  for item in deserializer_generator:
48
48
  deserialized_data[field_name] = item.object
49
+ deserialized_data[field_name].refresh_from_db()
49
50
  break
50
51
  else:
51
52
  deserialized_data[field_name] = []
52
53
  for item in deserializer_generator:
53
54
  deserialized_data[field_name].append(item.object)
55
+ deserialized_data[field_name][-1].refresh_from_db()
54
56
  else:
55
57
  deserialized_data[field_name] = val
56
58
  return deserialized_data
Binary file
Binary file
Binary file
Binary file
simo/fleet/admin.py CHANGED
@@ -5,14 +5,14 @@ from django.template.loader import render_to_string
5
5
  from django.templatetags.static import static
6
6
  from simo.core.models import Component
7
7
  from simo.core.utils.admin import FormAction
8
- from .models import Colonel, I2CInterface, ColonelPin
9
- from .forms import ColonelAdminForm, MoveColonelForm, I2CInterfaceAdminForm
8
+ from .models import Colonel, Interface, ColonelPin
9
+ from .forms import ColonelAdminForm, MoveColonelForm, InterfaceAdminForm
10
10
 
11
11
 
12
- class I2CInterfaceInline(admin.TabularInline):
13
- model = I2CInterface
12
+ class InterfaceInline(admin.TabularInline):
13
+ model = Interface
14
14
  extra = 0
15
- form = I2CInterfaceAdminForm
15
+ form = InterfaceAdminForm
16
16
 
17
17
 
18
18
  class ColonelPinsInline(admin.TabularInline):
@@ -71,7 +71,7 @@ class ColonelAdmin(admin.ModelAdmin):
71
71
  'rebuild_occupied_pins'
72
72
  )
73
73
 
74
- inlines = I2CInterfaceInline, ColonelPinsInline
74
+ inlines = InterfaceInline, ColonelPinsInline
75
75
 
76
76
  def get_queryset(self, request):
77
77
  qs = super().get_queryset(request)
simo/fleet/auto_urls.py CHANGED
@@ -1,9 +1,8 @@
1
1
  from django.urls import path, re_path
2
- from django.views.generic import TemplateView
3
2
  from .views import (
4
3
  colonels_ping,
5
4
  PinsSelectAutocomplete,
6
- I2CInterfaceSelectAutocomplete
5
+ InterfaceSelectAutocomplete
7
6
  )
8
7
 
9
8
  urlpatterns = [
@@ -15,7 +14,8 @@ urlpatterns = [
15
14
  PinsSelectAutocomplete.as_view(), name='autocomplete-colonel-pins'
16
15
  ),
17
16
  path(
18
- 'autocomplete-colonel-i2c_interfaces',
19
- I2CInterfaceSelectAutocomplete.as_view(), name='autocomplete-colonel-i2c_interfaces'
17
+ 'autocomplete-colonel-interfaces',
18
+ InterfaceSelectAutocomplete.as_view(),
19
+ name='autocomplete-interfaces'
20
20
  )
21
21
  ]
simo/fleet/controllers.py CHANGED
@@ -24,7 +24,7 @@ from .forms import (
24
24
  ColonelDHTSensorConfigForm, DS18B20SensorConfigForm,
25
25
  BME680SensorConfigForm, MPC9808SensorConfigForm,
26
26
  DualMotorValveForm, BlindsConfigForm, BurglarSmokeDetectorConfigForm,
27
- TTLockConfigForm
27
+ TTLockConfigForm, DALIDeviceConfigForm
28
28
  )
29
29
 
30
30
 
@@ -294,6 +294,7 @@ class TTLock(FleeDeviceMixin, Lock):
294
294
  @classmethod
295
295
  def init_discovery(self, form_cleaned_data):
296
296
  from simo.core.models import Gateway
297
+ print("INIT discovery form cleaned data: ", form_cleaned_data)
297
298
  print("Serialized form: ", serialize_form_data(form_cleaned_data))
298
299
  gateway = Gateway.objects.filter(type=self.gateway_class.uid).first()
299
300
  gateway.start_discovery(
@@ -307,7 +308,7 @@ class TTLock(FleeDeviceMixin, Lock):
307
308
 
308
309
  @classmethod
309
310
  def _process_discovery(cls, started_with, data):
310
- if data['discover-ttlock'] == 'fail':
311
+ if data['discovery-result'] == 'fail':
311
312
  if data['result'] == 0:
312
313
  return {'error': 'Internal Colonel error. See Colonel logs.'}
313
314
  if data['result'] == 1:
@@ -348,6 +349,7 @@ class TTLock(FleeDeviceMixin, Lock):
348
349
  },
349
350
  }
350
351
  new_component.save()
352
+ new_component.gateway.finish_discovery()
351
353
  GatewayObjectCommand(
352
354
  new_component.gateway, Colonel(
353
355
  id=new_component.config['colonel']
@@ -417,4 +419,75 @@ class TTLock(FleeDeviceMixin, Lock):
417
419
  ).publish()
418
420
 
419
421
 
422
+ class DALIDevice(FleeDeviceMixin):
423
+ gateway_class = FleetGatewayHandler
424
+ config_form = DALIDeviceConfigForm
425
+ discovery_msg = _("Please hook up your new DALI device to your DALI bus.")
426
+
427
+ @classmethod
428
+ def init_discovery(self, form_cleaned_data):
429
+ from simo.core.models import Gateway
430
+ gateway = Gateway.objects.filter(type=self.gateway_class.uid).first()
431
+ gateway.start_discovery(
432
+ self.uid, serialize_form_data(form_cleaned_data),
433
+ timeout=60
434
+ )
435
+ GatewayObjectCommand(
436
+ gateway, form_cleaned_data['colonel'],
437
+ command=f'discover-dali',
438
+ interface=form_cleaned_data['interface'].no
439
+ ).publish()
440
+
441
+ @classmethod
442
+ def _process_discovery(cls, started_with, data):
443
+ started_with = deserialize_form_data(started_with)
444
+ form = TTLockConfigForm(controller_uid=cls.uid, data=started_with)
445
+
446
+ if form.is_valid():
447
+ new_component = form.save()
448
+ new_component.config.update(data.get('result', {}).get('config'))
449
+ new_component.meta['finalization_data'] = {
450
+ 'temp_id': data['result']['id'],
451
+ 'permanent_id': new_component.id,
452
+ 'config': {
453
+ 'type': cls.uid.split('.')[-1],
454
+ 'config': new_component.config,
455
+ 'val': False,
456
+ },
457
+ }
458
+ new_component.save()
459
+ new_component.gateway.finish_discovery()
460
+ GatewayObjectCommand(
461
+ new_component.gateway, Colonel(
462
+ id=new_component.config['colonel']
463
+ ), command='finalize',
464
+ data=new_component.meta['finalization_data'],
465
+ ).publish()
466
+ return [new_component]
467
+
468
+ # Literally impossible, but just in case...
469
+ return {'error': 'INVALID INITIAL DISCOVERY FORM!'}
470
+
471
+
472
+ class DALIGear(DALIDevice):
473
+
474
+ def _send_to_device(self, value):
475
+ GatewayObjectCommand(
476
+ self.component.gateway,
477
+ Colonel(id=self.component.config['colonel']),
478
+ set_val=value,
479
+ component_id=self.component.id,
480
+ ).publish()
481
+
482
+
483
+ class DALILamp(DALIGear, BaseSwitch):
484
+ manual_add = False
485
+ name = 'DALI Lamp'
486
+ discovery_msg = _("Please hook up your new DALI device to your DALI bus.")
487
+
488
+
489
+ class DALIDimmableLamp(DALIGear, BaseDimmer):
490
+ manual_add = False
491
+ name = 'DALI Dimmable Lamp'
492
+ discovery_msg = _("Please hook up your new DALI lamp to your DALI bus.")
420
493
 
simo/fleet/forms.py CHANGED
@@ -12,7 +12,8 @@ from simo.core.widgets import LogOutputWidget
12
12
  from simo.core.utils.easing import EASING_CHOICES
13
13
  from simo.core.utils.validators import validate_slaves
14
14
  from simo.core.utils.admin import AdminFormActionForm
15
- from .models import Colonel, ColonelPin, I2CInterface, i2c_interface_no_choices
15
+ from .models import Colonel, ColonelPin, Interface
16
+ from .utils import INTERFACES_PINS_MAP
16
17
 
17
18
 
18
19
  class ColonelPinChoiceField(forms.ModelChoiceField):
@@ -23,6 +24,11 @@ class ColonelPinChoiceField(forms.ModelChoiceField):
23
24
  filter_by = 'colonel'
24
25
 
25
26
 
27
+ class ColonelInterfacesChoiceField(forms.ModelChoiceField):
28
+ filter_by = 'colonel'
29
+
30
+
31
+
26
32
  class ColonelAdminForm(forms.ModelForm):
27
33
  log = forms.CharField(
28
34
  widget=forms.HiddenInput, required=False
@@ -52,34 +58,29 @@ class MoveColonelForm(AdminFormActionForm):
52
58
  )
53
59
 
54
60
 
55
- class I2CInterfaceAdminForm(forms.ModelForm):
56
- scl_pin = ColonelPinChoiceField(
57
- queryset=ColonelPin.objects.filter(output=True, native=True),
58
- widget=autocomplete.ListSelect2(
59
- url='autocomplete-colonel-pins',
60
- forward=[
61
- forward.Self(),
62
- forward.Field('colonel'),
63
- forward.Const({'output': True, 'native': True}, 'filters')
64
- ]
65
- )
66
- )
67
- sda_pin = ColonelPinChoiceField(
68
- queryset=ColonelPin.objects.filter(output=True, native=True),
69
- widget=autocomplete.ListSelect2(
70
- url='autocomplete-colonel-pins',
71
- forward=[
72
- forward.Self(),
73
- forward.Field('colonel'),
74
- forward.Const({'output': True, 'native': True}, 'filters')
75
- ]
76
- )
77
- )
61
+ class InterfaceAdminForm(forms.ModelForm):
78
62
 
79
63
  class Meta:
80
- model = I2CInterface
64
+ model = Interface
81
65
  fields = '__all__'
82
66
 
67
+
68
+ def clean(self):
69
+ if self.instance.pk:
70
+ return self.cleaned_data
71
+
72
+ for pin_no in INTERFACES_PINS_MAP[self.cleaned_data['no']]:
73
+ cpin = ColonelPin.objects.get(
74
+ colonel=self.instance.colonel, no=pin_no
75
+ )
76
+ if cpin.occupied_by:
77
+ raise forms.ValidationError(
78
+ f"Interface can not be created, because "
79
+ f"GPIO{cpin} is already occupied by {cpin.occupied_by}."
80
+ )
81
+
82
+
83
+
83
84
  def clean_scl_pin(self):
84
85
  if self.cleaned_data['scl_pin'].occupied_by \
85
86
  and self.cleaned_data['scl_pin'].occupied_by != self.instance:
@@ -416,13 +417,16 @@ class ColonelDHTSensorConfigForm(ColonelComponentForm):
416
417
 
417
418
 
418
419
  class BME680SensorConfigForm(ColonelComponentForm):
419
- i2c_interface = forms.TypedChoiceField(
420
- coerce=int, choices=i2c_interface_no_choices,
420
+ interface = ColonelInterfacesChoiceField(
421
+ queryset=Interface.objects.filter(type='i2c'),
421
422
  widget=autocomplete.ListSelect2(
422
- url='autocomplete-colonel-i2c_interfaces',
423
+ url='autocomplete-interfaces',
423
424
  forward=[
424
425
  forward.Self(),
425
426
  forward.Field('colonel'),
427
+ forward.Const(
428
+ {'type': 'i2c'}, 'filters'
429
+ )
426
430
  ]
427
431
  )
428
432
  )
@@ -437,15 +441,22 @@ class BME680SensorConfigForm(ColonelComponentForm):
437
441
 
438
442
  )
439
443
 
444
+ def save(self, commit=True):
445
+ self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
446
+ return super().save(commit=commit)
447
+
440
448
 
441
449
  class MPC9808SensorConfigForm(ColonelComponentForm):
442
- i2c_interface = forms.TypedChoiceField(
443
- coerce=int, choices=i2c_interface_no_choices,
450
+ interface = ColonelInterfacesChoiceField(
451
+ queryset=Interface.objects.filter(type='i2c'),
444
452
  widget=autocomplete.ListSelect2(
445
- url='autocomplete-colonel-i2c_interfaces',
453
+ url='autocomplete-interfaces',
446
454
  forward=[
447
455
  forward.Self(),
448
456
  forward.Field('colonel'),
457
+ forward.Const(
458
+ {'type': 'i2c'}, 'filters'
459
+ )
449
460
  ]
450
461
  )
451
462
  )
@@ -460,6 +471,10 @@ class MPC9808SensorConfigForm(ColonelComponentForm):
460
471
 
461
472
  )
462
473
 
474
+ def save(self, commit=True):
475
+ self.instance.config['i2c_interface'] = self.cleaned_data['interface'].no
476
+ return super().save(commit=commit)
477
+
463
478
 
464
479
  class ColonelTouchSensorConfigForm(ColonelComponentForm):
465
480
  pin = ColonelPinChoiceField(
@@ -987,7 +1002,6 @@ class BurglarSmokeDetectorConfigForm(ColonelComponentForm):
987
1002
 
988
1003
 
989
1004
  class TTLockConfigForm(ColonelComponentForm):
990
- pass
991
1005
 
992
1006
  def clean(self):
993
1007
  if not self.instance or not self.instance.pk:
@@ -1002,7 +1016,6 @@ class TTLockConfigForm(ColonelComponentForm):
1002
1016
  )
1003
1017
  return self.cleaned_data
1004
1018
 
1005
-
1006
1019
  def save(self, commit=True):
1007
1020
  obj = super(ColonelComponentForm, self).save(commit)
1008
1021
  if commit:
@@ -1010,3 +1023,25 @@ class TTLockConfigForm(ColonelComponentForm):
1010
1023
  self.cleaned_data['colonel'].save()
1011
1024
  return obj
1012
1025
 
1026
+
1027
+
1028
+ class DALIDeviceConfigForm(ColonelComponentForm):
1029
+ interface = ColonelInterfacesChoiceField(
1030
+ queryset=Interface.objects.filter(type='dali'),
1031
+ widget=autocomplete.ListSelect2(
1032
+ url='autocomplete-interfaces',
1033
+ forward=[
1034
+ forward.Self(),
1035
+ forward.Field('colonel'),
1036
+ forward.Const(
1037
+ {'type': 'dali'}, 'filters'
1038
+ )
1039
+ ]
1040
+ )
1041
+ )
1042
+
1043
+ def save(self, commit=True):
1044
+ self.instance.config['dali_interface'] = self.cleaned_data['interface'].no
1045
+ return super().save(commit=commit)
1046
+
1047
+
simo/fleet/gateways.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import time
2
3
  from django.utils import timezone
3
4
  from simo.core.gateways import BaseObjectCommandsGatewayHandler
4
5
  from simo.core.forms import BaseGatewayForm
@@ -14,7 +15,7 @@ class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
14
15
  periodic_tasks = (
15
16
  ('look_for_updates', 600),
16
17
  ('watch_colonels_connection', 30),
17
- ('push_discoveries', 3),
18
+ ('push_discoveries', 10),
18
19
  )
19
20
 
20
21
  def _on_mqtt_message(self, client, userdata, msg):
@@ -37,9 +38,12 @@ class FleetGatewayHandler(BaseObjectCommandsGatewayHandler):
37
38
  def push_discoveries(self):
38
39
  from .models import Colonel
39
40
  for gw in Gateway.objects.filter(
40
- type=self.uid,
41
- discovery__has_key='start',
41
+ type=self.uid, discovery__has_key='start',
42
42
  ).exclude(discovery__has_key='finished'):
43
+ if time.time() - gw.discovery.get('last_check') > 10:
44
+ gw.finish_discovery()
45
+ continue
46
+
43
47
  colonel = Colonel.objects.get(
44
48
  id=gw.discovery['init_data']['colonel']['val'][0]['pk']
45
49
  )
simo/fleet/managers.py CHANGED
@@ -22,11 +22,13 @@ class ColonelPinsManager(models.Manager):
22
22
  return qs
23
23
 
24
24
 
25
- class I2CInterfacesManager(models.Manager):
25
+ class InterfacesManager(models.Manager):
26
26
 
27
27
  def get_queryset(self):
28
28
  qs = super().get_queryset()
29
29
  instance = get_current_instance()
30
30
  if instance:
31
31
  qs = qs.filter(colonel__instance=instance)
32
- return qs
32
+ return qs
33
+
34
+
@@ -0,0 +1,33 @@
1
+ # Generated by Django 3.2.9 on 2024-04-15 07:36
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('fleet', '0031_alter_colonel_type'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='colonel',
16
+ name='logs_stream',
17
+ field=models.BooleanField(default=False, help_text='ATENTION! Causes serious overhead and significantly degrades the lifespan of a chip due to a lot of writes to the memory. It also causes Colonel websocket to run out of memory and reset if a lot of data is being transmitted. Leave this off, unleess you know what you are doing!'),
18
+ ),
19
+ migrations.CreateModel(
20
+ name='Interface',
21
+ fields=[
22
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23
+ ('no', models.PositiveIntegerField(choices=[(1, '1'), (2, '2')])),
24
+ ('type', models.CharField(choices=[('i2c', 'I2C'), ('dali', 'DALI')], max_length=20)),
25
+ ('pin_a', models.ForeignKey(editable=False, limit_choices_to={'native': True, 'output': True}, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interface_a', to='fleet.colonelpin')),
26
+ ('pin_b', models.ForeignKey(editable=False, limit_choices_to={'native': True, 'output': True}, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='interface_b', to='fleet.colonelpin')),
27
+ ('colonel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='interfaces', to='fleet.colonel')),
28
+ ],
29
+ options={
30
+ 'unique_together': {('colonel', 'no')},
31
+ },
32
+ ),
33
+ ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 3.2.9 on 2024-04-15 07:36
2
+
3
+ from django.db import migrations
4
+
5
+ def create_objects(apps, schema_editor):
6
+ I2CInterface = apps.get_model("fleet", "I2CInterface")
7
+ Interface = apps.get_model("fleet", "Interface")
8
+ for i2c_i in I2CInterface.objects.filter(no__gt=0):
9
+ Interface.objects.create(
10
+ colonel=i2c_i.colonel, type='i2c',
11
+ pin_a=i2c_i.scl_pin, pin_b=i2c_i.sda_pin
12
+ )
13
+
14
+
15
+ def delete_objects(apps, schema_editor):
16
+ Interface = apps.get_model("fleet", "Interface")
17
+ Interface.delete()
18
+
19
+
20
+ class Migration(migrations.Migration):
21
+
22
+ dependencies = [
23
+ ('fleet', '0032_auto_20240415_0736'),
24
+ ]
25
+
26
+ operations = [
27
+ migrations.RunPython(create_objects, delete_objects),
28
+ ]
simo/fleet/models.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import requests
2
2
  import time
3
+ from django.core.exceptions import ValidationError
3
4
  from django.db import transaction
4
5
  from django.db import models
5
6
  from django.db.models.signals import post_save, pre_delete, post_delete
@@ -11,8 +12,8 @@ from simo.core.models import Instance, Gateway, Component
11
12
  from simo.core.utils.helpers import get_random_string
12
13
  from simo.core.events import GatewayObjectCommand
13
14
  from .gateways import FleetGatewayHandler
14
- from .managers import ColonelsManager, ColonelPinsManager, I2CInterfacesManager
15
- from .utils import GPIO_PINS
15
+ from .managers import ColonelsManager, ColonelPinsManager, InterfacesManager
16
+ from .utils import GPIO_PINS, INTERFACES_PINS_MAP
16
17
 
17
18
 
18
19
 
@@ -181,10 +182,12 @@ class Colonel(DirtyFieldsMixin, models.Model):
181
182
  pin.save()
182
183
 
183
184
  for interface in self.i2c_interfaces.all():
184
- interface.sda_pin.occupied_by = interface
185
- interface.sda_pin.save()
186
- interface.scl_pin.occupied_by = interface
187
- interface.scl_pin.save()
185
+ if interface.sda_pin:
186
+ interface.sda_pin.occupied_by = interface
187
+ interface.sda_pin.save()
188
+ if interface.scl_pin:
189
+ interface.scl_pin.occupied_by = interface
190
+ interface.scl_pin.save()
188
191
 
189
192
 
190
193
  def move_to(self, other_colonel):
@@ -256,12 +259,6 @@ def after_colonel_save(sender, instance, created, *args, **kwargs):
256
259
  capacitive=data.get('capacitive'), adc=data.get('adc'),
257
260
  native=data.get('native'), note=data.get('note')
258
261
  )
259
- if instance.type in ('ample-wall', 'game-changer'):
260
- I2CInterface.objects.create(
261
- colonel=instance, name='Main', no=0,
262
- scl_pin=ColonelPin.objects.get(colonel=instance, no=4),
263
- sda_pin=ColonelPin.objects.get(colonel=instance, no=15),
264
- )
265
262
 
266
263
 
267
264
  @receiver(pre_delete, sender=Component)
@@ -310,7 +307,7 @@ class I2CInterface(models.Model):
310
307
  default=100000, help_text="100000 - is a good middle point!"
311
308
  )
312
309
 
313
- objects = I2CInterfacesManager()
310
+ objects = InterfacesManager()
314
311
 
315
312
  class Meta:
316
313
  unique_together = 'colonel', 'no'
@@ -319,7 +316,7 @@ class I2CInterface(models.Model):
319
316
  return self.name
320
317
 
321
318
 
322
- @receiver(post_save, sender=I2CInterface)
319
+ @receiver(post_delete, sender=I2CInterface)
323
320
  def post_i2c_interface_delete(sender, instance, *args, **kwargs):
324
321
  with transaction.atomic():
325
322
  ct = ContentType.objects.get_for_model(instance)
@@ -334,3 +331,74 @@ def post_i2c_interface_delete(sender, instance, *args, **kwargs):
334
331
  instance.scl_pin.save()
335
332
  instance.sda_pin.occupied_by = instance
336
333
  instance.sda_pin.save()
334
+
335
+
336
+ class Interface(models.Model):
337
+ colonel = models.ForeignKey(
338
+ Colonel, on_delete=models.CASCADE, related_name='interfaces'
339
+ )
340
+ no = models.PositiveIntegerField(choices=((1, "1"), (2, "2")))
341
+ type = models.CharField(
342
+ max_length=20, choices=(('i2c', "I2C"), ('dali', "DALI"))
343
+ )
344
+ pin_a = models.ForeignKey(
345
+ ColonelPin, on_delete=models.CASCADE, limit_choices_to={
346
+ 'native': True, 'output': True,
347
+ }, verbose_name="Pin A (scl)", null=True, related_name='interface_a',
348
+ editable=False
349
+ )
350
+ pin_b = models.ForeignKey(
351
+ ColonelPin, on_delete=models.CASCADE, limit_choices_to={
352
+ 'native': True, 'output': True,
353
+ }, verbose_name="Pin B (sda)", null=True, related_name='interface_b',
354
+ editable=False
355
+ )
356
+
357
+ objects = InterfacesManager()
358
+
359
+ class Meta:
360
+ unique_together = 'colonel', 'no'
361
+
362
+ def __str__(self):
363
+ return f"{self.no} - {self.get_type_display()}"
364
+
365
+ def save(self, *args, **kwargs):
366
+ if not self.pk:
367
+ for pin_no in INTERFACES_PINS_MAP[self.no]:
368
+ cpin = ColonelPin.objects.get(colonel=self.colonel, no=pin_no)
369
+ if cpin.occupied_by:
370
+ raise ValidationError(
371
+ f"Interface can not be created, because "
372
+ f"GPIO{cpin} is already occupied by {cpin.occupied_by}."
373
+ )
374
+ return super().save(*args, **kwargs)
375
+
376
+
377
+ @receiver(post_save, sender=Interface)
378
+ def post_interface_save(sender, instance, created, *args, **kwargs):
379
+ if created:
380
+ instance.pin_a = ColonelPin.objects.get(
381
+ colonel=instance.colonel, no=INTERFACES_PINS_MAP[instance.no][0]
382
+ )
383
+ instance.pin_a.occupied_by = instance
384
+ instance.pin_a.save()
385
+ instance.pin_b = ColonelPin.objects.get(
386
+ colonel=instance.colonel, no=INTERFACES_PINS_MAP[instance.no][1]
387
+ )
388
+ instance.pin_b.occupied_by = instance
389
+ instance.pin_b.save()
390
+
391
+
392
+ @receiver(post_delete, sender=Interface)
393
+ def post_interface_delete(sender, instance, *args, **kwargs):
394
+ with transaction.atomic():
395
+ ct = ContentType.objects.get_for_model(instance)
396
+ for pin in ColonelPin.objects.filter(
397
+ occupied_by_content_type=ct,
398
+ occupied_by_id=instance.id
399
+ ):
400
+ pin.occupied_by_content_type = None
401
+ pin.occupied_by_content_id = None
402
+ pin.save()
403
+
404
+
@@ -218,15 +218,14 @@ class FleetConsumer(AsyncWebsocketConsumer):
218
218
  }
219
219
  }
220
220
  config_data['settings'].update(instance_options)
221
- i2c_interfaces = await sync_to_async(list, thread_sensitive=True)(
222
- self.colonel.i2c_interfaces.all().select_related(
223
- 'scl_pin', 'sda_pin'
221
+ interfaces = await sync_to_async(list, thread_sensitive=True)(
222
+ self.colonel.interfaces.all().select_related(
223
+ 'pin_a', 'pin_b'
224
224
  )
225
225
  )
226
- for i2c_interface in i2c_interfaces:
227
- config_data['interfaces']['i2c-%d' % i2c_interface.no] = {
228
- 'scl': i2c_interface.scl_pin.no, 'sda': i2c_interface.sda_pin.no,
229
- 'freq': i2c_interface.freq
226
+ for interface in interfaces:
227
+ config_data['interfaces'][f'{interface.type}-{interface.no}'] = {
228
+ 'pin_a': interface.pin_a.no, 'pin_b': interface.pin_b.no,
230
229
  }
231
230
  components = await sync_to_async(
232
231
  list, thread_sensitive=True
@@ -319,6 +318,11 @@ class FleetConsumer(AsyncWebsocketConsumer):
319
318
  asyncio.run(self.send_data({
320
319
  'command': 'discover-ttlock'
321
320
  }))
321
+ elif payload.get('command') == 'discover-dali':
322
+ print("SEND discover-dali command!")
323
+ asyncio.run(self.send_data({
324
+ 'command': 'discover-dali', 'i': payload['interface']
325
+ }))
322
326
  elif payload.get('command') == 'finalize':
323
327
  asyncio.run(self.send_data({
324
328
  'command': 'finalize',
@@ -420,18 +424,21 @@ class FleetConsumer(AsyncWebsocketConsumer):
420
424
  except Exception as e:
421
425
  print(traceback.format_exc(), file=sys.stderr)
422
426
 
423
- elif 'discover-ttlock' in data:
427
+ elif 'discovery-result' in data:
424
428
  def process_discovery_result():
425
- self.gateway.refresh_from_db()
426
- if self.gateway.discovery.get('finished'):
427
- return Component.objects.filter(
429
+ # check if component is already created
430
+ if data['discovery-result'] == 'success':
431
+ comp = Component.objects.filter(
428
432
  meta__finalization_data__temp_id=data['result']['id']
429
433
  ).first()
434
+ if comp:
435
+ return comp
436
+
437
+ self.gateway.refresh_from_db()
430
438
  try:
431
439
  self.gateway.process_discovery(data)
432
440
  except Exception as e:
433
441
  print(traceback.format_exc(), file=sys.stderr)
434
- self.gateway.finish_discovery()
435
442
 
436
443
  finished_comp = await sync_to_async(
437
444
  process_discovery_result, thread_sensitive=True
simo/fleet/utils.py CHANGED
@@ -58,7 +58,7 @@ for no, data in BASE_ESP32_GPIO_PINS.items():
58
58
 
59
59
  # ample-wall
60
60
  for no, data in BASE_ESP32_GPIO_PINS.items():
61
- if no in (4, 12, 13, 14, 15, 23, 32, 33, 34, 36, 39):
61
+ if no in (12, 13, 14, 23, 32, 33, 34, 36, 39):
62
62
  GPIO_PINS['ample-wall'][no] = GPIO_PIN_DEFAULTS.copy()
63
63
  GPIO_PINS['ample-wall'][no].update(data)
64
64
 
@@ -114,3 +114,8 @@ for no, data in BASE_ESP32_GPIO_PINS.items():
114
114
  GPIO_PINS['4-relays'][no]['note'] = 'Relay4'
115
115
  else:
116
116
  GPIO_PINS['4-relays'][no].update(data)
117
+
118
+
119
+ INTERFACES_PINS_MAP = {
120
+ 1: [13, 23], 2: [32, 33]
121
+ }
simo/fleet/views.py CHANGED
@@ -1,9 +1,8 @@
1
- from django.contrib.contenttypes.models import ContentType
2
1
  from django.http import HttpResponse, Http404
3
2
  from django.db.models import Q
4
3
  from dal import autocomplete
5
4
  from simo.core.utils.helpers import search_queryset
6
- from .models import Colonel, ColonelPin, I2CInterface
5
+ from .models import Colonel, ColonelPin, Interface
7
6
 
8
7
 
9
8
  def colonels_ping(request):
@@ -43,20 +42,22 @@ class PinsSelectAutocomplete(autocomplete.Select2QuerySetView):
43
42
  return qs
44
43
 
45
44
 
46
- class I2CInterfaceSelectAutocomplete(autocomplete.Select2ListView):
45
+ class InterfaceSelectAutocomplete(autocomplete.Select2ListView):
47
46
 
48
47
  def get_list(self):
49
48
  if not self.request.user.is_staff:
50
- return []
49
+ return Interface.objects.none()
51
50
 
52
51
  try:
53
52
  colonel = Colonel.objects.get(
54
53
  pk=self.forwarded.get("colonel")
55
54
  )
56
55
  except:
57
- return []
56
+ return Interface.objects.none()
58
57
 
59
- return [
60
- (i.no, i.get_no_display()) for i in
61
- I2CInterface.objects.filter(colonel=colonel)
62
- ]
58
+ qs = Interface.objects.filter(colonel=colonel)
59
+
60
+ if self.forwarded.get('filters'):
61
+ qs = qs.filter(**self.forwarded.get('filters'))
62
+
63
+ return qs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.0.6
3
+ Version: 2.0.7
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
@@ -25,8 +25,8 @@ simo/_hub_template/hub/settings.py,sha256=4QhvhbtLRxHvAntwqG_qeAAtpDUqKvN4jzw9u3
25
25
  simo/_hub_template/hub/supervisor.conf,sha256=IY3fdK0fDD2eAothB0n54xhjQj8LYoXIR96-Adda5Z8,1353
26
26
  simo/_hub_template/hub/urls.py,sha256=Ydm-1BkYAzWeEF-MKSDIFf-7aE4qNLPm48-SA51XgJQ,25
27
27
  simo/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- simo/core/admin.py,sha256=p4wbVpU4H42hwj5edWP-0a2aWElEnrOH0t9WA9SFUZQ,17464
29
- simo/core/api.py,sha256=93q_58VAj-HKzvixGb0Z0T7obDHbdRC4T_YExEtcvM0,23646
28
+ simo/core/admin.py,sha256=MoYz7B5YaTkF2JeacaqsR177N2IagKXc-rG0FTXjJ1w,17622
29
+ simo/core/api.py,sha256=OVvv3a7KYJGbuUgSOfWzPg8hoCCRhdDejQ2kVs0H2p8,23803
30
30
  simo/core/api_auth.py,sha256=_3hG4e1eLKrcRnSAOB_xTL6cwtOJ2_7JS7GZU_iqTgA,1251
31
31
  simo/core/api_meta.py,sha256=li4KLFl6xTYOoD8pgS8PYcjqTZlzhXI0reAkt06PZFA,3404
32
32
  simo/core/app_widgets.py,sha256=EEQOto3fGR0syDqpJE38tQrx8DoTTyg26nF5kYzHY38,2018
@@ -34,19 +34,19 @@ simo/core/auto_urls.py,sha256=0gu-IL7PHobrmKW6ksffiOkAYu-aIorykWdxRNtwGYo,1194
34
34
  simo/core/autocomplete_views.py,sha256=JT5LA2_Wtr60XYSAIqaXFKFYPjrmkEf6yunXD9y2zco,4022
35
35
  simo/core/base_types.py,sha256=yqbIZqBksrAkEuHRbt6iExwPDDy0K5II2NzRCkmOvMU,589
36
36
  simo/core/context.py,sha256=98PXAMie43faRVBFkOG22uNpvGRNprcGhzjBFkrxaRY,1367
37
- simo/core/controllers.py,sha256=paeZU6Ky2LgRTwj9nFqrgfeJ4kxWPcl95WDTf6P7jOo,27200
37
+ simo/core/controllers.py,sha256=2D7YCLktx7a-4tn80DenQP2CdY0dc2bWg6IRU69YTZ8,27246
38
38
  simo/core/dynamic_settings.py,sha256=U2WNL96JzVXdZh0EqMPWrxqO6BaRR2Eo5KTDqz7MC4o,1943
39
39
  simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
40
40
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
41
- simo/core/forms.py,sha256=FkuP1NKWCfMpYGHs0unYiW_bjEuq951IokLRWu4pz9o,21466
41
+ simo/core/forms.py,sha256=OQTPuacid9AoEvZ86G9p6ILuviqJCtSDuwk2WlLj43E,21484
42
42
  simo/core/gateways.py,sha256=s_c2W0v2_te89i6LS4Nj7F2wn9UwjZXPT7pfy6SToVo,3714
43
43
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
44
44
  simo/core/managers.py,sha256=WoQ4OX3akIvoroSYji-nLVqXBSJzCiC1u_IiWkKbKmA,2413
45
45
  simo/core/middleware.py,sha256=64PYjnyRnYf4sgMvPfR0oQqf9UEtxUwnhJe3RV6z_HI,2040
46
- simo/core/models.py,sha256=b8ADs_jb09wt_hqZBux1TW4uHP0UyBnlN1YbTglJpB8,18997
46
+ simo/core/models.py,sha256=VNoHjHUFQRvKH4ejv4kGv5E6a4bSOhuM8sfAlRYaj-g,19036
47
47
  simo/core/permissions.py,sha256=UmFjGPDWtAUbaWxJsWORb2q6BREHqndv9mkSIpnmdLk,1379
48
48
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
49
- simo/core/serializers.py,sha256=JXCgdzJR8cfydtAaXDAHa_H-MilO5r0li_2ZyfdVcnk,15754
49
+ simo/core/serializers.py,sha256=miEh2Sd47KmB0viyNlwrEG_1kxYiTUrvQQvisEoLYuA,15759
50
50
  simo/core/signal_receivers.py,sha256=EZ8NSYZxUgSaLS16YZdK7T__l8dl0joMRllOxx5PUt4,2809
51
51
  simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
52
52
  simo/core/storage.py,sha256=YlxmdRs-zhShWtFKgpJ0qp2NDBuIkJGYC1OJzqkbttQ,572
@@ -56,8 +56,8 @@ simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
56
56
  simo/core/views.py,sha256=hlAKpAbCbqI3a-uL5tDp532T2oLFiF0MBzKUJ_SNzo0,5833
57
57
  simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
58
58
  simo/core/__pycache__/__init__.cpython-38.pyc,sha256=y0IW37wBUIGa3Eh_ZG28pRqHKoLiPyTgUX2OnbkEPlc,158
59
- simo/core/__pycache__/admin.cpython-38.pyc,sha256=NhGeufnlBnidyTV7bzSPOS3yrLMX-18dW0UJANJm1EA,13347
60
- simo/core/__pycache__/api.cpython-38.pyc,sha256=Yklz1SziU8ZLDG6zG7gmSuN_RDaf6bW2lFGCORCpAVc,18775
59
+ simo/core/__pycache__/admin.cpython-38.pyc,sha256=GP3lRW8djW3w_k5jgzs_fuW7j8wnmeysZcDtm5RFnD0,13442
60
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=W-CdACWTu_ebqH52riswadzT7z2mNRZJU8HngqbYXzw,18874
61
61
  simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=5UTBr3rDMERAfc0OuOVDwGeQkt6Q7GLBtZJAMBse1sg,1712
62
62
  simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=bdk1PG7FuRfFwcvQtF103H0kQrx6Vt0JRiepktWEPh8,2730
63
63
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=9Es2wZNduzUJv-jZ_HX0-L3vqwpXWBbseEwoC5K6b-w,3465
@@ -65,19 +65,19 @@ simo/core/__pycache__/auto_urls.cpython-38.pyc,sha256=SVl4fF0-yiq7e9gt08jIM6_rL4
65
65
  simo/core/__pycache__/autocomplete_views.cpython-38.pyc,sha256=hJ6JILI1LqrAtpQMvxnLvljGdW1v1gpvBsD79vFkZ58,3972
66
66
  simo/core/__pycache__/base_types.cpython-38.pyc,sha256=Ukc5U63YJbyUcn0cwNMS8nteRSvEJmCszZUfHClKBtg,735
67
67
  simo/core/__pycache__/context.cpython-38.pyc,sha256=MSZPDhqMhCpUuBJl3HCIBHZA3BntYeP8RAnQcdqAH9k,1278
68
- simo/core/__pycache__/controllers.cpython-38.pyc,sha256=j7ND-Gd9YOcnz9Z92Wrvc55rR6fZN2-_w0BbnNsNjr8,24092
68
+ simo/core/__pycache__/controllers.cpython-38.pyc,sha256=-NjuX7iGheE_ZMqkZ6g4ZnnVjdUnFCTlH0awAJxZt2Y,24110
69
69
  simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=ELu06Hub4DOidja71ybvD3ZM4HdXiyZjNJrZfnXZXNA,2476
70
70
  simo/core/__pycache__/events.cpython-38.pyc,sha256=A1Axx-qftd1r7st7wkO3DkvTdt9-RkcJe5KJhpzJVk8,5109
71
71
  simo/core/__pycache__/filters.cpython-38.pyc,sha256=VIMADCBiYhziIyRmxAyUDJluZvuZmiC4bNYWTRsGSao,721
72
- simo/core/__pycache__/forms.cpython-38.pyc,sha256=iwwT-M_G6jh2X4W8Z14tNKo7ESBMVCJequkCorMLWN4,17823
72
+ simo/core/__pycache__/forms.cpython-38.pyc,sha256=KH1SBm1NaDv99yHONenWWJcd4XSIqQ5tqaF8LSoeDws,17843
73
73
  simo/core/__pycache__/gateways.cpython-38.pyc,sha256=XBiwMfBkjoQ2re6jvADJOwK0_0Aav-crzie9qtfqT9U,4599
74
74
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
75
75
  simo/core/__pycache__/managers.cpython-38.pyc,sha256=5vstOMfm997CZBBkaSiaS7EojhLTWZlbeA_EQ8u-yfg,2554
76
76
  simo/core/__pycache__/middleware.cpython-38.pyc,sha256=bGOFJNEhJeLbpsZp8LYn1VA3paLF5HULHQ6IFKa7Juc,2022
77
- simo/core/__pycache__/models.cpython-38.pyc,sha256=Vj5YpJqEd0xI-lv2kJc_wEUF1gPkTSAM9NNrP3xfL3w,16685
77
+ simo/core/__pycache__/models.cpython-38.pyc,sha256=Hl9MXjnnmDTp826aEc5KLqPFl4ZzrT7HTVxVSz2-Vik,16695
78
78
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=uygjPbfRQiEzyo5-McCxsuMDJLbDYO_TLu55U7bJbR0,1809
79
79
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
80
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=_4Dn280tzqXYLhoOE33WVwjz5ara9i-00VndiEaJsQk,15724
80
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=tJf8jV9pPJXnJjUPXCc103wQxC5ZrZaC9SlIR41JomQ,15707
81
81
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=sgjH_wv-1U99auH5uHb3or0qettPeHAlsz8P7B03ajY,2430
82
82
  simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=NJUr7nRyHFvmAumxxWpsod5wzVVZM99rCEuJs1utHA4,8432
83
83
  simo/core/__pycache__/storage.cpython-38.pyc,sha256=BTkYH8QQyjqI0WOtJC8fHNtgu0YA1vjqZclXjC2vCVI,1116
@@ -170,6 +170,7 @@ simo/core/migrations/0026_category_instance.py,sha256=Slrev0VvCkqEQhKly2ZcM7QUam
170
170
  simo/core/migrations/0027_remove_component_tags.py,sha256=V0o_lgKiVU3HfG5V8MTO-j4UVPakGV5lxV0Jo6qAPpQ,325
171
171
  simo/core/migrations/0028_rename_subcomponents_component_slaves.py,sha256=ioQcfO2_IIfPc_BZzETmSodsYstzygR9U0ULnhET6ac,373
172
172
  simo/core/migrations/0029_auto_20240229_1331.py,sha256=BYXPNwjXApAx7mxE5li3QssfksWTsSjDf_VPQ8iGV8c,1140
173
+ simo/core/migrations/0030_alter_instance_timezone.py,sha256=XZuYr2eD9MvE21Jxfdat8RC3sbc7PaGUfNPaqqxBNzE,23248
173
174
  simo/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
174
175
  simo/core/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=w6GiBXVxWj30Bg4Sn_pFVeA041d-pCrkaq8mR3KuF70,5381
175
176
  simo/core/migrations/__pycache__/0002_load_icons.cpython-38.pyc,sha256=Nb9RrPjVYo_RpZ5PmzoaEIWGCeVt4kicpmGiKlBrpIw,2123
@@ -200,6 +201,7 @@ simo/core/migrations/__pycache__/0026_category_instance.cpython-38.pyc,sha256=0C
200
201
  simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-38.pyc,sha256=Jadlk2tN_3UfPj-xpZssFs5dftZaPl8reWpPWYQu2nY,538
201
202
  simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-38.pyc,sha256=PSiMp1yDzZ36Ei36U2tcIlvyzGgB5RuvGImrJ__7Q5s,593
202
203
  simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-38.pyc,sha256=nO6lBU-1SxMQv67jQs7cGgNnot722UVL9pj3UE14I1k,1086
204
+ simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-38.pyc,sha256=paRgdijg5o8QzluT4GjSEQIMk6UAF7XmSwjqknXPE_4,16333
203
205
  simo/core/migrations/__pycache__/__init__.cpython-38.pyc,sha256=VZmDQ57BTcebuM0KMhjiTOabgWZCBxQmSJzWZos9SO8,169
204
206
  simo/core/static/ansi_styles.css,sha256=4ieJGrjZPKyPSago9FdB_gflHoGE1vxCHi8qVn5tY-Y,37352
205
207
  simo/core/static/admin/Img/plus.svg,sha256=2NpSFPWqGIjpAQGFI7LDQHPKagEhYkJiJX95ufCoZaI,741
@@ -10140,7 +10142,7 @@ simo/core/utils/logs.py,sha256=Zn9JQxqCH9Odx2J1BWT84nFCfkJ4Z4p5X8psdll7hNc,2366
10140
10142
  simo/core/utils/mixins.py,sha256=X6kUPKAi_F-uw7tgm8LEaYalBXpvDA-yrLNFCGr2rks,259
10141
10143
  simo/core/utils/model_helpers.py,sha256=3IzJeOvBoYdUJVXCJkY20npOZXPjNPAiEFvuT0OPhwA,884
10142
10144
  simo/core/utils/relay.py,sha256=i1xy_nPTgY5Xn0l2W4lNI3xeVUpDQTUUfV3M8h2DeBg,457
10143
- simo/core/utils/serialization.py,sha256=JuVMl5Oc2ZrZNW4cTJUiQt-xFESP2fuO_-pun2xQi-M,1887
10145
+ simo/core/utils/serialization.py,sha256=v0HLQ98r3zOlsf6dv6S4WxOEt6BzmFz2eTXa_iuKjSM,2057
10144
10146
  simo/core/utils/type_constants.py,sha256=xR2HXZOw9GZhC47iO1Py5B8mpaQMPbzvqX5nHWakhsY,4116
10145
10147
  simo/core/utils/validators.py,sha256=FRO6_K5HAO1OaC-LosApZjh-W3EA-IJZ53HnwEJgqiI,1297
10146
10148
  simo/core/utils/__pycache__/__init__.cpython-38.pyc,sha256=NJHPMizDKYRDEyMdQIh-ZRwT-BntwrvYfF450N2RYdI,164
@@ -10156,39 +10158,39 @@ simo/core/utils/__pycache__/logs.cpython-38.pyc,sha256=BVVeQoOhfRHm3SHnCoE1d5G84
10156
10158
  simo/core/utils/__pycache__/mixins.cpython-38.pyc,sha256=8Js2T7jVQ7hugRUIRu3rdxW86dJW4KeUUWqKqSkIGb0,615
10157
10159
  simo/core/utils/__pycache__/model_helpers.cpython-38.pyc,sha256=QzO0rh1NuQePHDCSLmUCRrAZEnV4o8jh9CF_jp7IoUo,1351
10158
10160
  simo/core/utils/__pycache__/relay.cpython-38.pyc,sha256=gs4iN9TWBo_JIW07emIggIcv6gHKuOY_4jfmAFhuL3k,697
10159
- simo/core/utils/__pycache__/serialization.cpython-38.pyc,sha256=Mq5NrDvrKiiwjZFUrl5dJ6cgJikRNGHu8BjwJf0qlhQ,1254
10161
+ simo/core/utils/__pycache__/serialization.cpython-38.pyc,sha256=9nTbzozDi8Avl6krHvAo67CLdiTrYW0ij3hQtucHty0,1338
10160
10162
  simo/core/utils/__pycache__/type_constants.cpython-38.pyc,sha256=bEMvzkBxzc6MKq6gn9A6wszXzMjLTbX-V-IK4NMht8E,3363
10161
10163
  simo/core/utils/__pycache__/validators.cpython-38.pyc,sha256=gjeBOjL_keMoRDjdn8v-3F3wcjPIT3Xx5KpTalo0e-Y,1247
10162
10164
  simo/fleet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10163
- simo/fleet/admin.py,sha256=Vxp3yTNRVoDif_hwwBW3weeMNakQ3iZo-GC0VvdScfQ,5699
10165
+ simo/fleet/admin.py,sha256=aQulOPtrIQUKj8WvA4GfINfqVA52fcU72yK2hVlcmJ0,5681
10164
10166
  simo/fleet/api.py,sha256=Hxn84xI-Q77HxjINgRbjSJQOv9jii4OL20LxK0VSrS8,2499
10165
- simo/fleet/auto_urls.py,sha256=gAXTWUvsWkQHRdZGM_W_5iJBEsM4lY063kIx3f5LUqs,578
10167
+ simo/fleet/auto_urls.py,sha256=X04oKJWA48wFW5iXg3PPROY2KDdHn_a99orQSE28QC4,518
10166
10168
  simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
10167
- simo/fleet/controllers.py,sha256=N8Qzdp2RPFrpZ_l9O4u8VjHWoY_WTWGg76s3V3oJqEs,13999
10168
- simo/fleet/forms.py,sha256=HpvcdFyMl9dLNx1sEOkAkXOkYht6ku2HwWWga-PJzZQ,35067
10169
- simo/fleet/gateways.py,sha256=xFsmF_SXYXK_kMJOCHkiInPJ_0VcPWz-kJDoMup2lT8,1576
10170
- simo/fleet/managers.py,sha256=kpfvvfdH4LDxddIBDpdAb5gsVk8Gb0-L9biFcj9OFPs,807
10171
- simo/fleet/models.py,sha256=O0lsXRmTgPyOhpcwWeJ-2GHTNe2uFhiJy4FTW9Ljz-c,11830
10169
+ simo/fleet/controllers.py,sha256=VxutXZSZaZHmXGYpqjsC_6DgJsF1ZDZeJwu3px79wSE,16683
10170
+ simo/fleet/forms.py,sha256=pR_KER9u9VtNb5NpSWwI7LrnBBtn9jbEXzUvyFRzoj0,35986
10171
+ simo/fleet/gateways.py,sha256=m-jF8S_kJCI-yLI0UmWm46xZrsHcvSfw2gozZWRoFfE,1707
10172
+ simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
10173
+ simo/fleet/models.py,sha256=7ZZ1z_cId7z9bEzLHvEEDtpFwUMgIUDesr5hhveDcWg,14136
10172
10174
  simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
10173
10175
  simo/fleet/serializers.py,sha256=zEpXAXxjk4Rf1JhlNnLTrs20qJggqjvIySbeHVo4Tt4,1505
10174
- simo/fleet/socket_consumers.py,sha256=xNeR1IuaBTiHO2GEXwB1_4CJ29uMlqBycIUdxGT96E8,19578
10175
- simo/fleet/utils.py,sha256=D0EGFbDmW8zyhyxf5ozGtRpo4Sy5Ov6ZixukBK_e2Do,3462
10176
- simo/fleet/views.py,sha256=PbdZpsM_7-oyKzuDX1A5WULNABA1_B7ISF70UJX97FE,1662
10176
+ simo/fleet/socket_consumers.py,sha256=ii5L1di8iXzn-l91zVFQ_g9YQm_a-_Z-Dn5OnKbJ9FI,19876
10177
+ simo/fleet/utils.py,sha256=2gcjbwQawsGw2edr_wm9q6XacGpYqO-gd4BF1t0Hg6U,3511
10178
+ simo/fleet/views.py,sha256=WMMG8rEJA6RTOf3U-2sYbiSH2Q3rBC-6kYg9KpYHtlI,1686
10177
10179
  simo/fleet/__pycache__/__init__.cpython-38.pyc,sha256=pIZE7EL6-cuJ3pQtaSwjKLrKLsTYelp1k9sRhXKLh6s,159
10178
- simo/fleet/__pycache__/admin.cpython-38.pyc,sha256=sVZl_jESRoUjJRMDSlpzFkwW0uUNeBdlu95jPehilqc,5807
10180
+ simo/fleet/__pycache__/admin.cpython-38.pyc,sha256=Tw3g9JKzJ3ICjWnHQedU8qV7RSZeJL81jSYpvTLK5bM,5798
10179
10181
  simo/fleet/__pycache__/api.cpython-38.pyc,sha256=rL9fb7cCQatyFvXyKmlNOKmxVo8vHYeYhfSiAgchyAs,3110
10180
- simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=P-ja8CU47dnovCrZu2vv1ut0iEQTgyoefZMS0T39BBM,604
10182
+ simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=SqyTuaz_kEBvx-bL46SclsZEEP5RFh6U6TGKyXDdiOE,565
10181
10183
  simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
10182
- simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=dVdHAhAjCiS9QRkcWryFHh7MtrfEDtlCGly7qyiQnos,12944
10183
- simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=_oArxGwzm-ct4McPfWm4ymlr-Q2Qa9iXjHhcRB-1yPc,24416
10184
- simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=DT07jzeceh0QpT2eQd4dhX9gB87SmTNE9mBdQhRVRHg,2056
10185
- simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=JMyjf8wVsVGqox645or0qaO6B4Ek-K1oa1eV1FQCTvA,1316
10186
- simo/fleet/__pycache__/models.cpython-38.pyc,sha256=5Dac_TOovkwFpdE_qwyqLVtbG6PHMDxaCXDbqzJWCs8,10463
10184
+ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=sOxMEUCc347vDlsC2Pp9h5jxyhax2dFBAVEgP_aTN3s,14848
10185
+ simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=7AjtKMSUAuaxLIRx1lvEfRaAlujKRyIMK7gnJjru-fI,25650
10186
+ simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=Qpfw3NYxCS9tS63FaZz8fdL9fq5X1k5QcQlaJl-szb4,2152
10187
+ simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
10188
+ simo/fleet/__pycache__/models.cpython-38.pyc,sha256=1nBzbxLzIOYxss3wx0-lyGP-JCHnGdbADH_NDQ4If50,12273
10187
10189
  simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
10188
10190
  simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=yuY2H7jcboQGZdjb5WIsgNHXFhI9IPMUrEu9NgSiXNo,2452
10189
- simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=kavoF9hB6ohz5k1KyqxAuiq4EYIWCTdNG0MyapDYzX0,14325
10190
- simo/fleet/__pycache__/utils.cpython-38.pyc,sha256=NprFr6NRDZSv7I2Vj1WiL6FbuW6a0KWhzHjbKESMlHc,1888
10191
- simo/fleet/__pycache__/views.cpython-38.pyc,sha256=IiPtx3PRmmUpq4MM-Lr90O4QYczugGzHlsk3e1qiOvI,2054
10191
+ simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=5bmMyD3gRyfR2Hbh0KwZwMPYzZR8NPWuMhN8PHWOqLg,14408
10192
+ simo/fleet/__pycache__/utils.cpython-38.pyc,sha256=dTuvW9MnhUycwdCc6eHYfHsMlvZw-CmEWXWYu18X8Uw,1955
10193
+ simo/fleet/__pycache__/views.cpython-38.pyc,sha256=HLHXI3JgCDUWP7oY944nBqpVVu0D6-qOuiSMraNUdq8,1825
10192
10194
  simo/fleet/migrations/0001_initial.py,sha256=lce8nkD8Sz6pYr-XJSpDm4CMDuB6TA__WtnHpIp-eA4,1326
10193
10195
  simo/fleet/migrations/0002_auto_20220422_0743.py,sha256=sFOfAjnQOzcJjE8lHrrHgTaGilJNYswMdXphgVzUZqY,825
10194
10196
  simo/fleet/migrations/0003_auto_20220422_0752.py,sha256=VcH7DyMAniEwT76hDVofS8FTNpM3nxz_J9AC2zKHDSA,543
@@ -10220,6 +10222,8 @@ simo/fleet/migrations/0028_remove_i2cinterface_scl_pin_no_and_more.py,sha256=Ceo
10220
10222
  simo/fleet/migrations/0029_alter_i2cinterface_scl_pin_and_more.py,sha256=aquymc1ZcUVgdrqZxl3viN6kiCHtw4HjgL6n4d0cSpQ,886
10221
10223
  simo/fleet/migrations/0030_colonelpin_label_alter_colonel_type.py,sha256=5T5bmQxPZrG0UseCLd7ssV-AeFF3O4T_DFxLu3whSqg,706
10222
10224
  simo/fleet/migrations/0031_alter_colonel_type.py,sha256=Kv_Gld-X0NZ7d2P9WBXfIlhq4iPH1_NnzDrPyy9_Pos,522
10225
+ simo/fleet/migrations/0032_auto_20240415_0736.py,sha256=yBT48pIfDBm7J1Y3LrvNtmihRbwEXjmBGBB1ghc2z5Y,1800
10226
+ simo/fleet/migrations/0033_auto_20240415_0736.py,sha256=_7p3-Qdc7aaP4mDwny_ig5E4XoEm8t2PoZ3-UeQ4jio,758
10223
10227
  simo/fleet/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10224
10228
  simo/fleet/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=9kc1UyMEYkRNVnZ7iwZbiW1t3qWXROvWrI2G1BdzIaA,1250
10225
10229
  simo/fleet/migrations/__pycache__/0002_auto_20220422_0743.cpython-38.pyc,sha256=8oxhGb7rL8QYKlBLU3pOYcd8aHeQWDB9I8awkK04mXg,841
@@ -10252,6 +10256,8 @@ simo/fleet/migrations/__pycache__/0028_remove_i2cinterface_scl_pin_no_and_more.c
10252
10256
  simo/fleet/migrations/__pycache__/0029_alter_i2cinterface_scl_pin_and_more.cpython-38.pyc,sha256=S0V5f3Q366v6NlSBW78IqjC8evoFoOTnoYmsFhsOBO4,902
10253
10257
  simo/fleet/migrations/__pycache__/0030_colonelpin_label_alter_colonel_type.cpython-38.pyc,sha256=sfglSDxXLKJ0qE8Dl3MYjv5hbszpDtb9CDxatoEzPSw,853
10254
10258
  simo/fleet/migrations/__pycache__/0031_alter_colonel_type.cpython-38.pyc,sha256=zXX254ZgEE4uSV8xnLdH9DM3qy-ICmbrT05i0Q287bU,733
10259
+ simo/fleet/migrations/__pycache__/0032_auto_20240415_0736.cpython-38.pyc,sha256=QD3JNIDQhzseXKLRYysYY3Q9_vDaurIhlWBcri83FMw,1655
10260
+ simo/fleet/migrations/__pycache__/0033_auto_20240415_0736.cpython-38.pyc,sha256=XBy2jZZ4kDRn06KC9YcHRnoaol8heCMAvHZ3BAELr2c,1031
10255
10261
  simo/fleet/migrations/__pycache__/__init__.cpython-38.pyc,sha256=5k1KW0jeSDzw6RnVPRq4CaO13Lg7M0F-pxA_gqqZ6Mg,170
10256
10262
  simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10257
10263
  simo/generic/app_widgets.py,sha256=E_pnpA1hxMIhenRCrHoQ5cik06jm2BAHCkl_eo-OudU,1264
@@ -10431,8 +10437,8 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
10431
10437
  simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10432
10438
  simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10433
10439
  simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10434
- simo-2.0.6.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10435
- simo-2.0.6.dist-info/METADATA,sha256=PyDP96gxumILX0PRUHKNWqLdOFuHkNoI1ulsao4ZMRs,1699
10436
- simo-2.0.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
10437
- simo-2.0.6.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10438
- simo-2.0.6.dist-info/RECORD,,
10440
+ simo-2.0.7.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10441
+ simo-2.0.7.dist-info/METADATA,sha256=D3DwzzxRfVOdr1NCw4Me2MvxkgLnZ-jPQdbnREr0oV0,1699
10442
+ simo-2.0.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
10443
+ simo-2.0.7.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10444
+ simo-2.0.7.dist-info/RECORD,,
File without changes