Browse Source

Integration of module devdi

master
Dirk Alders 1 year ago
parent
commit
0f429b2579
11 changed files with 138 additions and 61 deletions
  1. 2
    3
      .vscode/settings.json
  2. 1
    1
      devdi
  3. 15
    8
      devices/__init__.py
  4. 16
    8
      devices/base.py
  5. 14
    5
      devices/brennenstuhl.py
  6. 8
    3
      devices/livarno.py
  7. 36
    0
      devices/my.py
  8. 2
    1
      devices/shelly.py
  9. 5
    1
      devices/tradfri.py
  10. 34
    31
      home_emulation.py
  11. 5
    0
      home_emulation.sh

+ 2
- 3
.vscode/settings.json View File

1
 {
1
 {
2
   "python.defaultInterpreterPath": "./venv/bin/python",
2
   "python.defaultInterpreterPath": "./venv/bin/python",
3
   "autopep8.args": ["--max-line-length=150"],
3
   "autopep8.args": ["--max-line-length=150"],
4
-  "python.formatting.provider": "none",
5
   "[python]": {
4
   "[python]": {
6
-    "editor.defaultFormatter": "ms-python.python",
5
+    "python.formatting.provider": "none",
6
+    "editor.defaultFormatter": "ms-python.autopep8",
7
     "editor.formatOnSave": true
7
     "editor.formatOnSave": true
8
   },
8
   },
9
-  "editor.formatOnSave": true,
10
   "editor.fontSize": 14,
9
   "editor.fontSize": 14,
11
   "emmet.includeLanguages": { "django-html": "html" },
10
   "emmet.includeLanguages": { "django-html": "html" },
12
   "python.testing.pytestArgs": ["-v", "--cov", "--cov-report=xml", "__test__"],
11
   "python.testing.pytestArgs": ["-v", "--cov", "--cov-report=xml", "__test__"],

+ 1
- 1
devdi

1
-Subproject commit a5a55a158050fdb978f4e9c1f7d43c8e6aa83a1c
1
+Subproject commit 773d0a6679810b365bbd4537156c513b0f496c5a

+ 15
- 8
devices/__init__.py View File

1
+from devices.brennenstuhl import vlv as brennenstuhl_heatingvalve
2
+from devices.livarno import sw as silvercrest_powerplug
3
+from devices.livarno import sw_br_ct as livarno_sw_br_ct
4
+from devices.my import powerplug as my_powerplug
1
 from devices.shelly import shelly_sw1
5
 from devices.shelly import shelly_sw1
2
-
3
 from devices.tradfri import sw as tradfri_sw
6
 from devices.tradfri import sw as tradfri_sw
4
 from devices.tradfri import sw_br as tradfri_sw_br
7
 from devices.tradfri import sw_br as tradfri_sw_br
5
 from devices.tradfri import sw_br_ct as tradfri_sw_br_ct
8
 from devices.tradfri import sw_br_ct as tradfri_sw_br_ct
6
-tradfri_button = None
7
 
9
 
8
-from devices.livarno import sw_br_ct as livarno_sw_br_ct
9
-silvercrest_powerplug = None
10
+tradfri_button = None   # TODO: required, when a interface for external device stimulation is available
10
 silvercrest_motion_sensor = None
11
 silvercrest_motion_sensor = None
12
+audio_status = None
13
+remote = None
11
 
14
 
12
-from devices.brennenstuhl import vlv as brennenstuhl_heatingvalve
13
 
15
 
14
-my_powerplug = None
15
-audio_status = None
16
-remote = None
16
+class group(object):
17
+    def __init__(self, *args):
18
+        self.device_group = args
19
+        self.topic = self.device_group[0].topic
20
+
21
+    def power_on_action(self, *args, **kwargs):
22
+        for gm in self.device_group:
23
+            gm.power_on_action(*args, **kwargs)

+ 16
- 8
devices/base.py View File

1
 import logging
1
 import logging
2
 
2
 
3
+try:
4
+    from config import APP_NAME as ROOT_LOGGER_NAME
5
+except ImportError:
6
+    ROOT_LOGGER_NAME = 'root'
7
+
3
 
8
 
4
 class base(dict):
9
 class base(dict):
5
     """A base device for all devicetypes
10
     """A base device for all devicetypes
15
         self.mqtt_client = mqtt_client
20
         self.mqtt_client = mqtt_client
16
         self.topic = topic
21
         self.topic = topic
17
         #
22
         #
18
-        self.logger = logging.getLogger('devices')
23
+        self.logger = logging.getLogger(ROOT_LOGGER_NAME).getChild("devices")
19
         for entry in self.topic.split('/'):
24
         for entry in self.topic.split('/'):
20
             self.logger = self.logger.getChild(entry)
25
             self.logger = self.logger.getChild(entry)
21
         #
26
         #
22
-        self.__power_on_inst__ = []
27
+        self.__power_on_inst__ = {}
23
 
28
 
24
     def __set__(self, key, data):
29
     def __set__(self, key, data):
25
         if key in self.PROPERTIES:
30
         if key in self.PROPERTIES:
28
         else:
33
         else:
29
             self.logger.warning("Ignoring unsupported property %s", key)
34
             self.logger.warning("Ignoring unsupported property %s", key)
30
 
35
 
31
-    def power_on(self):
32
-        for i in self.__power_on_inst__:
36
+    def power_on(self, key):
37
+        for i in self.__power_on_inst__.get(key, []):
38
+            self.logger.info("Power on action for %s will be executed.", i.topic)
33
             i.power_on_action()
39
             i.power_on_action()
34
 
40
 
35
-    def register_power_on_instance(self, inst):
36
-        if inst not in self.__power_on_inst__:
37
-            self.__power_on_inst__.append(inst)
41
+    def register_power_on_instance(self, inst, key):
42
+        if key not in self.__power_on_inst__:
43
+            self.__power_on_inst__[key] = []
44
+        if inst not in self.__power_on_inst__[key]:
45
+            self.__power_on_inst__[key].append(inst)
38
 
46
 
39
     def power_on_action(self):
47
     def power_on_action(self):
40
-        pass
48
+        pass

+ 14
- 5
devices/brennenstuhl.py View File

28
 
28
 
29
 from devices.base import base
29
 from devices.base import base
30
 import json
30
 import json
31
+import task
31
 import time
32
 import time
32
 
33
 
33
 """ ANSWER of a device:
34
 """ ANSWER of a device:
78
         self["window_detection"] = "ON"
79
         self["window_detection"] = "ON"
79
         #
80
         #
80
         self.mqtt_client.add_callback(self.topic + '/set', self.__rx_set__)
81
         self.mqtt_client.add_callback(self.topic + '/set', self.__rx_set__)
82
+        #
83
+        self.tq = task.threaded_queue()
84
+        self.tq.run()
81
 
85
 
82
     def set_state(self, value):
86
     def set_state(self, value):
83
         self.__set__("state", "on" if value else "off")
87
         self.__set__("state", "on" if value else "off")
88
         self.logger.info("Received set data: %s", repr(data))
92
         self.logger.info("Received set data: %s", repr(data))
89
         for key in data:
93
         for key in data:
90
             self.__set__(key, data[key])
94
             self.__set__(key, data[key])
91
-        #time.sleep(1.5)
92
-        self.send_device_status()
95
+        self.tq.enqueue(1, self.send_device_status, data)
93
 
96
 
94
-    def send_device_status(self):
95
-        data = json.dumps(self)
97
+    def send_device_status(self, rt, data):
98
+        for i in range(0, 75):
99
+            time.sleep(0.01)
100
+            if self.tq.qsize() >= 3:
101
+                return
102
+        for key in self:
103
+            if key not in data:
104
+                data[key] = self[key]
96
         self.logger.info("Sending status: %s", repr(data))
105
         self.logger.info("Sending status: %s", repr(data))
97
-        self.mqtt_client.send(self.topic, data)
106
+        self.mqtt_client.send(self.topic, json.dumps(data))

+ 8
- 3
devices/livarno.py View File

1
-import devices.tradfri
1
+from devices.tradfri import sw as tradfri_sw
2
+from devices.tradfri import sw_br_ct as tradfri_sw_br_ct
2
 
3
 
3
 
4
 
4
-class sw_br_ct(devices.tradfri.sw_br_ct):
5
+class sw(tradfri_sw):
6
+    pass
7
+
8
+
9
+class sw_br_ct(tradfri_sw_br_ct):
5
     def set_state(self, value):
10
     def set_state(self, value):
6
         self.__set__("state", "on" if value else "off")
11
         self.__set__("state", "on" if value else "off")
7
 
12
 
8
     def power_on_action(self):
13
     def power_on_action(self):
9
-        pass
14
+        self["state"] = "on"

+ 36
- 0
devices/my.py View File

1
+#!/usr/bin/env python
2
+# -*- coding: utf-8 -*-
3
+#
4
+
5
+from devices.base import base
6
+
7
+
8
+class powerplug(base):
9
+    PROPERTIES = [
10
+        "output/1",
11
+        "output/2",
12
+        "output/3",
13
+        "output/4",
14
+    ]
15
+
16
+    def __init__(self, mqtt_client, topic):
17
+        super().__init__(mqtt_client, topic)
18
+        #
19
+        for i in range(0, 4):
20
+            self[self.PROPERTIES[i]] = False
21
+            self.mqtt_client.add_callback(self.topic + '/output/%d/set' % (i + 1), self.__rx_set__)
22
+
23
+    def __rx_set__(self, client, userdata, message):
24
+        data = message.payload.decode('utf-8')
25
+        key = message.topic.split('/')[-3] + '/' + message.topic.split('/')[-2]
26
+        self.logger.info("Received set data for %s: %s", key, repr(data))
27
+        self.__set__(key, data)
28
+        self.send_device_status(key)
29
+        if key.startswith("output/"):
30
+            if data == "true":
31
+                self.power_on(key)
32
+
33
+    def send_device_status(self, key):
34
+        data = self[key]
35
+        self.logger.info("Sending status for %s: %s", key, repr(data))
36
+        self.mqtt_client.send(self.topic + '/' + key, data)

+ 2
- 1
devices/shelly.py View File

46
     PROPERTIES = [
46
     PROPERTIES = [
47
         "relay/0",
47
         "relay/0",
48
     ]
48
     ]
49
+
49
     def __init__(self, mqtt_client, topic):
50
     def __init__(self, mqtt_client, topic):
50
         super().__init__(mqtt_client, topic)
51
         super().__init__(mqtt_client, topic)
51
         self["state"] = "off"
52
         self["state"] = "off"
62
         self.send_device_status(key)
63
         self.send_device_status(key)
63
         if key == "relay/0":
64
         if key == "relay/0":
64
             if data.lower() == "on":
65
             if data.lower() == "on":
65
-                self.power_on()
66
+                self.power_on(key)
66
                 if self.__auto_off__ is not None:
67
                 if self.__auto_off__ is not None:
67
                     self.__auto_off__.run()
68
                     self.__auto_off__.run()
68
             else:
69
             else:

+ 5
- 1
devices/tradfri.py View File

53
     PROPERTIES = [
53
     PROPERTIES = [
54
         "state",
54
         "state",
55
     ]
55
     ]
56
+
56
     def __init__(self, mqtt_client, topic):
57
     def __init__(self, mqtt_client, topic):
57
         super().__init__(mqtt_client, topic)
58
         super().__init__(mqtt_client, topic)
58
         self["state"] = "off"
59
         self["state"] = "off"
71
             self.__set__(key, data[key])
72
             self.__set__(key, data[key])
72
         self.send_device_status()
73
         self.send_device_status()
73
         if "state" in data and data.get("state", 'OFF').lower() == "on":
74
         if "state" in data and data.get("state", 'OFF').lower() == "on":
74
-            self.power_on()
75
+            self.power_on("state")
75
 
76
 
76
     def __rx_get__(self, client, userdata, message):
77
     def __rx_get__(self, client, userdata, message):
77
         self.send_device_status()
78
         self.send_device_status()
78
 
79
 
79
     def power_on_action(self):
80
     def power_on_action(self):
81
+        self["state"] = "on"
80
         self.send_device_status()
82
         self.send_device_status()
81
 
83
 
82
     def send_device_status(self):
84
     def send_device_status(self):
95
     PROPERTIES = sw.PROPERTIES + [
97
     PROPERTIES = sw.PROPERTIES + [
96
         "brightness",
98
         "brightness",
97
     ]
99
     ]
100
+
98
     def __init__(self, mqtt_client, topic):
101
     def __init__(self, mqtt_client, topic):
99
         super().__init__(mqtt_client, topic)
102
         super().__init__(mqtt_client, topic)
100
         self["brightness"] = 64
103
         self["brightness"] = 64
110
     PROPERTIES = sw_br.PROPERTIES + [
113
     PROPERTIES = sw_br.PROPERTIES + [
111
         "color_temp",
114
         "color_temp",
112
     ]
115
     ]
116
+
113
     def __init__(self, mqtt_client, topic):
117
     def __init__(self, mqtt_client, topic):
114
         super().__init__(mqtt_client, topic)
118
         super().__init__(mqtt_client, topic)
115
         self["color_temp"] = 413
119
         self["color_temp"] = 413

+ 34
- 31
home_emulation.py View File

1
 import config
1
 import config
2
 import devdi
2
 import devdi
3
 import devdi.props as props
3
 import devdi.props as props
4
-#import function
5
-#import json
6
 import logging
4
 import logging
7
 import mqtt
5
 import mqtt
8
 import os
6
 import os
9
 import report
7
 import report
10
-#import subprocess
11
 import time
8
 import time
12
 
9
 
10
+# TODO: Implementation of missing devices in devices/__init__.py
11
+# TODO: Implementation of interface for external device stimulation
12
+
13
 logger = logging.getLogger(config.APP_NAME)
13
 logger = logging.getLogger(config.APP_NAME)
14
 
14
 
15
 
15
 
30
                           password=config.MQTT_PASSWORD, name=config.APP_NAME)
30
                           password=config.MQTT_PASSWORD, name=config.APP_NAME)
