Adds site_config; adds Tuya lights. Bugfixes.
[python_utils.git] / light_utils.py
index 8101a32523c486d0bc2ff782be8435297c18bcd9..6ca6e71db2329a65402116a5cf769048023521f6 100644 (file)
@@ -10,7 +10,9 @@ import os
 import re
 import subprocess
 import sys
-from typing import Dict, List, Optional, Set
+from typing import Any, Dict, List, Optional, Set
+
+import tinytuya as tt
 
 import argparse_utils
 import config
@@ -178,6 +180,71 @@ class GoogleLight(Light):
         )
 
 
+class TuyaLight(Light):
+    ids_by_mac = {
+        '68:C6:3A:DE:1A:94': '8844664268c63ade1a94',
+        '68:C6:3A:DE:27:1A': '8844664268c63ade271a',
+        '68:C6:3A:DE:1D:95': '8844664268c63ade1d95',
+        '68:C6:3A:DE:19:B3': '8844664268c63ade19b3',
+        '80:7D:3A:77:3B:F5': '07445340807d3a773bf5',
+        '80:7D:3A:58:37:02': '07445340807d3a583702',
+    }
+    keys_by_mac = {
+        '68:C6:3A:DE:1A:94': '237f19b1b3d49c36',
+        '68:C6:3A:DE:27:1A': '237f19b1b3d49c36',
+        '68:C6:3A:DE:1D:95': '04b90fc5cd7625d8',
+        '68:C6:3A:DE:19:B3': '2d601f2892f1aefd',
+        '80:7D:3A:77:3B:F5': '27ab921fe4633519',
+        '80:7D:3A:58:37:02': '8559b5416bfa0c05',
+    }
+
+    def __init__(self, name: str, mac: str, keywords: str = "") -> None:
+        from subprocess import Popen, PIPE
+        super().__init__(name, mac, keywords)
+        mac = mac.upper()
+        if mac not in TuyaLight.ids_by_mac or mac not in TuyaLight.keys_by_mac:
+            raise Exception(f'{mac} is unknown; add it to ids_by_mac and keys_by_mac')
+        self.devid = TuyaLight.ids_by_mac[mac]
+        self.key = TuyaLight.keys_by_mac[mac]
+        try:
+            pid = Popen(['maclookup', mac], stdout=PIPE)
+            ip = pid.communicate()[0]
+            ip = ip[:-1]
+        except Exception:
+            ip = '0.0.0.0'
+        self.bulb = tt.BulbDevice(self.devid, ip, local_key=self.key)
+
+    def turn_on(self) -> bool:
+        self.bulb.turn_on()
+        return True
+
+    def turn_off(self) -> bool:
+        self.bulb.turn_off()
+        return True
+
+    def get_status(self) -> Dict[str, Any]:
+        return self.bulb.status()
+
+    def is_on(self) -> bool:
+        s = self.get_status()
+        return s['dps']['1']
+
+    def is_off(self) -> bool:
+        return not self.is_on()
+
+    def get_dimmer_level(self) -> Optional[int]:
+        s = self.get_status()
+        return s['dps']['3']
+
+    def set_dimmer_level(self, level: int) -> bool:
+        self.bulb.set_brightness(level)
+        return True
+
+    def make_color(self, color: str) -> bool:
+        self.bulb.set_colour(255,0,0)
+        return True
+
+
 class TPLinkLight(Light):
     def __init__(self, name: str, mac: str, keywords: str = "") -> None:
         super().__init__(name, mac, keywords)
@@ -350,46 +417,6 @@ class GoogleLightGroup(GoogleLight):
         )
 
 
-def group_google_lights(lights: List[Light]) -> List[Light]:
-    bookcase_group = []
-    diningroom_group = []
-    for light in lights:
-        name = light.get_name()
-        if "bookcase_light_" in name:
-            bookcase_group.append(light)
-        elif "diningroom_light_" in name:
-            diningroom_group.append(light)
-
-    did_bookcase = False
-    did_diningroom = False
-    ret = []
-    for light in lights:
-        name = light.get_name()
-        if "bookcase_light_" in name:
-            if len(bookcase_group) == 4 and not did_bookcase:
-                ret.append(
-                    GoogleLightGroup(
-                        "bookcase_lights",
-                        bookcase_group,
-                        "perm wifi light smart goog dimmer"
-                    )
-                )
-                did_bookcase = True
-        elif "diningroom_light_" in name:
-            if len(diningroom_group) == 2 and not did_diningroom:
-                ret.append(
-                    GoogleLightGroup(
-                        "dining_room_lights",
-                        diningroom_group,
-                        "intermittent wifi light smart goog dimmer"
-                    )
-                )
-                did_diningroom = True
-        else:
-            ret.append(light)
-    return ret
-
-
 class LightingConfig(object):
     """Representation of the smart light device config."""
 
