simo 2.0.2__py3-none-any.whl → 2.0.4__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/_hub_template/hub/nginx.conf +2 -2
- simo/core/controllers.py +24 -5
- simo/core/socket_consumers.py +5 -0
- simo/core/utils/logs.py +34 -0
- simo/fleet/forms.py +3 -1
- simo/fleet/models.py +13 -36
- simo/fleet/socket_consumers.py +107 -99
- {simo-2.0.2.dist-info → simo-2.0.4.dist-info}/METADATA +2 -1
- {simo-2.0.2.dist-info → simo-2.0.4.dist-info}/RECORD +12 -12
- {simo-2.0.2.dist-info → simo-2.0.4.dist-info}/LICENSE.md +0 -0
- {simo-2.0.2.dist-info → simo-2.0.4.dist-info}/WHEEL +0 -0
- {simo-2.0.2.dist-info → simo-2.0.4.dist-info}/top_level.txt +0 -0
simo/core/controllers.py
CHANGED
|
@@ -228,7 +228,7 @@ class ControllerBase(ABC):
|
|
|
228
228
|
self.component.change_init_fingerprint = None
|
|
229
229
|
self.component.save()
|
|
230
230
|
|
|
231
|
-
def _receive_from_device(self, value, is_alive=True):
|
|
231
|
+
def _receive_from_device(self, value, is_alive=True, battery_level=None):
|
|
232
232
|
value = self._prepare_for_set(value)
|
|
233
233
|
actor = self._get_actor(value)
|
|
234
234
|
|
|
@@ -241,7 +241,9 @@ class ControllerBase(ABC):
|
|
|
241
241
|
# in relation to the change of this component
|
|
242
242
|
introduce(actor)
|
|
243
243
|
self.component.alive = is_alive
|
|
244
|
-
|
|
244
|
+
if battery_level:
|
|
245
|
+
self.battery_level = battery_level
|
|
246
|
+
self.component.save(update_fields=['alive', 'battery_level'])
|
|
245
247
|
self.set(value, actor)
|
|
246
248
|
|
|
247
249
|
if init_by_device and self.component.slaves.count():
|
|
@@ -762,19 +764,36 @@ class Lock(Switch):
|
|
|
762
764
|
app_widget = LockWidget
|
|
763
765
|
admin_widget_template = 'admin/controller_widgets/lock.html'
|
|
764
766
|
|
|
767
|
+
UNLOCKED = 0
|
|
768
|
+
LOCKED = 1
|
|
769
|
+
LOCKING = 2
|
|
770
|
+
UNLOCKING = 3
|
|
771
|
+
FAULT = 4
|
|
772
|
+
|
|
765
773
|
def lock(self):
|
|
766
774
|
self.turn_on()
|
|
767
775
|
|
|
768
776
|
def unlock(self):
|
|
769
777
|
self.turn_off()
|
|
770
778
|
|
|
771
|
-
def _receive_from_device(self, value, is_alive=True):
|
|
772
|
-
if type(value)
|
|
779
|
+
def _receive_from_device(self, value, is_alive=True, battery_level=None):
|
|
780
|
+
if type(value) == bool:
|
|
773
781
|
if value:
|
|
774
782
|
value = 'locked'
|
|
775
783
|
else:
|
|
776
784
|
value = 'unlocked'
|
|
777
|
-
|
|
785
|
+
if type(value) == int:
|
|
786
|
+
values_map = {
|
|
787
|
+
self.UNLOCKED: 'unlocked',
|
|
788
|
+
self.LOCKED: 'locked',
|
|
789
|
+
self.LOCKING: 'locking',
|
|
790
|
+
self.UNLOCKING: 'unlocking',
|
|
791
|
+
self.FAULT: 'fault'
|
|
792
|
+
}
|
|
793
|
+
value = values_map.get(value, 'fault')
|
|
794
|
+
return super()._receive_from_device(
|
|
795
|
+
value, is_alive=is_alive, battery_level=battery_level
|
|
796
|
+
)
|
|
778
797
|
|
|
779
798
|
def _validate_val(self, value, occasion=None):
|
|
780
799
|
if occasion == BEFORE_SEND:
|
simo/core/socket_consumers.py
CHANGED
|
@@ -7,6 +7,7 @@ from django.conf import settings
|
|
|
7
7
|
from django.contrib.contenttypes.models import ContentType
|
|
8
8
|
from channels.generic.websocket import AsyncWebsocketConsumer, WebsocketConsumer
|
|
9
9
|
from simo.core.events import ObjectChangeEvent, get_event_obj
|
|
10
|
+
from simo.core.utils.logs import capture_socket_errors
|
|
10
11
|
import paho.mqtt.client as mqtt
|
|
11
12
|
from simo.users.middleware import introduce
|
|
12
13
|
from simo.core.models import Component, Gateway
|
|
@@ -14,6 +15,7 @@ from simo.core.utils.model_helpers import get_log_file_path
|
|
|
14
15
|
from simo.core.middleware import introduce_instance
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
@capture_socket_errors
|
|
17
19
|
class SIMOWebsocketConsumer(WebsocketConsumer):
|
|
18
20
|
headers = {}
|
|
19
21
|
|
|
@@ -24,6 +26,7 @@ class SIMOWebsocketConsumer(WebsocketConsumer):
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
|
|
29
|
+
@capture_socket_errors
|
|
27
30
|
class LogConsumer(AsyncWebsocketConsumer):
|
|
28
31
|
log_file = None
|
|
29
32
|
in_error = False
|
|
@@ -123,6 +126,7 @@ class LogConsumer(AsyncWebsocketConsumer):
|
|
|
123
126
|
self.log_file = None
|
|
124
127
|
|
|
125
128
|
|
|
129
|
+
@capture_socket_errors
|
|
126
130
|
class GatewayController(SIMOWebsocketConsumer):
|
|
127
131
|
gateway = None
|
|
128
132
|
_mqtt_client = None
|
|
@@ -178,6 +182,7 @@ class GatewayController(SIMOWebsocketConsumer):
|
|
|
178
182
|
pass
|
|
179
183
|
|
|
180
184
|
|
|
185
|
+
@capture_socket_errors
|
|
181
186
|
class ComponentController(SIMOWebsocketConsumer):
|
|
182
187
|
component = None
|
|
183
188
|
send_value = False
|
simo/core/utils/logs.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from functools import wraps
|
|
3
|
+
from inspect import iscoroutinefunction
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
from channels.exceptions import AcceptConnection, DenyConnection, StopConsumer
|
|
6
|
+
|
|
7
|
+
logger = getLogger()
|
|
2
8
|
|
|
3
9
|
|
|
4
10
|
class StreamToLogger(object):
|
|
@@ -28,3 +34,31 @@ class StreamToLogger(object):
|
|
|
28
34
|
if self.linebuf != '':
|
|
29
35
|
self.logger.log(self.log_level, self.linebuf.rstrip())
|
|
30
36
|
self.linebuf = ''
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def propagate_exceptions(func):
|
|
42
|
+
async def wrapper(*args, **kwargs): # we're wrapping an async function
|
|
43
|
+
try:
|
|
44
|
+
return await func(*args, **kwargs)
|
|
45
|
+
except (AcceptConnection, DenyConnection, StopConsumer): # these are handled by channels
|
|
46
|
+
raise
|
|
47
|
+
except Exception as exception: # any other exception
|
|
48
|
+
# avoid logging the same exception multiple times
|
|
49
|
+
if not getattr(exception, "caught", False):
|
|
50
|
+
setattr(exception, "caught", True)
|
|
51
|
+
logger.error(
|
|
52
|
+
"Exception occurred in {}:".format(func.__qualname__),
|
|
53
|
+
exc_info=exception,
|
|
54
|
+
)
|
|
55
|
+
raise # propagate the exception
|
|
56
|
+
return wraps(func)(wrapper)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def capture_socket_errors(consumer_class):
|
|
60
|
+
for method_name, method in list(consumer_class.__dict__.items()):
|
|
61
|
+
if iscoroutinefunction(method): # an async method
|
|
62
|
+
# wrap the method with a decorator that propagate exceptions
|
|
63
|
+
setattr(consumer_class, method_name, propagate_exceptions(method))
|
|
64
|
+
return consumer_class
|
simo/fleet/forms.py
CHANGED
|
@@ -106,6 +106,8 @@ class ColonelComponentForm(BaseComponentForm):
|
|
|
106
106
|
)
|
|
107
107
|
|
|
108
108
|
def clean_colonel(self):
|
|
109
|
+
if not self.instance.pk:
|
|
110
|
+
return self.cleaned_data['colonel']
|
|
109
111
|
org = self.instance.config.get('colonel')
|
|
110
112
|
if org and org != self.cleaned_data['colonel'].id:
|
|
111
113
|
raise forms.ValidationError(
|
|
@@ -618,7 +620,7 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
|
|
|
618
620
|
help_text="easeOutSine - offers most naturally looking effect."
|
|
619
621
|
)
|
|
620
622
|
inverse = forms.BooleanField(
|
|
621
|
-
label=_("Inverse dimmer signal"), required=False
|
|
623
|
+
label=_("Inverse dimmer signal"), required=False, initial=True
|
|
622
624
|
)
|
|
623
625
|
on_value = forms.FloatField(
|
|
624
626
|
required=True, initial=100,
|
simo/fleet/models.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import requests
|
|
2
|
+
import time
|
|
2
3
|
from django.db import transaction
|
|
3
4
|
from django.db import models
|
|
4
5
|
from django.db.models.signals import post_save, pre_delete, post_delete
|
|
@@ -82,10 +83,12 @@ class Colonel(DirtyFieldsMixin, models.Model):
|
|
|
82
83
|
occupied_pins = models.JSONField(default=dict, blank=True)
|
|
83
84
|
|
|
84
85
|
logs_stream = models.BooleanField(
|
|
85
|
-
default=False, help_text="ATENTION! Causes serious overhead
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
86
|
+
default=False, help_text="ATENTION! Causes serious overhead and "
|
|
87
|
+
"significantly degrades the lifespan of a chip "
|
|
88
|
+
"due to a lot of writes to the memory. "
|
|
89
|
+
"It also causes Colonel websocket to run out of memory "
|
|
90
|
+
"and reset if a lot of data is being transmitted. "
|
|
91
|
+
"Leave this off, unleess you know what you are doing!"
|
|
89
92
|
)
|
|
90
93
|
pwm_frequency = models.IntegerField(default=1, choices=(
|
|
91
94
|
(0, "3kHz"), (1, "22kHz")
|
|
@@ -183,39 +186,13 @@ class Colonel(DirtyFieldsMixin, models.Model):
|
|
|
183
186
|
interface.scl_pin.save()
|
|
184
187
|
|
|
185
188
|
|
|
186
|
-
@transaction.atomic()
|
|
187
189
|
def move_to(self, other_colonel):
|
|
188
|
-
|
|
189
|
-
other_colonel.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
component.config['colonel'] = other_colonel.id
|
|
195
|
-
component.save()
|
|
196
|
-
self.components.remove(component)
|
|
197
|
-
other_colonel.components.add(component)
|
|
198
|
-
|
|
199
|
-
self.rebuild_occupied_pins()
|
|
200
|
-
other_colonel.rebuild_occupied_pins()
|
|
201
|
-
|
|
202
|
-
other_colonel.i2c_interfaces.all().delete()
|
|
203
|
-
|
|
204
|
-
for i2c_interface in self.i2c_interfaces.all():
|
|
205
|
-
I2CInterface.objects.create(
|
|
206
|
-
no=i2c_interface.no,
|
|
207
|
-
colonel=other_colonel, name=i2c_interface.name,
|
|
208
|
-
freq=i2c_interface.freq,
|
|
209
|
-
scl_pin=ColonelPin.objects.get(
|
|
210
|
-
colonel=other_colonel, no=i2c_interface.scl_pin.no,
|
|
211
|
-
),
|
|
212
|
-
sda_pin=ColonelPin.objects.get(
|
|
213
|
-
colonel=other_colonel, no=i2c_interface.sda_pin.no,
|
|
214
|
-
),
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
self.update_config()
|
|
218
|
-
other_colonel.update_config()
|
|
190
|
+
self.restart()
|
|
191
|
+
other_colonel.restart()
|
|
192
|
+
time.sleep(1)
|
|
193
|
+
self.uid = other_colonel.uid
|
|
194
|
+
other_colonel.delete()
|
|
195
|
+
self.save()
|
|
219
196
|
|
|
220
197
|
|
|
221
198
|
class ColonelPin(models.Model):
|
simo/fleet/socket_consumers.py
CHANGED
|
@@ -13,15 +13,18 @@ import paho.mqtt.client as mqtt
|
|
|
13
13
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
|
14
14
|
from asgiref.sync import sync_to_async
|
|
15
15
|
from simo.core.utils.model_helpers import get_log_file_path
|
|
16
|
+
from simo.core.utils.logs import capture_socket_errors
|
|
16
17
|
from simo.core.events import GatewayObjectCommand, get_event_obj
|
|
17
18
|
from simo.core.models import Gateway, Instance, Component
|
|
18
19
|
from simo.conf import dynamic_settings
|
|
19
20
|
from simo.users.models import Fingerprint
|
|
21
|
+
|
|
20
22
|
from .gateways import FleetGatewayHandler
|
|
21
23
|
from .models import Colonel
|
|
22
24
|
from .controllers import TTLock
|
|
23
25
|
|
|
24
26
|
|
|
27
|
+
@capture_socket_errors
|
|
25
28
|
class FleetConsumer(AsyncWebsocketConsumer):
|
|
26
29
|
colonel = None
|
|
27
30
|
colonel_logger = None
|
|
@@ -43,6 +46,8 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
async def connect(self):
|
|
49
|
+
print("Fleet Socket Connect with headers:", self.scope.get('headers'))
|
|
50
|
+
await self.accept()
|
|
46
51
|
|
|
47
52
|
headers = {
|
|
48
53
|
item[0].decode().lower(): item[1].decode() for item in self.scope['headers']
|
|
@@ -88,7 +93,8 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
88
93
|
'name': headers.get('colonel-name'),
|
|
89
94
|
'type': headers['colonel-type'],
|
|
90
95
|
'firmware_version': headers['firmware-version'],
|
|
91
|
-
'last_seen': timezone.now()
|
|
96
|
+
'last_seen': timezone.now(),
|
|
97
|
+
'enabled': True
|
|
92
98
|
}
|
|
93
99
|
with transaction.atomic():
|
|
94
100
|
colonel, new = Colonel.objects.get_or_create(
|
|
@@ -96,10 +102,10 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
96
102
|
)
|
|
97
103
|
if not new:
|
|
98
104
|
for key, val in defaults.items():
|
|
105
|
+
if key in ('new', ):
|
|
106
|
+
continue
|
|
99
107
|
setattr(colonel, key, val)
|
|
100
|
-
|
|
101
|
-
colonel.enabled = True
|
|
102
|
-
colonel.save()
|
|
108
|
+
colonel.save()
|
|
103
109
|
|
|
104
110
|
return colonel, new
|
|
105
111
|
|
|
@@ -110,7 +116,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
110
116
|
print(f"Colonel {self.colonel} connected!")
|
|
111
117
|
if not self.colonel.enabled:
|
|
112
118
|
print("Colonel %s drop, it's not enabled!" % str(self.colonel))
|
|
113
|
-
await self.accept()
|
|
114
119
|
return await self.close()
|
|
115
120
|
|
|
116
121
|
if headers.get('instance-uid') != self.colonel.instance.uid \
|
|
@@ -120,8 +125,6 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
120
125
|
|
|
121
126
|
self.connected = True
|
|
122
127
|
|
|
123
|
-
await self.accept()
|
|
124
|
-
|
|
125
128
|
await self.log_colonel_connected()
|
|
126
129
|
|
|
127
130
|
|
|
@@ -345,106 +348,111 @@ class FleetConsumer(AsyncWebsocketConsumer):
|
|
|
345
348
|
|
|
346
349
|
|
|
347
350
|
async def receive(self, text_data=None, bytes_data=None):
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
351
|
+
try:
|
|
352
|
+
if text_data:
|
|
353
|
+
print(f"{self.colonel}: {text_data}")
|
|
354
|
+
data = json.loads(text_data)
|
|
355
|
+
if 'get_config' in data:
|
|
356
|
+
config = await self.get_config_data()
|
|
357
|
+
print("Send config: ", config)
|
|
358
|
+
await self.send_data({
|
|
359
|
+
'command': 'set_config', 'data': config
|
|
360
|
+
}, compress=True)
|
|
361
|
+
elif 'comp' in data:
|
|
359
362
|
try:
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
receive_val, thread_sensitive=True
|
|
380
|
-
)(data['val'])
|
|
381
|
-
|
|
382
|
-
if 'options' in data:
|
|
383
|
-
def receive_options(val):
|
|
384
|
-
component.meta['options'] = val
|
|
385
|
-
component.save()
|
|
386
|
-
await sync_to_async(
|
|
387
|
-
receive_options, thread_sensitive=True
|
|
388
|
-
)(data['options'])
|
|
389
|
-
|
|
390
|
-
if 'codes' in data and component.controller_uid == TTLock.uid:
|
|
391
|
-
def save_codes(codes):
|
|
392
|
-
component.meta['codes'] = codes
|
|
393
|
-
for code in codes:
|
|
394
|
-
Fingerprint.objects.get_or_create(
|
|
395
|
-
value=f"ttlock-{component.id}-code-{str(code)}",
|
|
396
|
-
defaults={'type': "TTLock code"}
|
|
363
|
+
try:
|
|
364
|
+
id=int(data['comp'])
|
|
365
|
+
except:
|
|
366
|
+
return
|
|
367
|
+
|
|
368
|
+
component = await sync_to_async(
|
|
369
|
+
Component.objects.get, thread_sensitive=True
|
|
370
|
+
)(id=id)
|
|
371
|
+
|
|
372
|
+
if 'val' in data:
|
|
373
|
+
def receive_val(data):
|
|
374
|
+
if data.get('actor'):
|
|
375
|
+
fingerprint = Fingerprint.objects.filter(
|
|
376
|
+
value=f"ttlock-{component.id}-{data.get('actor')}",
|
|
377
|
+
).first()
|
|
378
|
+
component.change_init_fingerprint = fingerprint
|
|
379
|
+
component.controller._receive_from_device(
|
|
380
|
+
data['val'], bool(data.get('alive')),
|
|
381
|
+
data.get('battery_level')
|
|
397
382
|
)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
383
|
+
await sync_to_async(
|
|
384
|
+
receive_val, thread_sensitive=True
|
|
385
|
+
)(data)
|
|
386
|
+
|
|
387
|
+
if 'options' in data:
|
|
388
|
+
def receive_options(val):
|
|
389
|
+
component.meta['options'] = val
|
|
390
|
+
component.save()
|
|
391
|
+
await sync_to_async(
|
|
392
|
+
receive_options, thread_sensitive=True
|
|
393
|
+
)(data['options'])
|
|
394
|
+
|
|
395
|
+
if 'codes' in data and component.controller_uid == TTLock.uid:
|
|
396
|
+
def save_codes(codes):
|
|
397
|
+
component.meta['codes'] = codes
|
|
398
|
+
for code in codes:
|
|
399
|
+
Fingerprint.objects.get_or_create(
|
|
400
|
+
value=f"ttlock-{component.id}-code-{str(code)}",
|
|
401
|
+
defaults={'type': "TTLock code"}
|
|
402
|
+
)
|
|
403
|
+
component.save()
|
|
404
|
+
await sync_to_async(
|
|
405
|
+
save_codes, thread_sensitive=True
|
|
406
|
+
)(data['codes'])
|
|
407
|
+
if 'fingerprints' in data and component.controller_uid == TTLock.uid:
|
|
408
|
+
def save_codes(codes):
|
|
409
|
+
component.meta['fingerprints'] = codes
|
|
410
|
+
for code in codes:
|
|
411
|
+
Fingerprint.objects.get_or_create(
|
|
412
|
+
value=f"ttlock-{component.id}-finger-{str(code)}",
|
|
413
|
+
defaults={'type': "TTLock Fingerprint"}
|
|
414
|
+
)
|
|
415
|
+
component.save()
|
|
416
|
+
await sync_to_async(
|
|
417
|
+
save_codes, thread_sensitive=True
|
|
418
|
+
)(data['fingerprints'])
|
|
419
|
+
|
|
427
420
|
except Exception as e:
|
|
428
421
|
print(traceback.format_exc(), file=sys.stderr)
|
|
429
|
-
self.gateway.finish_discovery()
|
|
430
422
|
|
|
431
|
-
|
|
432
|
-
process_discovery_result
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
423
|
+
elif 'discover-ttlock' in data:
|
|
424
|
+
def process_discovery_result():
|
|
425
|
+
self.gateway.refresh_from_db()
|
|
426
|
+
if self.gateway.discovery.get('finished'):
|
|
427
|
+
return Component.objects.filter(
|
|
428
|
+
meta__finalization_data__temp_id=data['result']['id']
|
|
429
|
+
).first()
|
|
430
|
+
try:
|
|
431
|
+
self.gateway.process_discovery(data)
|
|
432
|
+
except Exception as e:
|
|
433
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
434
|
+
self.gateway.finish_discovery()
|
|
435
|
+
|
|
436
|
+
finished_comp = await sync_to_async(
|
|
437
|
+
process_discovery_result, thread_sensitive=True
|
|
438
|
+
)()
|
|
439
|
+
if finished_comp:
|
|
440
|
+
await self.send_data({
|
|
441
|
+
'command': 'finalize',
|
|
442
|
+
'data': finished_comp.meta['finalization_data']
|
|
443
|
+
})
|
|
439
444
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
445
|
+
elif bytes_data:
|
|
446
|
+
if not self.colonel_logger:
|
|
447
|
+
await self.start_logger()
|
|
443
448
|
|
|
444
|
-
|
|
445
|
-
|
|
449
|
+
for logline in bytes_data.decode(errors='replace').split('\n'):
|
|
450
|
+
self.colonel_logger.log(logging.INFO, logline)
|
|
451
|
+
|
|
452
|
+
await self.log_colonel_connected()
|
|
453
|
+
except Exception as e:
|
|
454
|
+
print(traceback.format_exc(), file=sys.stderr)
|
|
446
455
|
|
|
447
|
-
await self.log_colonel_connected()
|
|
448
456
|
|
|
449
457
|
|
|
450
458
|
async def log_colonel_connected(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: simo
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
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
|
|
@@ -43,4 +43,5 @@ Requires-Dist: ansi2html ==1.7.0
|
|
|
43
43
|
Requires-Dist: slugify ==0.0.1
|
|
44
44
|
Requires-Dist: django-countries ==7.5.1
|
|
45
45
|
Requires-Dist: librosa ==0.10.1
|
|
46
|
+
Requires-Dist: daphne ==4.1.0
|
|
46
47
|
|
|
@@ -20,7 +20,7 @@ simo/__pycache__/wsgi.cpython-38.pyc,sha256=Wt9kKkH2Sg5LRL4NrVQQDYPIoDyTvnXwm6jZ
|
|
|
20
20
|
simo/_hub_template/hub/asgi.py,sha256=ElN_fdeSkf0Ysa7pS9rJVmZ1HmLhFxb8jFaMLqe1220,126
|
|
21
21
|
simo/_hub_template/hub/celeryc.py,sha256=3ksDXftIZKJ4Cq9WNKJERdZdQlDEnjTQXycweRFmsSQ,27
|
|
22
22
|
simo/_hub_template/hub/manage.py,sha256=PNNlw3EVeIJDgkG0l-klqoxsKWfTYWG9jzRG0upmAaI,620
|
|
23
|
-
simo/_hub_template/hub/nginx.conf,sha256=
|
|
23
|
+
simo/_hub_template/hub/nginx.conf,sha256=MOJljsz_symwQF_L7ubp2ZnhkE7BrvkzIxZPtd1sWw0,2000
|
|
24
24
|
simo/_hub_template/hub/settings.py,sha256=4QhvhbtLRxHvAntwqG_qeAAtpDUqKvN4jzw9u3vqff8,361
|
|
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
|
|
@@ -34,7 +34,7 @@ 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=
|
|
37
|
+
simo/core/controllers.py,sha256=oxdl3a8cZvR-4_Z-TGUROz2tHjN-T-OuqC-Q4AGcljA,27199
|
|
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
|
|
@@ -48,7 +48,7 @@ simo/core/permissions.py,sha256=UmFjGPDWtAUbaWxJsWORb2q6BREHqndv9mkSIpnmdLk,1379
|
|
|
48
48
|
simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
|
|
49
49
|
simo/core/serializers.py,sha256=bkfXZgUzbXZOrJY69VIevBHNLWRd7DmgyFRh4arr-gs,15810
|
|
50
50
|
simo/core/signal_receivers.py,sha256=EZ8NSYZxUgSaLS16YZdK7T__l8dl0joMRllOxx5PUt4,2809
|
|
51
|
-
simo/core/socket_consumers.py,sha256=
|
|
51
|
+
simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
|
|
52
52
|
simo/core/storage.py,sha256=YlxmdRs-zhShWtFKgpJ0qp2NDBuIkJGYC1OJzqkbttQ,572
|
|
53
53
|
simo/core/tasks.py,sha256=se27V-noW02v4ZY2PMv0AJkXNsY3NtJ4G43__KLW7Kg,11005
|
|
54
54
|
simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
|
|
@@ -10110,7 +10110,7 @@ simo/core/utils/form_fields.py,sha256=UOzYdPd71qgCw1H3qH01u85YjrOlETPJAHOJrZKhyD
|
|
|
10110
10110
|
simo/core/utils/form_widgets.py,sha256=Zxn9jJqPle9Q_BKNJnyTDn7MosYwNp1TFu5LoKs0bfc,408
|
|
10111
10111
|
simo/core/utils/formsets.py,sha256=1u34QGZ2P67cxZD2uUJS3lAf--E8XsiiqFmZ4P41Vw4,6463
|
|
10112
10112
|
simo/core/utils/helpers.py,sha256=TOWy3slspaEYEhe9zDcb0RgzHUYslF6LZDlrWPGSqUI,3791
|
|
10113
|
-
simo/core/utils/logs.py,sha256=
|
|
10113
|
+
simo/core/utils/logs.py,sha256=Zn9JQxqCH9Odx2J1BWT84nFCfkJ4Z4p5X8psdll7hNc,2366
|
|
10114
10114
|
simo/core/utils/mixins.py,sha256=X6kUPKAi_F-uw7tgm8LEaYalBXpvDA-yrLNFCGr2rks,259
|
|
10115
10115
|
simo/core/utils/model_helpers.py,sha256=3IzJeOvBoYdUJVXCJkY20npOZXPjNPAiEFvuT0OPhwA,884
|
|
10116
10116
|
simo/core/utils/relay.py,sha256=i1xy_nPTgY5Xn0l2W4lNI3xeVUpDQTUUfV3M8h2DeBg,457
|
|
@@ -10125,13 +10125,13 @@ simo/fleet/api.py,sha256=Hxn84xI-Q77HxjINgRbjSJQOv9jii4OL20LxK0VSrS8,2499
|
|
|
10125
10125
|
simo/fleet/auto_urls.py,sha256=gAXTWUvsWkQHRdZGM_W_5iJBEsM4lY063kIx3f5LUqs,578
|
|
10126
10126
|
simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
|
|
10127
10127
|
simo/fleet/controllers.py,sha256=N8Qzdp2RPFrpZ_l9O4u8VjHWoY_WTWGg76s3V3oJqEs,13999
|
|
10128
|
-
simo/fleet/forms.py,sha256=
|
|
10128
|
+
simo/fleet/forms.py,sha256=HpvcdFyMl9dLNx1sEOkAkXOkYht6ku2HwWWga-PJzZQ,35067
|
|
10129
10129
|
simo/fleet/gateways.py,sha256=xFsmF_SXYXK_kMJOCHkiInPJ_0VcPWz-kJDoMup2lT8,1576
|
|
10130
10130
|
simo/fleet/managers.py,sha256=kpfvvfdH4LDxddIBDpdAb5gsVk8Gb0-L9biFcj9OFPs,807
|
|
10131
|
-
simo/fleet/models.py,sha256=
|
|
10131
|
+
simo/fleet/models.py,sha256=MldGstAZf5k0T_QE2qZEyp-64LhUG8Dqiy22_HptwH0,11779
|
|
10132
10132
|
simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
|
|
10133
10133
|
simo/fleet/serializers.py,sha256=zEpXAXxjk4Rf1JhlNnLTrs20qJggqjvIySbeHVo4Tt4,1505
|
|
10134
|
-
simo/fleet/socket_consumers.py,sha256=
|
|
10134
|
+
simo/fleet/socket_consumers.py,sha256=xNeR1IuaBTiHO2GEXwB1_4CJ29uMlqBycIUdxGT96E8,19578
|
|
10135
10135
|
simo/fleet/utils.py,sha256=D0EGFbDmW8zyhyxf5ozGtRpo4Sy5Ov6ZixukBK_e2Do,3462
|
|
10136
10136
|
simo/fleet/views.py,sha256=PbdZpsM_7-oyKzuDX1A5WULNABA1_B7ISF70UJX97FE,1662
|
|
10137
10137
|
simo/fleet/__pycache__/__init__.cpython-38.pyc,sha256=pIZE7EL6-cuJ3pQtaSwjKLrKLsTYelp1k9sRhXKLh6s,159
|
|
@@ -10343,8 +10343,8 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
10343
10343
|
simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10344
10344
|
simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10345
10345
|
simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10346
|
-
simo-2.0.
|
|
10347
|
-
simo-2.0.
|
|
10348
|
-
simo-2.0.
|
|
10349
|
-
simo-2.0.
|
|
10350
|
-
simo-2.0.
|
|
10346
|
+
simo-2.0.4.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
10347
|
+
simo-2.0.4.dist-info/METADATA,sha256=jFNjSQgwnq0CvLKeo5qrAgzbGkeytZt7Em6JVT7WGJM,1699
|
|
10348
|
+
simo-2.0.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
10349
|
+
simo-2.0.4.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
|
|
10350
|
+
simo-2.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|