浏览代码

Integration of module devdi

master
Dirk Alders 1年前
父节点
当前提交
0f429b2579
共有 11 个文件被更改,包括 138 次插入61 次删除
  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 查看文件

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

+ 1
- 1
devdi

@@ -1 +1 @@
1
-Subproject commit a5a55a158050fdb978f4e9c1f7d43c8e6aa83a1c
1
+Subproject commit 773d0a6679810b365bbd4537156c513b0f496c5a

+ 15
- 8
devices/__init__.py 查看文件

@@ -1,16 +1,23 @@
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 5
 from devices.shelly import shelly_sw1
2
-
3 6
 from devices.tradfri import sw as tradfri_sw
4 7
 from devices.tradfri import sw_br as tradfri_sw_br
5 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 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 查看文件

@@ -1,5 +1,10 @@
1 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 9
 class base(dict):
5 10
     """A base device for all devicetypes
@@ -15,11 +20,11 @@ class base(dict):
15 20
         self.mqtt_client = mqtt_client
16 21
         self.topic = topic
17 22
         #
18
-        self.logger = logging.getLogger('devices')
23
+        self.logger = logging.getLogger(ROOT_LOGGER_NAME).getChild("devices")
19 24
         for entry in self.topic.split('/'):
20 25
             self.logger = self.logger.getChild(entry)
21 26
         #
22
-        self.__power_on_inst__ = []
27
+        self.__power_on_inst__ = {}
23 28
 
24 29
     def __set__(self, key, data):
25 30
         if key in self.PROPERTIES:
@@ -28,13 +33,16 @@ class base(dict):
28 33
         else:
29 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 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 47
     def power_on_action(self):
40
-        pass
48
+        pass

+ 14
- 5
devices/brennenstuhl.py 查看文件

@@ -28,6 +28,7 @@
28 28
 
29 29
 from devices.base import base
30 30
 import json
31
+import task
31 32
 import time
32 33
 
33 34
 """ ANSWER of a device:
@@ -78,6 +79,9 @@ class vlv(base):
78 79
         self["window_detection"] = "ON"
79 80
         #
80 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 86
     def set_state(self, value):
83 87
         self.__set__("state", "on" if value else "off")
@@ -88,10 +92,15 @@ class vlv(base):
88 92
         self.logger.info("Received set data: %s", repr(data))
89 93
         for key in data:
90 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 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 查看文件

@@ -1,9 +1,14 @@
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 10
     def set_state(self, value):
6 11
         self.__set__("state", "on" if value else "off")
7 12
 
8 13
     def power_on_action(self):
9
-        pass
14
+        self["state"] = "on"

+ 36
- 0
devices/my.py 查看文件

@@ -0,0 +1,36 @@
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 查看文件

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

+ 5
- 1
devices/tradfri.py 查看文件

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

+ 34
- 31
home_emulation.py 查看文件

@@ -1,15 +1,15 @@
1 1
 import config
2 2
 import devdi
3 3
 import devdi.props as props
4
-#import function
5
-#import json
6 4
 import logging
7 5
 import mqtt
8 6
 import os
9 7
 import report
10
-#import subprocess
11 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 13
 logger = logging.getLogger(config.APP_NAME)
14 14
 
15 15
 
@@ -30,9 +30,9 @@ if __name__ == "__main__":
30 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 38
     # Smart Home Functionality
@@ -43,55 +43,58 @@ if __name__ == "__main__":
43 43
     loc = props.LOC_GFW
44 44
     # DIRK
45 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 54
     # FLOOR
50 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 61
     # FFW #
59 62
     #######
60 63
     loc = props.LOC_FFW
61 64
     # JULIAN
62 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 69
     # LIVINGROOM
67 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 74
     # SLEEP
72 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 81
     # FFE #
79 82
     #######
80 83
     loc = props.LOC_FFE
81 84
     # KITCHEN
82 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 87
     sml.auto_off(600)
85 88
     # LIVINGROOM
86 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 93
     # SLEEP
91 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 99
     while (True):
97 100
         time.sleep(1)

+ 5
- 0
home_emulation.sh 查看文件

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

正在加载...
取消
保存