From f8d100ded32da24fa3ffcdf143f5fb8dfcb2c5e3 Mon Sep 17 00:00:00 2001
From: jkerdreu <jkerdreu@b32b6428-25c9-4566-ad07-03861ab6144f>
Date: Thu, 17 Oct 2019 13:35:52 +0000
Subject: [PATCH] Backport again .. grrr

git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/Python/branches/0.7@2309 b32b6428-25c9-4566-ad07-03861ab6144f
---
 apps/rest/setup.py                          |   2 +-
 devices/protocols/Tuya/xaal/tuya/devices.py | 112 ++++++++++++++------
 devices/protocols/Tuya/xaal/tuya/gw.py      |  12 ++-
 scripts/btn_relay_labo.py                   |  47 +++++++-
 scripts/ensibs_alarm_SDB_haut.py            |  17 +--
 scripts/ensibs_alarm_WC_haut.py             |   2 +-
 scripts/ensibs_btn.py                       | 104 ++++++++++++++----
 7 files changed, 225 insertions(+), 71 deletions(-)

diff --git a/apps/rest/setup.py b/apps/rest/setup.py
index 97549439..52dcd50c 100644
--- a/apps/rest/setup.py
+++ b/apps/rest/setup.py
@@ -26,7 +26,7 @@ setup(
     install_requires=[
         'xaal.lib',
         'bottle',
-        'gevent',
+        'gevent==1.4.0',
         'gevent-websocket',
     ]
 )
diff --git a/devices/protocols/Tuya/xaal/tuya/devices.py b/devices/protocols/Tuya/xaal/tuya/devices.py
index 5ec6edbf..36855126 100644
--- a/devices/protocols/Tuya/xaal/tuya/devices.py
+++ b/devices/protocols/Tuya/xaal/tuya/devices.py
@@ -26,18 +26,16 @@ class TuyaDev:
         self.tuya_id  = tuya_id
         self.tuya_key = tuya_key
         self.tuya_ip  = tuya_ip
+        self.tuya_dev = None
         self.base_addr = base_addr
         self.last_update = 0
         self.devices = []
         self.setup()
         self.init_properties()
-        
+
     def setup(self):
-        logger.warning('Please overide setup()')
+        logger.warning('Please override setup()')
 
-    def update_status(self):
-        pass
-        
     def init_properties(self):
         for dev in self.devices:
             dev.vendor_id = 'IHSEV / Tuya'
@@ -45,52 +43,98 @@ class TuyaDev:
             dev.info = 'Tuya device: %s @ %s' % (self.tuya_id,self.tuya_ip)
             if len(self.devices) > 1:
                 dev.group_id = self.base_addr + 'ff'
+        
+    def update_status(self):
+        try:
+            self._update_status()
+        except RetryError as e:
+            logger.warn(e)
 
-class PowerRelay(TuyaDev):
-    def setup(self):
-        dev = devices.powerrelay_toggle(self.base_addr + '00')
-        dev.methods['on']  = self.on
-        dev.methods['off'] = self.off
-        dev.methods['toggle'] = self.toggle
-        dev.product_id = 'Generic Tuya Outlet'
-        self.devices.append(dev)
-        self.relay = pytuya.OutletDevice(self.tuya_id,self.tuya_ip,self.tuya_key)
-        self.relay.set_version(3.3)
+    @retry(stop=stop_after_attempt(2))
+    def _update_status(self):
+        time.sleep(0.1)
+        logger.info("Updating %s" % self.tuya_id)
+        self.last_update = now()
+        status = self.tuya_dev.status()
+        logger.warning(status)
+        self.on_status(status)
+
+    def on_status(self,status):
+        logger.warning('Please override on_status')
+            
+                
+class OnOffMixing(object):
+
+    def setup_onoff(self,tuya_dev,xaal_dev):
+        tuya_dev.set_version(3.3)        
+        self.tuya_dev = tuya_dev
+        xaal_dev.methods['on']  = self.on
+        xaal_dev.methods['off'] = self.off
+        xaal_dev.methods['toggle'] = self.toggle
+        self.xaal_dev = xaal_dev
 
     @retry(stop=stop_after_attempt(2))
     def on(self):
-        self.relay.turn_on()
+        self.tuya_dev.turn_on()
         self.update_status()
 