@@ -428,45 +455,45 @@ class LightingConfig(object):
             self.keywords_by_mac[mac] = keywords
             self.names_by_mac[mac] = name
 
-            if "bookcase_light_" in name:
-                bookcase_lights.append(mac)
-            elif "diningroom_light_" in name:
-                diningroom_lights.append(mac)
-            else:
-                self.index_light(name, keywords, mac)
-
-        name = 'bookcase_lights'
-        group = []
-        keywords = 'perm wifi light smart goog dimmer'
-        for b in bookcase_lights:
-            group.append(self.get_light_by_mac(b))
-        self.bookcase_group = GoogleLightGroup(
-            name,
-            group,
-            keywords,
-        )
-        mac = self.bookcase_group.get_mac()
-        self.macs_by_name[name] = mac
-        self._keywords_by_name[name] = keywords
-        self.keywords_by_mac[mac] = keywords
-        self.names_by_mac[mac] = name
-        self.index_light(name, keywords, mac)
-
-        name = 'dining_room_lights'
-        group = []
-        for b in diningroom_lights:
-            group.append(self.get_light_by_mac(b))
-        self.diningroom_group = GoogleLightGroup(
-            name,
-            group,
-            keywords,
-        )
-        mac = self.diningroom_group.get_mac()
-        self.macs_by_name[name] = mac
-        self._keywords_by_name[name] = keywords
-        self.keywords_by_mac[mac] = keywords
-        self.names_by_mac[mac] = name
-        self.index_light(name, keywords, mac)
+#            if "bookcase_light_" in name:
+#                bookcase_lights.append(mac)
+#            elif "diningroom_light_" in name:
+#                diningroom_lights.append(mac)
+#            else:
+            self.index_light(name, keywords, mac)
+
+        name = 'bookcase_lights'
+        group = []
+        keywords = 'perm wifi light smart goog dimmer'
+        for b in bookcase_lights:
+            group.append(self.get_light_by_mac(b))
+        self.bookcase_group = GoogleLightGroup(
+            name,
+            group,
+            keywords,
+        )
+        mac = self.bookcase_group.get_mac()
+        self.macs_by_name[name] = mac
+        self._keywords_by_name[name] = keywords
+        self.keywords_by_mac[mac] = keywords
+        self.names_by_mac[mac] = name
+        self.index_light(name, keywords, mac)
+
+        name = 'dining_room_lights'
+        group = []
+        for b in diningroom_lights:
+            group.append(self.get_light_by_mac(b))
+        self.diningroom_group = GoogleLightGroup(
+            name,
+            group,
+            keywords,
+        )
+        mac = self.diningroom_group.get_mac()
+        self.macs_by_name[name] = mac
+        self._keywords_by_name[name] = keywords
+        self.keywords_by_mac[mac] = keywords
+        self.names_by_mac[mac] = name
+        self.index_light(name, keywords, mac)
 
     def index_light(self, name: str, keywords: str, mac: str) -> None:
         properties = [("name", name)]
@@ -477,14 +504,13 @@ class LightingConfig(object):
                 properties.append((key, value))
             else:
                 tags.add(kw)
-        self.corpus.add_doc(
-            logical_search.Document(
-                docid=mac,
-                tags=tags,
-                properties=properties,
-                reference=None,
-            )
+        light = logical_search.Document(
+            docid=mac,
+            tags=tags,
+            properties=properties,
+            reference=None,
         )
+        self.corpus.add_doc(light)
 
     def __repr__(self) -> str:
         s = "Known devices:\n"
@@ -522,7 +548,7 @@ class LightingConfig(object):
                 light = self.get_light_by_mac(mac)
                 if light is not None:
                     retval.append(light)
-        return group_google_lights(retval)
+        return retval
 
     def get_light_by_mac(self, mac: str) -> Optional[Light]:
         if mac in self.keywords_by_mac:
@@ -532,8 +558,10 @@ class LightingConfig(object):
                 return self.bookcase_group
             elif name == 'dining_room_lights':
                 return self.diningroom_group
-            elif "tplink" in kws.lower():
+            elif 'tplink' in kws.lower():
                 return TPLinkLight(name, mac, kws)
+            elif 'tuya' in kws.lower():
+                return TuyaLight(name, mac, kws)
             else:
                 return GoogleLight(name, mac, kws)
         return None
@@ -551,4 +579,4 @@ class LightingConfig(object):
                     light = self.get_light_by_mac(mac)
                     if light is not None:
                         retval.append(light)
-        return group_google_lights(retval)
+        return retval