Browse Source

Initial Version with very limited functions

tags/v1.0.0
Dirk Alders 2 years ago
parent
commit
e702960e4d
11 changed files with 700 additions and 21 deletions
  1. 38
    21
      .gitignore
  2. 6
    0
      .gitmodules
  3. 11
    0
      .vscode/settings.json
  4. 41
    0
      __install__.py
  5. 461
    0
      devices/__init__.py
  6. 19
    0
      function/__init__.py
  7. 24
    0
      function/first_floor_dining.py
  8. 1
    0
      mqtt
  9. 1
    0
      report
  10. 94
    0
      smart_brain.py
  11. 4
    0
      smart_brain.sh

+ 38
- 21
.gitignore View File

@@ -1,3 +1,41 @@
1
+config.py
2
+
3
+# ---> Linux
4
+*~
5
+
6
+# temporary files which can be created if a process still has a handle open of a deleted file
7
+.fuse_hidden*
8
+
9
+# KDE directory preferences
10
+.directory
11
+
12
+# Linux trash folder which might appear on any partition or disk
13
+.Trash-*
14
+
15
+# .nfs files are created when an open file is removed but is still being accessed
16
+.nfs*
17
+
18
+# ---> Backup
19
+*.bak
20
+*.gho
21
+*.ori
22
+*.orig
23
+*.tmp
24
+
25
+# ---> VirtualEnv
26
+# Virtualenv
27
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
28
+.Python
29
+[Bb]in
30
+[Ii]nclude
31
+[Ll]ib
32
+[Ll]ib64
33
+[Ll]ocal
34
+[Ss]cripts
35
+pyvenv.cfg
36
+.venv
37
+pip-selfcheck.json
38
+
1 39
 # ---> Python
2 40
 # Byte-compiled / optimized / DLL files
3 41
 __pycache__/
@@ -114,24 +152,3 @@ dmypy.json
114 152
 # Pyre type checker
115 153
 .pyre/
116 154
 
117
-# ---> Backup
118
-*.bak
119
-*.gho
120
-*.ori
121
-*.orig
122
-*.tmp
123
-
124
-# ---> VirtualEnv
125
-# Virtualenv
126
-# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
127
-.Python
128
-[Bb]in
129
-[Ii]nclude
130
-[Ll]ib
131
-[Ll]ib64
132
-[Ll]ocal
133
-[Ss]cripts
134
-pyvenv.cfg
135
-.venv
136
-pip-selfcheck.json
137
-

+ 6
- 0
.gitmodules View File

@@ -0,0 +1,6 @@
1
+[submodule "mqtt"]
2
+	path = mqtt
3
+	url = https://git.mount-mockery.de/pylib/mqtt.git
4
+[submodule "report"]
5
+	path = report
6
+	url = https://git.mount-mockery.de/pylib/report.git

+ 11
- 0
.vscode/settings.json View File

@@ -0,0 +1,11 @@
1
+{
2
+    "python.defaultInterpreterPath": "./venv/bin/python",
3
+    "editor.formatOnSave": true,
4
+    "autopep8.args": [
5
+        "--max-line-length=120"
6
+    ],
7
+    "editor.fontSize": 14,
8
+    "emmet.includeLanguages": {
9
+        "django-html": "html"
10
+    }
11
+}

+ 41
- 0
__install__.py View File

@@ -0,0 +1,41 @@
1
+#!/bin/python
2
+#
3
+import os
4
+import sys
5
+
6
+SERVICE_FILE = """
7
+[Unit]
8
+Description=Smarthome Ambient Information Service
9
+After=network-online.target
10
+Wants=network-online.target
11
+[Service]
12
+User=%(UID)d
13
+Group=%(GID)d
14
+ExecStart=%(MY_PATH)s/smart_brain.sh
15
+Type=simple
16
+[Install]
17
+WantedBy=default.target
18
+"""
19
+
20
+
21
+def help():
22
+    print("Usage: prog <UID> <GID> <TARGET_PATH>")
23
+
24
+if __name__ == "__main__":
25
+    if len(sys.argv) == 4:
26
+        try:
27
+            uid = int(sys.argv[1])
28
+            gid = int(sys.argv[2])
29
+        except ValueError:
30
+            help()
31
+        else:
32
+            if os.path.isdir(sys.argv[3]):
33
+                with open(os.path.join(sys.argv[3], 'smart_brain.service'), "w") as fh:
34
+                    fh.write(SERVICE_FILE % {
35
+                        "MY_PATH": os.path.dirname(os.path.abspath(__file__)),
36
+                        "UID": uid,
37
+                        "GID": gid})
38
+            else:
39
+                help()
40
+    else:
41
+        help()