-    @retry(stop=stop_after_attempt(2))       
+    @retry(stop=stop_after_attempt(2))
     def off(self):
-        self.relay.turn_off()
+        self.tuya_dev.turn_off()
         self.update_status()
 
     def toggle(self):
-        power = self.devices[0].attributes['power']
+        power = self.xaal_dev.attributes['power']
         if power == None:
             self.update_status()
-            power = self.devices[0].attributes['power']
+            power = self.xaal_dev.attributes['power']
         if power == True:
             self.off()
         elif power == False:
             self.on()
-            
-    @retry(stop=stop_after_attempt(2))       
-    def _update_status(self):
-        logger.info("Updating %s" % self.tuya_id)
-        time.sleep(0.1)
-        self.last_update = now()
-        power = self.relay.status()['dps']['1']
-        self.devices[0].attributes['power'] = power
 
-    def update_status(self):
-        try:
-            self._update_status()
-        except RetryError as e:
-            logger.warn(e)
+class PowerRelay(TuyaDev,OnOffMixing):
+    def setup(self):
+        relay = devices.powerrelay_toggle(self.base_addr + '00')
+        relay.product_id = 'Generic Tuya Outlet'
+        outlet = pytuya.OutletDevice(self.tuya_id,self.tuya_ip,self.tuya_key)
+        outlet.set_version(3.3)
+        self.setup_onoff(outlet,relay)
+        self.devices.append(relay)
+
+    def on_status(self,status):
+        self.devices[0].attributes['power'] = status['dps'][1]
+        
+
+class SmartPlug(TuyaDev,OnOffMixing):
+    def setup(self):
+        # TBD switch to the right schema, but right now nothing exists
+        relay = devices.powerrelay_toggle(self.base_addr + '00')
+        relay.product_id = 'Tuya Smart Plug Outlet'
+        plug = pytuya.OutletDevice(self.tuya_id,self.tuya_ip,self.tuya_key)
+        self.setup_onoff(plug,relay)
+
+        pmeter = devices.powermeter(self.base_addr + '01')
+        pmeter.product_id = 'Tuya Smart Plug Power Meter'
+        pmeter.new_attribute('voltage')
+        pmeter.new_attribute('current')
+        pmeter.del_attribute(pmeter.get_attribute('energy'))
+        pmeter.del_attribute(pmeter.get_attribute('devices'))
+        pmeter.unsupported_attributes = ['energy','devices']
+        
+        self.devices.append(relay)
+        self.devices.append(pmeter)
+        
+    def on_status(self,status):
+        dps = status['dps']
+        print(dps)
+        self.devices[0].attributes['power'] = dps.get('1',None)
+        self.devices[1].attributes['current'] = int(dps.get('4',0)) / 1000
+        self.devices[1].attributes['power'] = int(dps.get('5',0)) / 10
+        self.devices[1].attributes['voltage'] = int(dps.get('6',0)) / 10
+        
+        
         
-# TODO I don't have this kind of devices right now        
+# TODO I don't have this kind of devices right now
 class RGBLamp(TuyaDev):pass
 class PowerRelayMetering(TuyaDev):pass
diff --git a/devices/protocols/Tuya/xaal/tuya/gw.py b/devices/protocols/Tuya/xaal/tuya/gw.py
index 8418af7c..7466ac8e 100644
--- a/devices/protocols/Tuya/xaal/tuya/gw.py
+++ b/devices/protocols/Tuya/xaal/tuya/gw.py
@@ -12,6 +12,9 @@ logger = logging.getLogger(__name__)
 # poll devices only every n seconds
 REFRESH_RATE=30
 
+CFG_MAP = { 'powerrelay': devices.PowerRelay,
+            'smartplug' : devices.SmartPlug }
+
 class GW:
     def __init__(self,engine):
         self.engine = engine
@@ -44,7 +47,7 @@ class GW:
             base_addr  = cfg.get('base_addr',None)
             ip         = cfg.get('ip',None)
             key        = cfg.get('key',None)
-            type_      = cfg.get('type','powerrelay')
+            type_      = cfg.get('type','PowerRelay')
 
             if base_addr == None:
                 cfg['base_addr'] = base_addr = tools.get_random_uuid()[:-2]
