Selaa lähdekoodia

Device definition and initialisation module integrated

master
Dirk Alders 1 vuosi sitten
vanhempi
commit
0bb194dfd0
11 muutettua tiedostoa jossa 236 lisäystä ja 130 poistoa
  1. 3
    0
      .gitmodules
  2. 0
    1
      config.py
  3. 10
    0
      config.py
  4. 1
    0
      devdi
  5. 12
    19
      devices/__init__.py
  6. 14
    3
      devices/base.py
  7. 97
    0
      devices/brennenstuhl.py
  8. 3
    0
      devices/livarno.py
  9. 5
    8
      devices/shelly.py
  10. 11
    12
      devices/tradfri.py
  11. 80
    87
      home_emulation.py

+ 3
- 0
.gitmodules Näytä tiedosto

@@ -7,3 +7,6 @@
7 7
 [submodule "report"]
8 8
 	path = report
9 9
 	url = https://git.mount-mockery.de/pylib/report.git
10
+[submodule "devdi"]
11
+	path = devdi
12
+	url = https://git.mount-mockery.de/smarthome/smart_devdi.git

+ 0
- 1
config.py Näytä tiedosto

@@ -1 +0,0 @@
1
-../smart_brain/config.py

+ 10
- 0
config.py Näytä tiedosto

@@ -0,0 +1,10 @@
1
+DEBUG = True
2
+
3
+APP_NAME = "smart_homeemulation"
4
+
5
+MQTT_SERVER = "localhost"
6
+MQTT_PORT = 1883
7
+MQTT_USER = None
8
+MQTT_PASSWORD = None
9
+
10
+CHRISTMAS = True

+ 1
- 0
devdi

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

+ 12
- 19
devices/__init__.py Näytä tiedosto

@@ -1,23 +1,16 @@
1
-import devices.base
2
-import devices.livarno
3
-import devices.shelly
4
-import devices.tradfri
1
+from devices.shelly import shelly_sw1
5 2
 
3
+from devices.tradfri import sw as tradfri_sw
4
+from devices.tradfri import sw_br as tradfri_sw_br
5
+from devices.tradfri import sw_br_ct as tradfri_sw_br_ct
6
+tradfri_button = None
6 7
 
7
-class null(devices.base.base):
8
-    """A dummy device for not yet existing devicetypes
8
+from devices.livarno import sw_br_ct as livarno_sw_br_ct
9
+silvercrest_powerplug = None
10
+silvercrest_motion_sensor = None
9 11
 
10
-    Args:
11
-        mqtt_client (mqtt.mqtt_client): A MQTT Client instance
12
-        topic (str): the base topic for this device
13
-    """
14
-    def __init__(self, mqtt_client, topic, **kwargs):
15
-        super().__init__(mqtt_client, topic, **kwargs)
16
-        self.mqtt_client.add_callback(self.topic, self.__rx__)
17
-        self.mqtt_client.add_callback(self.topic + '/#', self.__rx__)
12
+from devices.brennenstuhl import vlv as brennenstuhl_heatingvalve
18 13
 
19
-    def __rx__(self, client, userdata, message):
20
-        self.logger.warning("Got messaqge for device with missing implementation: topic=%s, payload=%s", message.topic, repr(message.payload))
21
-
22
-    def set_state(self, value):
23
-        self.logger.warning("Got set_state call for device with missing implementation.")
14
+my_powerplug = None
15
+audio_status = None
16
+remote = None

+ 14
- 3
devices/base.py Näytä tiedosto