+ 461
- 0
devices/__init__.py View File

@@ -0,0 +1,461 @@
1
+#!/usr/bin/env python
2
+# -*- coding: utf-8 -*-
3
+#
4
+"""
5
+devices (DEVICES)
6
+===========
7
+
8
+**Author:**
9
+
10
+* Dirk Alders <sudo-dirk@mount-mockery.de>
11
+
12
+**Description:**
13
+
14
+    This Module supports smarthome devices
15
+
16
+**Submodules:**
17
+
18
+* :mod:`shelly`
19
+* :mod:`silvercrest_powerplug`
20
+
21
+**Unittest:**
22
+
23
+        See also the :download:`unittest <devices/_testresults_/unittest.pdf>` documentation.
24
+
25
+**Module Documentation:**
26
+
27
+"""
28
+
29
+__DEPENDENCIES__ = []
30
+
31
+import json
32
+import logging
33
+
34
+try:
35
+    from config import APP_NAME as ROOT_LOGGER_NAME
36
+except ImportError:
37
+    ROOT_LOGGER_NAME = 'root'
38
+logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
39
+
40
+BATTERY_WARN_LEVEL = 5
41
+
42
+
43
+def is_json(data):
44
+    try:
45
+        json.loads(data)
46
+    except json.decoder.JSONDecodeError:
47
+        return False
48
+    else:
49
+        return True
50
+
51
+
52
+class base(dict):
53
+    TX_TOPIC = None
54
+    TX_VALUE = 0
55
+    TX_DICT = 1
56
+    TX_TYPE = -1
57
+    TX_FILTER_DATA_KEYS = []
58
+    #
59
+    RX_LOG_INFO_ALWAYS_KEYS = []
60
+    RX_KEYS = []
61
+    RX_IGNORE_TOPICS = []
62
+    RX_IGNORE_KEYS = []
63
+    RX_FILTER_DATA_KEYS = []
64
+
65
+    def __init__(self, mqtt_client, topic):
66
+        # data storage
67
+        self.mqtt_client = mqtt_client
68
+        self.topic = topic
69
+        # initialisations
70
+        dict.__init__(self)
71
+        mqtt_client.add_callback(
72
+            topic=self.topic, callback=self.receive_callback)
73
+        mqtt_client.add_callback(
74
+            topic=self.topic+"/#", callback=self.receive_callback)
75
+        #
76
+        self.callback_list = []
77
+        self.warning_callback = None
78
+
79
+    def receive_callback(self, client, userdata, message):
80
+        self.unpack(message)
81
+
82
+    def unpack_filter(self, key):
83
+        if key in self.RX_FILTER_DATA_KEYS:
84
+            if self.get(key) == 1 or self.get(key) == 'on' or self.get(key) == 'ON':
85
+                self[key] = True
86
+            elif self.get(key) == 0 or self.get(key) == 'off' or self.get(key) == 'OFF':
87
+                self[key] = False
88
+
89
+    def unpack_single_value(self, key, data):
90
+        prev_value = self.get(key)
91
+        if key in self.RX_KEYS:
92
+            self[key] = data
93
+            # Filter, if needed
94
+            self.unpack_filter(key)
95
+            logger.log(logging.INFO if key in self.RX_LOG_INFO_ALWAYS_KEYS or prev_value != self.get(key) else logging.DEBUG,
96
+                       "Received data for (%s) %s - %s", self.topic, key, str(self.get(key)))
97
+            self.callback_caller(key, self[key])
98
+        elif key not in self.RX_IGNORE_KEYS:
99
+            logger.warning('Got a message with unparsed content "%s"', key)
100
+        else:
101
+            logger.debug("Ignoring key %s", key)
102
+
103
+    def unpack(self, message):
104
+        content_key = message.topic[len(self.topic) + 1:]
105
+        if content_key not in self.RX_IGNORE_TOPICS:
106
+            logger.debug("Unpacking content_key \"%s\" from message.", content_key)
107
+            if is_json(message.payload):
108
+                data = json.loads(message.payload)
109
+                if type(data) is dict:
110
+                    for key in data:
111
+                        self.unpack_single_value(key, data[key])
112
+                else:
113
+                    self.unpack_single_value(content_key, data)
114
+            # String
115
+            else:
116
+                self.unpack_single_value(
117
+                    content_key, message.payload.decode('utf-8'))
118
+            self.warning_caller()
119
+        else:
120
+            logger.debug("Ignoring topic %s", content_key)
121
+
122
+    def pack_filter(self, key, data):
123
+        if key in self.TX_FILTER_DATA_KEYS:
124
+            if data is True:
125
+                return "on"
126
+            elif data is False:
127
+                return "off"
128
+            else:
129
+                return data
130
+        return data
131
+
132
+    def pack(self, key, data):
133
+        data = self.pack_filter(key, data)
134
+        if self.TX_TOPIC is not None:
135
+            if self.TX_TYPE < 0:
136
+                logger.error(
137
+                    "Unknown tx type. Set TX_TYPE of class to a known value")
138
+            else:
139
+                if self.TX_TYPE == self.TX_DICT:
140
+                    self.mqtt_client.send('/'.join([self.topic, self.TX_TOPIC]), json.dumps({key: data}))
141
+                else:
142
+                    if type(data) not in [str, bytes]:
143
+                        data = json.dumps(data)
144
+                    self.mqtt_client.send('/'.join([self.topic, key, self.TX_TOPIC]), data)
145
+        else:
146
+            logger.error(
147
+                "Unknown tx toptic. Set TX_TOPIC of class to a known value")
148
+
149
+    def add_callback(self, key, data, callback):
150
+        """
151
+        key: key or None for all keys
152
+        data: data or None for all data
153
+        """
154
+        cb_tup = (key, data, callback)
155
+        if cb_tup not in self.callback_list:
156
+            self.callback_list.append(cb_tup)
157
+
158
+    def add_warning_callback(self, callback):
159
+        self.warning_callback = callback
160
+
161
+    def warning_call_condition(self):
162
+        return False
163
+
164
+    def callback_caller(self, key, data):
165
+        for cb_key, cb_data, callback in self.callback_list:
166
+            if (cb_key == key or cb_key is None) and (cb_data == data or cb_data is None):
167
+                callback(self, key, data)
168
+
169
+    def warning_caller(self):
170
+        if self.warning_call_condition():
171
+            warn_txt = self.warning_text()
172
+            logger.warning(warn_txt)
173
+            if self.warning_callback is not None:
174
+                self.warning_callback(self, warn_txt)
175
+
176
+    def warning_text(self, data):
177
+        return "default warning text - replace parent warning_text function"
178
+
179
+
180
+class shelly(base):
181
+    KEY_OUTPUT_0 = "relay/0"
182
+    KEY_OUTPUT_1 = "relay/1"
183
+    KEY_INPUT_0 = "input/0"
184
+    KEY_INPUT_1 = "input/1"
185
+    KEY_TEMPERATURE = "temperature"
186
+    KEY_OVERTEMPERATURE = "overtemperature"
187
+    #
188
+    TX_TOPIC = 'command'
189
+    TX_TYPE = base.TX_VALUE
190
+    TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1]
191
+    #
192
+    RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_INPUT_0,
193
+               KEY_INPUT_1, KEY_OVERTEMPERATURE, KEY_TEMPERATURE]
194
+    RX_IGNORE_TOPICS = [KEY_OUTPUT_0 + '/' + TX_TOPIC, KEY_OUTPUT_1 + '/' + TX_TOPIC,
195
+                        KEY_OUTPUT_0 + '/' + "energy", KEY_OUTPUT_1 + '/' + "energy"]
196
+    RX_IGNORE_KEYS = ['temperature_f']
197
+    RX_FILTER_DATA_KEYS = [KEY_INPUT_0, KEY_INPUT_1,
198
+                           KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OVERTEMPERATURE]
199
+
200
+    def __init__(self, mqtt_client, topic):
201
+        super().__init__(mqtt_client, topic)
202
+
203
+    #
204
+    # WARNING CALL
205
+    #
206
+    def warning_call_condition(self):
207
+        return self.get(self.KEY_OVERTEMPERATURE)
208
+
209
+    def warning_text(self):
210
+        if self.overtemperature:
211
+            if self.temperature is not None:
212
+                return "Overtemperature detected for %s. Temperature was %.1f°C." % (self.topic, self.temperature)
213
+            else:
214
+                return "Overtemperature detected for %s." % self.topic
215
+
216
+    #
217
+    # RX
218
+    #
219
+    @property
220
+    def output_0(self):
221
+        """rv: [True, False]"""
222
+        return self.get(self.KEY_OUTPUT_0)
223
+
224
+    @property
225
+    def output_1(self):
226
+        """rv: [True, False]"""
227
+        return self.get(self.KEY_OUTPUT_1)
228
+
229
+    @property
230
+    def input_0(self):
231
+        """rv: [True, False]"""
232
+        return self.get(self.KEY_INPUT_0)
233
+
234
+    @property
235
+    def input_1(self):
236
+        """rv: [True, False]"""
237
+        return self.get(self.KEY_INPUT_1)
238
+
239
+    @property
240
+    def temperature(self):
241
+        """rv: numeric value"""
242
+        return self.get(self.KEY_TEMPERATURE)
243
+
244
+    #
245
+    # TX
246
+    #
247
+    def set_output_0(self, state):
248
+        """state: [True, False, 'toggle']"""
249
+        self.pack(self.KEY_OUTPUT_0, state)
250
+
251
+    def set_output_1(self, state):
252
+        """state: [True, False, 'toggle']"""
253
+        self.pack(self.KEY_OUTPUT_1, state)
254
+
255
+
256
+class silvercrest_powerplug(base):
257
+    KEY_LINKQUALITY = "linkquality"
258
+    KEY_OUTPUT_0 = "state"
259
+    #
260
+    TX_TOPIC = 'set'
261
+    TX_TYPE = base.TX_DICT
262
+    TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0]
263
+    #
264
+    RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0]
265
+    RX_IGNORE_TOPICS = [TX_TOPIC]
266
+    RX_IGNORE_KEYS = []
267
+    RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0]
268
+
269
+    def __init__(self, mqtt_client, topic):
270
+        super().__init__(mqtt_client, topic)
271
+
272
+    #
273
+    # RX
274
+    #
275
+    @property
276
+    def output_0(self):
277
+        """rv: [True, False]"""
278
+        return self.get(self.KEY_OUTPUT_0)
279
+
280
+    @property
281
+    def linkquality(self):
282
+        """rv: numeric value"""
283
+        return self.get(self.KEY_LINKQUALITY)
284
+
285
+    #
286
+    # TX
287
+    #
288
+    def set_output_0(self, state):
289
+        """state: [True, False, 'toggle']"""
290
+        self.pack(self.KEY_OUTPUT_0, state)
291
+
292
+
293
+class my_powerplug(base):
294
+    KEY_OUTPUT_0 = "output/1"
295
+    KEY_OUTPUT_1 = "output/2"
296
+    KEY_OUTPUT_2 = "output/3"
297
+    KEY_OUTPUT_3 = "output/4"
298
+    KEY_OUTPUT_ALL = "output/all"
299
+    #
300
+    TX_TOPIC = 'set'
301
+    TX_TYPE = base.TX_VALUE
302
+    #
303
+    RX_KEYS = [KEY_OUTPUT_0, KEY_OUTPUT_1, KEY_OUTPUT_2, KEY_OUTPUT_3]
304
+    RX_IGNORE_TOPICS = [KEY_OUTPUT_0 + "/" + TX_TOPIC, KEY_OUTPUT_1 + "/" + TX_TOPIC,
305
+                        KEY_OUTPUT_2 + "/" + TX_TOPIC, KEY_OUTPUT_3 + "/" + TX_TOPIC]
306
+    RX_IGNORE_KEYS = []
307
+    RX_FILTER_DATA_KEYS = []
308
+
309
+    def __init__(self, mqtt_client, topic):
310
+        super().__init__(mqtt_client, topic)
311
+
312
+    #
313
+    # RX
314
+    #
315
+    @property
316
+    def output_0(self):
317
+        """rv: [True, False]"""
318
+        return self.get(self.KEY_OUTPUT_0)
319
+
320
+    @property
321
+    def output_1(self):
322
+        """rv: [True, False]"""
323
+        return self.get(self.KEY_OUTPUT_1)
324
+
325
+    @property
326
+    def output_2(self):
327
+        """rv: [True, False]"""
328
+        return self.get(self.KEY_OUTPUT_2)
329
+
330
+    @property
331
+    def output_3(self):
332
+        """rv: [True, False]"""
333
+        return self.get(self.KEY_OUTPUT_3)
334
+
335
+    #
336
+    # TX
337
+    #
338
+    def set_output_0(self, state):
339
+        """state: [True, False, 'toggle']"""
340
+        self.pack(self.KEY_OUTPUT_0, state)
341
+
342
+    def set_output_1(self, state):
343
+        """state: [True, False, 'toggle']"""
344
+        self.pack(self.KEY_OUTPUT_1, state)
345
+
346
+    def set_output_2(self, state):
347
+        """state: [True, False, 'toggle']"""
348
+        self.pack(self.KEY_OUTPUT_2, state)
349
+
350
+    def set_output_3(self, state):
351
+        """state: [True, False, 'toggle']"""
352
+        self.pack(self.KEY_OUTPUT_3, state)
353
+
354
+    def set_output_all(self, state):
355
+        """state: [True, False, 'toggle']"""
356
+        self.pack(self.KEY_OUTPUT_ALL, state)
357
+
358
+
359
+class tradfri_light(base):
360
+    KEY_LINKQUALITY = "linkquality"
361
+    KEY_OUTPUT_0 = "state"
362
+    KEY_BRIGHTNESS = "brightness"
363
+    KEY_COLOR_TEMP = "color_temp"
364
+    #
365
+    TX_TOPIC = 'set'
366
+    TX_TYPE = base.TX_DICT
367
+    TX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
368
+    #
369
+    RX_KEYS = [KEY_LINKQUALITY, KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
370
+    RX_IGNORE_TOPICS = [TX_TOPIC]
371
+    RX_IGNORE_KEYS = ['update', 'color_mode']
372
+    RX_FILTER_DATA_KEYS = [KEY_OUTPUT_0, KEY_BRIGHTNESS, KEY_COLOR_TEMP]
373
+
374
+    def __init__(self, mqtt_client, topic):
375
+        super().__init__(mqtt_client, topic)
376
+
377
+    def unpack_filter(self, key):
378
+        if key == self.KEY_BRIGHTNESS:
379
+            self[key] = self[key] * 100 / 256
380
+        elif key == self.KEY_COLOR_TEMP:
381
+            self[key] = (self[key] - 250) * 100 / 204
382
+        else:
383
+            super().unpack_filter(key)
384
+
385
+    def pack_filter(self, key, data):
386
+        if key == self.KEY_BRIGHTNESS:
387
+            return data * 256 / 100
388
+        elif key == self.KEY_COLOR_TEMP:
389
+            return data * 204 / 100 + 250
390
+        else:
391
+            return super().pack_filter(key, data)
392
+
393
+    #
394
+    # RX
395
+    #
396
+    @property
397
+    def output_0(self):
398
+        """rv: [True, False]"""
399
+        return self.get(self.KEY_OUTPUT_0)
400
+
401
+    @property
402
+    def linkquality(self):
403
+        """rv: numeric value"""
404
+        return self.get(self.KEY_LINKQUALITY)
405
+
406
+    @property
407
+    def brightness(self):
408
+        """rv: numeric value [0%, ..., 100%"""
409
+        return self.get(self.KEY_BRIGHTNESS)
410
+
411
+    @property
412
+    def color_temp(self):
413
+        """rv: numeric value [0%, ..., 100%"""
414
+        return self.get(self.KEY_COLOR_TEMP)
415
+
416
+    #
417
+    # TX
418
+    #
419
+    def set_output_0(self, state):
420
+        """state: [True, False, 'toggle']"""
421
+        self.pack(self.KEY_OUTPUT_0, state)
422
+
423
+    def set_brightness(self, brightness):
424
+        """brightness: [0, ..., 100]"""
425
+        self.pack(self.KEY_BRIGHTNESS, brightness)
426
+
427
+    def set_color_temp(self, color_temp):
428
+        """color_temp: [0, ..., 100]"""
429
+        self.pack(self.KEY_COLOR_TEMP, color_temp)
430
+
431
+
432
+class tradfri_button(base):
433
+    KEY_LINKQUALITY = "linkquality"
434
+    KEY_BATTERY = "battery"
435
+    KEY_ACTION = "action"
436
+    #
437
+    RX_LOG_INFO_ALWAYS_KEYS = [KEY_ACTION]
438
+    RX_KEYS = [KEY_LINKQUALITY, KEY_BATTERY, KEY_ACTION]
439
+    RX_IGNORE_TOPICS = []
440
+    RX_IGNORE_KEYS = ['update']
441
+    RX_FILTER_DATA_KEYS = []
442
+
443
+    def __init__(self, mqtt_client, topic):
444
+        super().__init__(mqtt_client, topic)
445
+
446
+    #
447
+    # RX
448
+    #
449
+    @property
450
+    def action(self):
451
+        """rv: action_txt"""
452
+        return self.get(self.KEY_ACTION)
453
+
454
+    #
455
+    # WARNING CALL
456
+    #
457
+    def warning_call_condition(self):
458
+        return self.get(self.KEY_BATTERY) <= BATTERY_WARN_LEVEL
459
+
460
+    def warning_text(self):
461
+        return "Low battery level detected for %s. Battery level was %.0f%%." % (self.topic, self.get(self.KEY_BATTERY))

+ 19
- 0
function/__init__.py View File

@@ -0,0 +1,19 @@
1
+#!/usr/bin/env python
2
+# -*- coding: utf-8 -*-
3
+#
4
+import logging
5
+
6
+__all__ = ['all_functions', 'first_floor_dining']
7
+
8
+from . import first_floor_dining
9
+
10
+try:
11
+    from config import APP_NAME as ROOT_LOGGER_NAME
12
+except ImportError:
13
+    ROOT_LOGGER_NAME = 'root'
14
+logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
15
+
16
+
17
+class all_functions(object):
18
+    def __init__(self, device_collection):
19
+        first_floor_dining.room_function(device_collection)

+ 24
- 0
function/first_floor_dining.py View File

@@ -0,0 +1,24 @@
1
+import devices
2
+import logging
3
+
4
+try:
5
+    from config import APP_NAME as ROOT_LOGGER_NAME
6
+except ImportError:
7
+    ROOT_LOGGER_NAME = 'root'
8
+logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
9
+
10
+
11
+class room_function(object):
12
+    def __init__(self, device_collection):
13
+        self.main_light_shelly = device_collection.shellies.dinigroom
14
+        self.floorlamp_powerplug = device_collection.powerplugs.dining_floorlamp
15
+        #
16
+        self.main_light_shelly.add_callback(devices.shelly.KEY_OUTPUT_0, None, self.main_light_shelly_callback)
17
+        #
18
+        self.main_light_shelly_last = None
19
+
20
+    def main_light_shelly_callback(self, device, key, data):
21
+        if data != self.main_light_shelly_last:
22
+            logger.info("Test")
23
+            self.floorlamp_powerplug.set_output_0(data)
24
+        self.main_light_shelly_last

+ 1
- 0
mqtt

@@ -0,0 +1 @@
1
+Subproject commit 1921bc619a9c4af682a7707d6fe58069478c59cd

+ 1
- 0
report

@@ -0,0 +1 @@
1
+Subproject commit e2392c9f28d88ee54463681850acf95ae496c9a0

+ 94
- 0
smart_brain.py View File

@@ -0,0 +1,94 @@
1
+import config
2
+import devices
3
+import function
4
+import inspect
5
+import logging
6
+import mqtt
7
+import os
8
+import report
9
+import time
10
+
11
+logger = logging.getLogger(config.APP_NAME)
12
+
13
+
14
+class shellies(object):
15
+    def __init__(self, mc):
16
+        self.dinigroom = devices.shelly(mc, topic="shellies/diningroom")            # http://shelly1l-84CCA8ADD055
17
+        self.sleep_madi = devices.shelly(mc, topic="shellies/sleep_madi")           # http://shelly1l-E8DB84A254C7
18
+        # self._ = devices.shelly(mc, topic="")            # http://
19
+        # self._ = devices.shelly(mc, topic="")            # http://
20
+        # self._ = devices.shelly(mc, topic="")            # http://
21
+        # self._ = devices.shelly(mc, topic="")            # http://
22
+        # self._ = devices.shelly(mc, topic="")            # http://
23
+        # self._ = devices.shelly(mc, topic="")            # http://
24
+        # self._ = devices.shelly(mc, topic="")            # http://
25
+
26
+
27
+class powerplugs(object):
28
+    def __init__(self, mc):
29
+        self.dining_floorlamp = devices.silvercrest_powerplug(mc, "zigbee_og_e/powerplug/dining_floorlamp")
30
+        self.aux = devices.silvercrest_powerplug(mc, topic="zigbee_og_e/powerplug/aux")
31
+        self.dirk = devices.my_powerplug(mc, "powerplug/dirk")
32
+
33
+
34
+class lights(object):
35
+    def __init__(self, mc):
36
+        self.sleep_madi = devices.tradfri_light(mc, topic="zigbee_og_e/light/sleep_madi")
37
+        self.sleep_bed_di = devices.tradfri_light(mc, topic="zigbee_og_e/light/sleep_bed_di")
38
+        # self._ = devices.tradfri_light(mc, topic="")
39
+        # self._ = devices.tradfri_light(mc, topic="")
40
+        # self._ = devices.tradfri_light(mc, topic="")
41
+        # self._ = devices.tradfri_light(mc, topic="")
42
+        # self._ = devices.tradfri_light(mc, topic="")
43
+        # self._ = devices.tradfri_light(mc, topic="")
44
+        # self._ = devices.tradfri_light(mc, topic="")
45
+        # self._ = devices.tradfri_light(mc, topic="")
46
+        # self._ = devices.tradfri_light(mc, topic="")
47
+
48
+
49
+class input_devices(object):
50
+    def __init__(self, mc):
51
+        self.og_east = devices.tradfri_button(mc, topic="zigbee_og_e/input_device/og_east")
52
+
53
+
54
+class all_devices(object):
55
+    def __init__(self, mc):
56
+        self.shellies = shellies(mc)
57
+        self.powerplugs = powerplugs(mc)
58
+        self.lights = lights(mc)
59
+        self.input_devices = input_devices(mc)
60
+
61
+    def devicelist(self):
62
+        rv = []
63
+        for name, obj in inspect.getmembers(self):
64
+            if not name.startswith('_') and name != inspect.stack()[0][3]:
65
+                for devicename, deviceobj in inspect.getmembers(obj):
66
+                    if not devicename.startswith('_'):
67
+                        rv.append(deviceobj)
68
+        return rv
69
+
70
+
71
+if __name__ == "__main__":
72
+    if config.DEBUG:
73
+        report.stdoutLoggingConfigure(([config.APP_NAME, config.DEBUGLEVEL], ), report.LONG_FMT)
74
+    else:
75
+        report.stdoutLoggingConfigure(((config.APP_NAME, logging.INFO),
76
+                                      (config.APP_NAME+'.devices', logging.WARNING)), report.SHORT_FMT)
77
+    #
78
+    mc = mqtt.mqtt_client(host=config.MQTT_SERVER, port=config.MQTT_PORT,
79
+                          username=config.MQTT_USER, password=config.MQTT_PASSWORD, name=config.APP_NAME)
80
+
81
+    ad = all_devices(mc)
82
+    func = function.all_functions(ad)
83
+
84
+    # def wcb(device, txt):
85
+    #     logger.warning("%s: %s", device.topic, txt)
86
+    # for device in ad.devicelist():
87
+    #     device.add_warning_callback(wcb)
88
+
89
+    # def cb(device, key, data):
90
+    #     print("Callback: %s::%s" % (key, str(data)))
91
+    # ad.shellies.dinigroom.add_callback(devices.shelly.KEY_OUTPUT_0, None, cb)
92
+
93
+    while (True):
94
+        time.sleep(1)

+ 4
- 0
smart_brain.sh View File

@@ -0,0 +1,4 @@
1
+#!/bin/sh
2
+#
3
+BASEPATH=`dirname $0`
4
+$BASEPATH/venv/bin/python $BASEPATH/smart_brain.py

Loading…
Cancel
Save