@@ -57,13 +60,16 @@ class GW:
         self.engine.add_device(gw)
 
     def add_device(self,tuya_id,tuya_key,ip,base_addr,type_):
-        if type_ == 'powerrelay':
-            dev = devices.PowerRelay(tuya_id,tuya_key,ip,base_addr)
+        dev_type = CFG_MAP.get(type_,None)
+        if dev_type:
+            dev = dev_type(tuya_id,tuya_key,ip,base_addr)
             self.devices[tuya_id] = dev
             for d in dev.devices:
                 self.engine.add_device(d)
                 self.gw.attributes['embedded'].append(d.address)
             dev.update_status()
+        else:
+            logger.warn(f"Unsupported device type {type_} {ip}")
             
     def update(self):
         # Tuya protocol doesn't support update broadcasting
diff --git a/scripts/btn_relay_labo.py b/scripts/btn_relay_labo.py
index a0891c76..9f0fb23c 100644
--- a/scripts/btn_relay_labo.py
+++ b/scripts/btn_relay_labo.py
@@ -1,19 +1,25 @@
 from xaal.lib import Engine
 from xaal.schemas import devices
 from xaal.monitor import Monitor
-import platform
+import platform,time
 
 PKG_NAME = 'btn_relay_labo'
 
 LAMPS=['ccc44227-d4fc-46eb-8578-159e2c47da03','ccc44227-d4fc-46eb-8578-159e2c47da04','ccc44227-d4fc-46eb-8578-159e2c47da05',
        'ccc44227-d4fc-46eb-8578-159e2c47da06','ccc44227-d4fc-46eb-8578-159e2c47da07','ccc44227-d4fc-46eb-8578-159e2c47da08']
 
+SPOTS=['6265eb30-8c59-11e9-98b1-b827ebe99201',]
+
+
 # Edisio labo
 BTNS=['743034ca-c2f0-11e8-9485-a40074bcb601','743034ca-c2f0-11e8-9485-a40074bcb603','743034ca-c2f0-11e8-9485-a40074bcb605',
       '743034ca-c2f0-11e8-9485-a40074bcb607','743034ca-c2f0-11e8-9485-a40074bcb608']
 
 # Aquara sw1
 AQUARA=['1ec6bbd0-20b5-11e9-b352-a4badbf92500']
+SDB = ['fb1f8648-20ba-11e9-b352-a4badbf92500','fb1f8648-20ba-11e9-b352-a4badbf92501','fb1f8648-20ba-11e9-b352-a4badbf92502']
+SCEN = ['00796898-20bb-11e9-b352-a4badbf92500','00796898-20bb-11e9-b352-a4badbf92501','00796898-20bb-11e9-b352-a4badbf92502']
+
 
 # Edisio bureau
 #BTNS = ['c4b33536-c314-11e8-a5d6-000673742b01','c4b33536-c314-11e8-a5d6-000673742b03','c4b33536-c314-11e8-a5d6-000673742b05',
@@ -21,6 +27,8 @@ AQUARA=['1ec6bbd0-20b5-11e9-b352-a4badbf92500']
 
 
 SHUTERS=['e4b05165-be5d-46d5-acd0-4da7be1158ed','2fe70f46-3ece-44d1-af34-2d82e10fb854']
+SIRENS =['980a639c-20b1-11e9-8d70-a4badbf92501',]
+
 
 LAMPS_A = [LAMPS[0], LAMPS[2], LAMPS[5]]
 LAMPS_B = [LAMPS[1], LAMPS[3], LAMPS[4]]
@@ -75,12 +83,45 @@ def handle_msg(msg):
                 #send([SHUTERS[1],],'down')
                 pass
 
+        if msg.source == SDB[0]:
+            send([LAMPS[3],],'toggle')
+
+        if msg.source == SCEN[0]:
+            "soirée TV"
+            send([SHUTERS[0]],'down')
+            send(LAMPS,'off')
+            send(SPOTS,'on')
+            send([SHUTERS[1]],'down')
+            
+        if msg.source == SCEN[1]:
+            "Début journée"
+            send([SHUTERS[0]],'up')
+            send([LAMPS[3],],'on')
+            send(SPOTS,'off')
+            send([SHUTERS[1]],'up')
+
+        if msg.source == SCEN[2]:
+            "stop"
+            send([SHUTERS[0]],'stop')
+            send([SHUTERS[1]],'stop')
+            send(SIRENS,'stop')
+            
     if msg.action == 'double_click':
         if msg.source in AQUARA:
             send([SHUTERS[0],],'stop')
             send([SHUTERS[1],],'stop')