@@ -10,16 +10,16 @@ class base(dict):
10 10
     """
11 11
     PROPERTIES = []
12 12
 
13
-    def __init__(self, mqtt_client, topic, **kwargs):
13
+    def __init__(self, mqtt_client, topic):
14 14
         super().__init__()
15 15
         self.mqtt_client = mqtt_client
16 16
         self.topic = topic
17
-        for key in kwargs:
18
-            setattr(self, key, kwargs[key])
19 17
         #
20 18
         self.logger = logging.getLogger('devices')
21 19
         for entry in self.topic.split('/'):
22 20
             self.logger = self.logger.getChild(entry)
21
+        #
22
+        self.__power_on_inst__ = []
23 23
 
24 24
     def __set__(self, key, data):
25 25
         if key in self.PROPERTIES:
@@ -27,3 +27,14 @@ class base(dict):
27 27
             self[key] = data
28 28
         else:
29 29
             self.logger.warning("Ignoring unsupported property %s", key)
30
+
31
+    def power_on(self):
32
+        for i in self.__power_on_inst__:
33
+            i.power_on_action()
34
+
35
+    def register_power_on_instance(self, inst):
36
+        if inst not in self.__power_on_inst__:
37
+            self.__power_on_inst__.append(inst)
38
+
39
+    def power_on_action(self):
40
+        pass

+ 97
- 0
devices/brennenstuhl.py Näytä tiedosto

@@ -0,0 +1,97 @@
1
+#!/usr/bin/env python
2
+# -*- coding: utf-8 -*-
3
+#
4
+""" Communication (MQTT)
5
+
6
+    brennenstuhl_heatingvalve {
7
+                            |      "away_mode": ["ON", "OFF"]
8
+                            |      "battery": [0...100] %
9
+                            |      "child_lock": ["LOCK", "UNLOCK"]
10
+                            |      "current_heating_setpoint": [5...30] °C
11
+                            |      "linkquality": [0...255] lqi
12
+                            |      "local_temperature": [numeric] °C
13
+                            |      "preset": ["manual", ...]
14
+                            |      "system_mode": ["heat", ...]
15
+                            |      "valve_detection": ["ON", "OFF"]
16
+                            |      "window_detection": ["ON", "OFF"]
17
+                            | }
18
+                            +- set {
19
+                                        "away_mode": ["ON", "OFF", "TOGGLE"]
20
+                                        "child_lock": ["LOCK", "UNLOCK"]
21
+                                        "current_heating_setpoint": [5...30] °C
22
+                                        "preset": ["manual", ...]
23
+                                        "system_mode": ["heat", ...]
24
+                                        "valve_detection": ["ON", "OFF", "TOGGLE"]
25
+                                        "window_detection": ["ON", "OFF", "TOGGLE"]
26
+                                    }
27
+"""
28
+
29
+from devices.base import base
30
+import json
31
+import time
32
+
33
+""" ANSWER of a device:
34
+{
35
+    "away_mode":"OFF",
36
+    "battery":5,
37
+    "child_lock":"UNLOCK",
38
+    "current_heating_setpoint":21,
39
+    "linkquality":196,
40
+    "local_temperature":21.2,
41
+    "preset":"manual",
42
+    "system_mode":"heat",
43
+    "valve_detection":"ON",
44
+    "window_detection":"ON"
45
+}
46
+"""
47
+
48
+class vlv(base):
49
+#    """A tradfri device with switching functionality
50
+
51
+#    Args:
52
+#        mqtt_client (mqtt.mqtt_client): A MQTT Client instance
53
+#        topic (str): the base topic for this device
54
+#    """
55
+    PROPERTIES = [
56
+        "away_mode",
57
+        "battery",
58
+        "child_lock",
59
+        "current_heating_setpoint",
60
+        "linkquality",
61
+        "local_temperature",
62
+        "preset",
63
+        "system_mode",
64
+        "valve_detection",
65
+        "window_detection"
66
+    ]
67
+    def __init__(self, mqtt_client, topic, **kwargs):
68
+        super().__init__(mqtt_client, topic, **kwargs)
69
+        self["away_mode"] = "OFF"
70
+        self["battery"] = 87
71
+        self["child_lock"] = "UNLOCK"
72
+        self["current_heating_setpoint"] = 21
73
+        self["linkquality"] = 196
74
+        self["local_temperature"] = 21.2
75
+        self["preset"] = "manual"
76
+        self["system_mode"] = "heat"
77
+        self["valve_detection"] = "ON"
78
+        self["window_detection"] = "ON"
79
+        #
80
+        self.mqtt_client.add_callback(self.topic + '/set', self.__rx_set__)
81
+
82
+    def set_state(self, value):
83
+        self.__set__("state", "on" if value else "off")
84
+        self.send_device_status()
85
+
86
+    def __rx_set__(self, client, userdata, message):
87
+        data = json.loads(message.payload)
88
+        self.logger.info("Received set data: %s", repr(data))
89
+        for key in data:
90
+            self.__set__(key, data[key])
91
+        #time.sleep(1.5)
92
+        self.send_device_status()
93
+
94
+    def send_device_status(self):
95
+        data = json.dumps(self)
96
+        self.logger.info("Sending status: %s", repr(data))
97
+        self.mqtt_client.send(self.topic, data)