31
 
31
 
32
     #
32
     #
33
-    # Smarthome Devices
33
+    # Smarthome physical Devices
34
     #
34
     #
35
-    ddi = devdi.devices(mc)
35
+    pd = devdi.physical_devices(mc)
36
 
36
 
37
     #
37
     #
38
     # Smart Home Functionality
38
     # Smart Home Functionality
43
     loc = props.LOC_GFW
43
     loc = props.LOC_GFW
44
     # DIRK
44
     # DIRK
45
     roo = props.ROO_DIR
45
     roo = props.ROO_DIR
46
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
47
-    tml = ddi.get(props.STG_ZGW, loc, roo, props.FUN_MAL)
48
-    sml.register_power_on_instance(tml)
46
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
47
+    tml = pd.get(props.STG_ZGW, loc, roo, props.FUN_MAL)
48
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
49
+
50
+    sml = pd.get(props.STG_MYA, loc, roo, props.FUN_MPP)
51
+    tml = pd.get(props.STG_ZGW, loc, roo, props.FUN_DEL)
52
+    sml.register_power_on_instance(tml, sml.PROPERTIES[1])
53
+
49
     # FLOOR
54
     # FLOOR
50
     roo = props.ROO_FLO
55
     roo = props.ROO_FLO
51
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
52
-    tml = ddi.get(props.STG_ZGW, loc, roo, props.FUN_MAL, 1)
53
-    sml.register_power_on_instance(tml)
54
-    tml = ddi.get(props.STG_ZGW, loc, roo, props.FUN_MAL, 2)
55
-    sml.register_power_on_instance(tml)
56
-    
56
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
57
+    tml = pd.get(props.STG_ZGW, loc, roo, props.FUN_MAL)
58
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
59
+
57
     #######
