diff --git a/apps/rest/setup.py b/apps/rest/setup.py index 9754943993d9b4dc21fa662e9ca4f9280e4592e4..52dcd50ce7174cfddfafb361fe0b5d0e6f432d03 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 5ec6edbffad018a6442b57839a9e21f37e7b80fe..368551262b8f4bdb8e496eed8491756df7ebf3c1 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 8418af7c0c0df67678f0fd352b8ec82808aba113..7466ac8ec631bc64a12a168c4cb83523e285a2e0 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 a0891c761464fe6892480a707ef7ae72d504cb57..9f0fb23ccea611eaf09284f72f235c250ef7829a 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 5c5d3fdd160bf35203406d799f5b91c7fe676a8b..eb195224f51c3689f8ce99a81ca45e1d49ec6468 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 054392eae78bef5c0f7e9499dc79bfbbc7867e3a..07d2ab7e49a0e97992efe74a48609371e6d94a3a 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 a566758b506f890c82bc806c64fac60a980ee43b..aa5b53deed4de098ee11965741295e8645a75769 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():