+ 3
- 0
devices/livarno.py Näytä tiedosto

@@ -4,3 +4,6 @@ import devices.tradfri
4 4
 class sw_br_ct(devices.tradfri.sw_br_ct):
5 5
     def set_state(self, value):
6 6
         self.__set__("state", "on" if value else "off")
7
+
8
+    def power_on_action(self):
9
+        pass

+ 5
- 8
devices/shelly.py Näytä tiedosto

@@ -34,7 +34,7 @@ from devices.base import base
34 34
 import json
35 35
 
36 36
 
37
-class sw_plain(base):
37
+class shelly_sw1(base):
38 38
     """A shelly device with switching functionality
39 39
 
40 40
     Args:
@@ -45,10 +45,8 @@ class sw_plain(base):
45 45
     PROPERTIES = [
46 46
         "relay/0",
47 47
     ]
48
-    def __init__(self, mqtt_client, topic, **kwargs):
49
-        super().__init__(mqtt_client, topic, **kwargs)
50
-        if getattr(self, 'cd_r0', None) is None:
51
-            self.cd_r0 = []
48
+    def __init__(self, mqtt_client, topic):
49
+        super().__init__(mqtt_client, topic)
52 50
         self["state"] = "off"
53 51
         #
54 52
         self.mqtt_client.add_callback(self.topic + '/relay/0/command', self.__rx_set__)
@@ -59,9 +57,8 @@ class sw_plain(base):
59 57
         self.logger.info("Received set data for %s: %s", key, repr(data))
60 58
         self.__set__(key, data)
61 59
         self.send_device_status(key)
62
-        if key == "relay/0":
63
-            for d in self.cd_r0:
64
-                d.set_state(data.lower() == "on")
60
+        if key == "relay/0" and data.lower() == "on":
61
+            self.power_on()
65 62
 
66 63
     def send_device_status(self, key):
67 64
         data = self[key]

+ 11
- 12
devices/tradfri.py Näytä tiedosto

@@ -49,15 +49,12 @@ class sw(base):
49 49
     Args:
50 50
         mqtt_client (mqtt.mqtt_client): A MQTT Client instance
51 51
         topic (str): the base topic for this device
52
-        kwargs (**dict): cd_st=list of devices connected to state
53 52
     """
54 53
     PROPERTIES = [
55 54
         "state",
56 55
     ]
57
-    def __init__(self, mqtt_client, topic, **kwargs):
58
-        super().__init__(mqtt_client, topic, **kwargs)
59
-        if getattr(self, 'cd_st', None) is None:
60
-            self.cd_st = []
56
+    def __init__(self, mqtt_client, topic):
57
+        super().__init__(mqtt_client, topic)
61 58
         self["state"] = "off"
62 59
         #
63 60
         self.mqtt_client.add_callback(self.topic + '/set', self.__rx_set__)
@@ -73,13 +70,15 @@ class sw(base):
73 70
         for key in data:
74 71
             self.__set__(key, data[key])
75 72
         self.send_device_status()
76
-        if "state" in data:
77
-            for d in self.cd_st:
78
-                d.set_state(data["state"].lower() == "on")
73
+        if "state" in data and data.get("state", 'OFF').lower() == "on":
74
+            self.power_on()
79 75
 
80 76
     def __rx_get__(self, client, userdata, message):
81 77
         self.send_device_status()
82 78
 
79
+    def power_on_action(self):
80
+        self.send_device_status()
81
+
83 82
     def send_device_status(self):
84 83
         data = json.dumps(self)
85 84
         self.logger.info("Sending status: %s", repr(data))
@@ -96,8 +95,8 @@ class sw_br(sw):
96 95
     PROPERTIES = sw.PROPERTIES + [
97 96
         "brightness",
98 97
     ]
99
-    def __init__(self, mqtt_client, topic, **kwargs):
100
-        super().__init__(mqtt_client, topic, **kwargs)
98
+    def __init__(self, mqtt_client, topic):
99
+        super().__init__(mqtt_client, topic)
101 100
         self["brightness"] = 64