+            send(SIRENS,'stop')
+            
+    if msg.action == 'attributesChange':
+        #print(msg)
+        if msg.source == 'd9993018-20b1-11e9-a250-a4badbf92500':
+            pres = msg.body.get('presence')
+            light = mon.devices.get_with_addr(LAMPS[3]).attributes.get('light')
+            print("pres & light %s/%s" % (pres,light)) 
+            if pres == False and light == True:
+                send(SIRENS,'play')
+                print('Alarme..')
             
-                
 def main():
     global dev
     global mon
@@ -94,6 +135,6 @@ def main():
 
 if __name__ == '__main__':
     try:
-        main()
+        eng = main()
     except KeyboardInterrupt:
         print('Bye bye')
diff --git a/scripts/ensibs_alarm_SDB_haut.py b/scripts/ensibs_alarm_SDB_haut.py
index 5c5d3fdd..eb195224 100644
--- a/scripts/ensibs_alarm_SDB_haut.py
+++ b/scripts/ensibs_alarm_SDB_haut.py
@@ -8,19 +8,22 @@ from enum import Enum
 
 DELAY = 30
 
-ADDR     = 'aa4d1cbc-92af-11e8-80cd-408d5c18c801'
+ADDR     = 'aa4d1cbc-92af-11e8-80cd-408d5c18c802'
 PKG_NAME = 'scenario_ensibs_alerte'
 
 DOOR     = 'ce91c3a6-20b1-11e9-a250-a4badbf92500'
 MVT      = '93e09033-708e-11e8-956e-00fec8f7138c'
-LIGHTS   = ['93e09007-708e-11e8-956e-00fec8f7138c','93e09008-708e-11e8-956e-00fec8f7138c']
+#LIGHTS   = ['93e09007-708e-11e8-956e-00fec8f7138c','93e09008-708e-11e8-956e-00fec8f7138c']
+LIGHT_PLAF  = '93e09007-708e-11e8-956e-00fec8f7138c'
+LIGHT_MIR   = '93e09008-708e-11e8-956e-00fec8f7138c'
 
 BULLET   = ['6eb64b73-6e51-11e9-8f96-00fec8f7138c']
 BLINKS   = ['aa8cd2e4-8c5d-11e9-b0ba-b827ebe99201','980a639c-20b1-11e9-8d70-a4badbf92500']
 SIREN    = ['980a639c-20b1-11e9-8d70-a4badbf92501',]
 
 
-MONITORING_DEVICES = [DOOR,LIGHTS,MVT]
+#MONITORING_DEVICES = [DOOR,LIGHTS,MVT]
+MONITORING_DEVICES = [DOOR,LIGHT_PLAF,LIGHT_MIR,MVT]
 
 class States(Enum):
     free       = 'free'
@@ -64,7 +67,7 @@ def send(targets,action,body=None):
 
 def alert():
     logger.warning('WARNING !!!!')
-    send(BULLET,'notify',{'title':'Alarme SDB haut !!','msg':"Personne inerte ou lumière oubliée"})
+    send(BULLET,'notify',{'title':'Alarme SDB haut !!','msg':"lumière oubliée"})
     send(BLINKS,'blink')
     send(SIREN,'play')
 
@@ -84,8 +87,10 @@ def on_event(event,dev):
     if event == Notification.new_device:
         if dev.address == DOOR  : devices.door   = dev
         if dev.address == MVT   : devices.motion = dev
-        if dev.address == LIGHTS[0] : devices.light0  = dev
-        if dev.address == LIGHTS[1] : devices.light1  = dev
+        #if dev.address == LIGHTS[0] : devices.light0  = dev
+        #if dev.address == LIGHTS[1] : devices.light1  = dev
+        if dev.address == LIGHT_PLAF : devices.light0  = dev
+        if dev.address == LIGHT_MIR  : devices.light1  = dev
 
         
     if event == Notification.attribute_change:
diff --git a/scripts/ensibs_alarm_WC_haut.py b/scripts/ensibs_alarm_WC_haut.py
index 054392ea..07d2ab7e 100644
--- a/scripts/ensibs_alarm_WC_haut.py
+++ b/scripts/ensibs_alarm_WC_haut.py
@@ -63,7 +63,7 @@ def send(targets,action,body=None):
 
 def alert():
     logger.warning('WARNING !!!!')
-    send(BULLET,'notify',{'title':'Alarme WC haut !!','msg':"Personne inerte ou lumière oubliée"})
+    send(BULLET,'notify',{'title':'Alarme WC haut !!','msg':"Personne inerte"})
     send(BLINKS,'blink')
     send(SIREN,'play')
 
diff --git a/scripts/ensibs_btn.py b/scripts/ensibs_btn.py
index a566758b..aa5b53de 100644
--- a/scripts/ensibs_btn.py
+++ b/scripts/ensibs_btn.py
@@ -2,10 +2,18 @@ from xaal.lib import Engine
 from xaal.schemas import devices
 from xaal.monitor import Monitor
 import platform
+from functools import partial
 
 PKG_NAME = 'scenario_btn_ensibs'
 
-LAMPS=['aa8cd2e4-8c5d-11e9-b0ba-b827ebe99201']
+LAMPS=['93e09003-708e-11e8-956e-00fec8f7138c','aa8cd2e4-8c5d-11e9-b0ba-b827ebe99201','93e09009-708e-11e8-956e-00fec8f7138c','93e09010-708e-11e8-956e-00fec8f7138c']
+
+MEUBLE_CUIS_UP      = ['93e09080-708e-11e8-956e-00fec8f7138c',]
+MEUBLE_CUIS_DOWN    = ['93e09081-708e-11e8-956e-00fec8f7138c',]
+PLAN_TRAV_CUIS_UP   = ['93e09082-708e-11e8-956e-00fec8f7138c',]
+PLAN_TRAV_CUIS_DOWN = ['93e09083-708e-11e8-956e-00fec8f7138c',]
+
+PRISES_CONNECTEE = ['6265eb30-8c59-11e9-98b1-b827ebe99201',]
 
 # Edisio labo
 EDISIO=['43c06446-8c5c-11e9-a105-b80673742b01','43c06446-8c5c-11e9-a105-b80673742b03','43c06446-8c5c-11e9-a105-b80673742b05',
@@ -16,24 +24,32 @@ AQUARA_1=['fb1f8648-20ba-11e9-b352-a4badbf92500','fb1f8648-20ba-11e9-b352-a4badb
 AQUARA_2=['00796898-20bb-11e9-b352-a4badbf92500','00796898-20bb-11e9-b352-a4badbf92501','00796898-20bb-11e9-b352-a4badbf92502']
 AQUARA_R= '1ec6bbd0-20b5-11e9-b352-a4badbf92500'
 
-SHUTERS=['e4b05165-be5d-46d5-acd0-4da7be1158ed','2fe70f46-3ece-44d1-af34-2d82e10fb854']
+SHUTERS=['93e09051-708e-11e8-956e-00fec8f7138c','93e09050-708e-11e8-956e-00fec8f7138c']
 
-SIREN = ['980a639c-20b1-11e9-8d70-a4badbf92501',]
-PUSH_BULLET=['bc5bb184-8d16-11e9-b4db-9cebe88e1963']
+SIREN= ['980a639c-20b1-11e9-8d70-a4badbf92501',]
+#PUSH_BULLET=['bc5bb184-8d16-11e9-b4db-9cebe88e1963']
+BULLET= ['6eb64b73-6e51-11e9-8f96-00fec8f7138c',]
 
-LAMPS_A = [LAMPS[0]]
+LAMPS_A = [LAMPS[0],LAMPS[1]]
 
 BLINKS = ['aa8cd2e4-8c5d-11e9-b0ba-b827ebe99201','980a639c-20b1-11e9-8d70-a4badbf92500']
 
-RELAYS = ['d34fd5be-8c58-11e9-8999-b827ebe99201']
+#RELAYS = ['d34fd5be-8c58-11e9-8999-b827ebe99201']
 
 mon = None
 dev = None
 
 def send(targets,action,body=None):
     global dev
+    print("Sending %s %s" % (targets,action))
     dev.engine.send_request(dev,targets,action,body)
 
+def delayed_send(delay,targets,action,body=None):
+    global dev
+    engine = dev.engine
+    func = partial(send,targets=targets,action=action,body=None)
+    engine.add_timer(func,delay,1)
+    
 def search_for_light(lamps):
     for l in lamps:
         dev = mon.devices.get_with_addr(l)
@@ -58,8 +74,10 @@ def siren_play(snd=2):
 def siren_stop():
     send(SIREN,'stop')
 
-def pushbullet(title,msg):
-    send(PUSH_BULLET,'notify',{'title': title,'msg':msg})
+#def pushbullet(title,msg):
+    #send(BULLET,'notify',{'title': title,'msg':msg})
+def pushbullet():
+    send(BULLET,'notify',{'title':'Alerte','msg':"Appel secour"})
 
 def blink():
     send(BLINKS,'blink')
@@ -73,27 +91,67 @@ def handle_msg(msg):
         if msg.source == AQUARA_R:
             blink()
             siren_play(2)
-            pushbullet('Alerte','')
+            #pushbullet('Alerte','')
+            pushbullet()
 
         if msg.source == AQUARA_1[0]:
-            #on_off_light(LAMPS_A)
-            send(RELAYS,'on')
-
+            send(MEUBLE_CUIS_DOWN,'on')
+            delayed_send(6,MEUBLE_CUIS_DOWN,'off')
+            send(PLAN_TRAV_CUIS_DOWN,'on')
+            delayed_send(8,PLAN_TRAV_CUIS_DOWN,'off')
+        
         if msg.source == AQUARA_1[1]:
             #on_off_light(LAMPS_A)
-            send(RELAYS,'off')
-
-        if msg.source == AQUARA_2[0]: 
-            siren_play(20)
-
-        if msg.source == AQUARA_2[1]: 
-            pushbullet('Alerte','Intrusion')
-            siren_play(1)
+            #send(RELAYS,'on')
+            #on_off_light(LAMPS)
+            send(MEUBLE_CUIS_UP,'on')
+            delayed_send(6,MEUBLE_CUIS_UP,'off')
+            send(PLAN_TRAV_CUIS_UP,'on')
+            delayed_send(8,PLAN_TRAV_CUIS_UP,'off')
+        
+        if msg.source == AQUARA_1[2]:
+            send(MEUBLE_CUIS_DOWN,'off')
+            send(PLAN_TRAV_CUIS_DOWN,'off')
+            send(MEUBLE_CUIS_UP,'off')
+            send(PLAN_TRAV_CUIS_UP,'off')
+            
+        if msg.source == AQUARA_2[0]:
+            #send(LAMPS,'on')
+            delayed_send(5,[LAMPS[0],],'on')
+            delayed_send(5,[LAMPS[3],],'on')
+            delayed_send(10,[LAMPS[1],],'on')
+            delayed_send(10,[LAMPS[2],],'on')
+            send(SHUTERS,'down')
+            #delayed_send(10,SHUTERS,'stop')
+            delayed_send(15,PRISES_CONNECTEE,'on')
+
+        if msg.source == AQUARA_2[1]:
+            send(SHUTERS,'up')
+            #send(LAMPS,'off')
+            #delayed_send(5,LAMPS,'off')
+            delayed_send(20,[LAMPS[1],],'off')
+            delayed_send(20,[LAMPS[2],],'off')
+            delayed_send(25,[LAMPS[0],],'off')
+            delayed_send(25,[LAMPS[3],],'off')
+            delayed_send(15,PRISES_CONNECTEE,'off')
 
         if msg.source == AQUARA_2[2]:
-            siren_stop()
-
-            #send(SHUTERS,'stop')
+            send(SHUTERS,'stop')
+        
+        if msg.source == EDISIO[0]:
+            send([SHUTERS[0],],'up')
+        
+        if msg.source == EDISIO[1]:
+            send([SHUTERS[1],],'up')
+        
+        if msg.source == EDISIO[2]:
+            send(SHUTERS,'stop')
+        
+        if msg.source == EDISIO[3]:
+            send([SHUTERS[0],],'down')
+        
+        if msg.source == EDISIO[4]:
+            send([SHUTERS[1],],'down')
 
                 
 def main():
-- 
GitLab