60
     #######
58
     # FFW #
61
     # FFW #
59
     #######
62
     #######
60
     loc = props.LOC_FFW
63
     loc = props.LOC_FFW
61
     # JULIAN
64
     # JULIAN
62
     roo = props.ROO_JUL
65
     roo = props.ROO_JUL
63
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
64
-    tml = ddi.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
65
-    sml.register_power_on_instance(tml)
66
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
67
+    tml = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
68
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
66
     # LIVINGROOM
69
     # LIVINGROOM
67
     roo = props.ROO_LIV
70
     roo = props.ROO_LIV
68
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
69
-    tml = ddi.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
70
-    sml.register_power_on_instance(tml)
71
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
72
+    tml = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
73
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
71
     # SLEEP
74
     # SLEEP
72
     roo = props.ROO_SLP
75
     roo = props.ROO_SLP
73
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
74
-    tml = ddi.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
75
-    sml.register_power_on_instance(tml)
76
-    
76
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
77
+    tml = pd.get(props.STG_ZFW, loc, roo, props.FUN_MAL)
78
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
79
+
77
     #######
80
     #######
78
     # FFE #
81
     # FFE #
79
     #######
82
     #######
80
     loc = props.LOC_FFE
83
     loc = props.LOC_FFE
81
     # KITCHEN