102 101
 
103 102
 
@@ -111,6 +110,6 @@ class sw_br_ct(sw_br):
111 110
     PROPERTIES = sw_br.PROPERTIES + [
112 111
         "color_temp",
113 112
     ]
114
-    def __init__(self, mqtt_client, topic, **kwargs):
115
-        super().__init__(mqtt_client, topic, **kwargs)
113
+    def __init__(self, mqtt_client, topic):
114
+        super().__init__(mqtt_client, topic)
116 115
         self["color_temp"] = 413

+ 80
- 87
home_emulation.py Näytä tiedosto

@@ -1,100 +1,93 @@
1 1
 import config
2
-import devices
2
+import devdi
3
+import devdi.props as props
4
+#import function
5
+#import json
3 6
 import logging
4 7
 import mqtt
8
+import os
5 9
 import report
10
+#import subprocess
6 11
 import time
7 12
 
13
+logger = logging.getLogger(config.APP_NAME)
8 14
 
9
-class device_creator(dict):
10
-    def __init__(self, mqtt_client):
11
-        self.mqtt_client = mqtt_client
12
-        #
13
-        # ground floor west
14
-        # floor
15
-        l1 = self.add_device(devices.livarno.sw_br_ct, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_ZIGBEE % 1)
16
-        l2 = self.add_device(devices.livarno.sw_br_ct, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_ZIGBEE % 2)
17
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_GFW_FLOOR_MAIN_LIGHT_SHELLY, cd_r0=[l1, l2])
18
-
19
-        # marion
20
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_GFW_MARION_MAIN_LIGHT_SHELLY)
21
-        self.add_device(devices.null, config.TOPIC_GFW_MARION_HEATING_VALVE_ZIGBEE)
22
-
23
-        # dirk
24
-        l = self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_GFW_DIRK_MAIN_LIGHT_ZIGBEE)
25
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_GFW_DIRK_MAIN_LIGHT_SHELLY, cd_r0=[l])
26
-        self.add_device(devices.null, config.TOPIC_GFW_DIRK_INPUT_DEVICE)
27
-        self.add_device(devices.null, config.TOPIC_GFW_DIRK_POWERPLUG)
28
-        self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_GFW_DIRK_DESK_LIGHT_ZIGBEE)
29
-        self.add_device(devices.null, config.TOPIC_GFW_DIRK_HEATING_VALVE_ZIGBEE)
30
-
31
-        # first floor west
32
-        # julian
33
-        l = self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_FFW_JULIAN_MAIN_LIGHT_ZIGBEE)
34
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFW_JULIAN_MAIN_LIGHT_SHELLY, cd_r0=[l])
35
-
36
-        # bath
37
-        self.add_device(devices.null, config.TOPIC_FFW_BATH_HEATING_VALVE_ZIGBEE)
38
-
39
-        # livingroom
40
-        l = self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_ZIGBEE)
41
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFW_LIVINGROOM_MAIN_LIGHT_SHELLY, cd_r0=[l])
42
-
43
-        # sleep
44
-        l = self.add_device(devices.tradfri.sw_br, config.TOPIC_FFW_SLEEP_MAIN_LIGHT_ZIGBEE)
45
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFW_SLEEP_MAIN_LIGHT_SHELLY, cd_r0=[l])
46
-
47
-
48
-        # first floor east
49
-        # floor
50
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFE_FLOOR_MAIN_LIGHT_SHELLY)
51
-
52
-        # kitchen
53
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFE_KITCHEN_MAIN_LIGHT_SHELLY)
54
-        self.add_device(devices.null, config.TOPIC_FFE_KITCHEN_CIRCULATION_PUMP_SHELLY)
55
-
56
-        # diningroom
57
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFE_DININGROOM_MAIN_LIGHT_SHELLY)
58
-        self.add_device(devices.null, config.TOPIC_FFE_DININGROOM_FLOOR_LAMP_POWERPLUG)
59
-        self.add_device(devices.null, config.TOPIC_FFE_DININGROOM_GARLAND_POWERPLUG)
60
-
61
-        # sleep
62
-        l = self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_ZIGBEE)
63
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFE_SLEEP_MAIN_LIGHT_SHELLY, cd_r0=[l])
64
-        self.add_device(devices.null, config.TOPIC_FFE_SLEEP_INPUT_DEVICE)
65
-        self.add_device(devices.tradfri.sw_br, config.TOPIC_FFE_SLEEP_BED_LIGHT_DI_ZIGBEE)
66
-        self.add_device(devices.null, config.TOPIC_FFE_SLEEP_BED_LIGHT_MA_POWERPLUG)
67
-        self.add_device(devices.null, config.TOPIC_FFE_SLEEP_HEATING_VALVE_ZIGBEE)
68
-
69
-        # livingroom
70
-        l = self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_ZIGBEE)
71
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_FFE_LIVINGROOM_MAIN_LIGHT_SHELLY, cd_r0=[l])
72
-        for i in range(1,7):
73
-            self.add_device(devices.tradfri.sw_br_ct, config.TOPIC_FFE_LIVINGROOM_FLOOR_LAMP_ZIGBEE % i)
74
-        self.add_device(devices.null, config.TOPIC_FFE_LIVINGROOM_XMAS_TREE_POWERPLUG)
75
-        self.add_device(devices.null, config.TOPIC_FFE_LIVINGROOM_XMAS_STAR_POWERPLUG)
76
-
77
-
78
-        # first floor east
79
-        # floor
80
-        self.add_device(devices.shelly.sw_plain, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_SHELLY)
81
-        self.add_device(devices.null, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_FF)
82
-        self.add_device(devices.null, config.TOPIC_STW_STAIRWAY_MAIN_LIGHT_MOTION_SENSOR_GF)
83
-
84
-    def add_device(self, deviceclass, topic, **kwargs):
85
-        self[topic] = deviceclass(self.mqtt_client, topic, **kwargs)
86
-        return self[topic]
87 15
 
88 16
 if __name__ == "__main__":
89
-    report.stdoutLoggingConfigure((
90
-        (config.APP_NAME, logging.DEBUG),
91
-        ('devices', logging.DEBUG),
92
-    ), report.SHORT_FMT)
93
-    
17
+    #
18
+    # Logging
19
+    #
20
+    if config.DEBUG:
21
+        report.appLoggingConfigure(None, 'stdout', ((config.APP_NAME, logging.DEBUG), ),
22
+                                   target_level=logging.WARNING, fmt=report.SHORT_FMT, host='localhost', port=19996)
23
+    else:
24
+        report.stdoutLoggingConfigure(((config.APP_NAME, logging.WARNING), ), report.SHORT_FMT)
25
+
26
+    #
27
+    # MQTT Client
28
+    #
94 29
     mc = mqtt.mqtt_client(host=config.MQTT_SERVER, port=config.MQTT_PORT, username=config.MQTT_USER,
95
-                          password=config.MQTT_PASSWORD, name='home_emulation')
96
-
97
-    device_dict = device_creator(mc)
30
+                          password=config.MQTT_PASSWORD, name=config.APP_NAME)
31
+
32
+    #
33
+    # Smarthome Devices
34
+    #
35
+    ddi = devdi.devices(mc)
36
+
37
+    #
38
+    # Smart Home Functionality
39
+    #
40
+    #######
41
+    # GFW #
42
+    #######
43
+    loc = props.LOC_GFW
44
+    # DIRK
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)
49
+    # FLOOR
50
+    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
+    
57
+    #######
58
+    # FFW #
59
+    #######
60
+    loc = props.LOC_FFW
61
+    # JULIAN
62
+    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
+    # LIVINGROOM
67
+    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
+    # SLEEP
72
+    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
+    
77
+    #######
78
+    # FFE #
79
+    #######
80
+    loc = props.LOC_FFE
81
+    # LIVINGROOM
82
+    roo = props.ROO_LIV
83
+    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
84
+    tml = ddi.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
85
+    sml.register_power_on_instance(tml)
86
+    # SLEEP
87
+    roo = props.ROO_SLP
88
+    sml = ddi.get(props.STG_SHE, loc, roo, props.FUN_MAL)
89
+    tml = ddi.get(props.STG_ZFE, loc, roo, props.FUN_MAL)
90
+    sml.register_power_on_instance(tml)
98 91
 
99 92
     while (True):
100 93
         time.sleep(1)

Loading…
Peruuta
Tallenna