84
     # KITCHEN
82
     roo = props.ROO_KIT
85
     roo = props.ROO_KIT
83
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_CIR)
86
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_CIR)
84
     sml.auto_off(600)
87
     sml.auto_off(600)
85
     # LIVINGROOM
88
     # LIVINGROOM
86
     roo = props.ROO_LIV
89
     roo = props.ROO_LIV
87
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
88
-    tml = ddi.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
89
-    sml.register_power_on_instance(tml)
90
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
91
+    tml = pd.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
92
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
90
     # SLEEP
93
     # SLEEP
91
     roo = props.ROO_SLP
94
     roo = props.ROO_SLP
92
-    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
93
-    tml = ddi.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
94
-    sml.register_power_on_instance(tml)
95
+    sml = pd.get(props.STG_SHE, loc, roo, props.FUN_MAL)
96
+    tml = pd.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
97
+    sml.register_power_on_instance(tml, sml.PROPERTIES[0])
95
 
98
 
96
     while (True):
99
     while (True):
97
         time.sleep(1)
100
         time.sleep(1)

+ 5
- 0
home_emulation.sh View File

1
+#!/bin/sh
2
+#
3
+BASEPATH=`dirname $0`
4
+$BASEPATH/venv/bin/python $BASEPATH/home_emulation.py
5
+

Loading…
Cancel
Save